| 1 | #include "LibcBenchmark.h" |
| 2 | #include "LibcMemoryBenchmark.h" |
| 3 | #include "MemorySizeDistributions.h" |
| 4 | #include "benchmark/benchmark.h" |
| 5 | #include "llvm/ADT/ArrayRef.h" |
| 6 | #include "llvm/ADT/Twine.h" |
| 7 | #include <chrono> |
| 8 | #include <cstdint> |
| 9 | #include <random> |
| 10 | #include <vector> |
| 11 | |
| 12 | using llvm::Align; |
| 13 | using llvm::ArrayRef; |
| 14 | using llvm::Twine; |
| 15 | using llvm::libc_benchmarks::BzeroConfiguration; |
| 16 | using llvm::libc_benchmarks::ComparisonSetup; |
| 17 | using llvm::libc_benchmarks::CopySetup; |
| 18 | using llvm::libc_benchmarks::MemcmpOrBcmpConfiguration; |
| 19 | using llvm::libc_benchmarks::MemcpyConfiguration; |
| 20 | using llvm::libc_benchmarks::MemmoveConfiguration; |
| 21 | using llvm::libc_benchmarks::MemorySizeDistribution; |
| 22 | using llvm::libc_benchmarks::MemsetConfiguration; |
| 23 | using llvm::libc_benchmarks::MoveSetup; |
| 24 | using llvm::libc_benchmarks::OffsetDistribution; |
| 25 | using llvm::libc_benchmarks::SetSetup; |
| 26 | |
| 27 | // Alignment to use for when accessing the buffers. |
| 28 | static constexpr Align kBenchmarkAlignment = Align::Constant<1>(); |
| 29 | |
| 30 | static std::mt19937_64 &getGenerator() { |
| 31 | static std::mt19937_64 Generator( |
| 32 | std::chrono::system_clock::now().time_since_epoch().count()); |
| 33 | return Generator; |
| 34 | } |
| 35 | |
| 36 | template <typename SetupType, typename ConfigurationType> struct Runner { |
| 37 | Runner(benchmark::State &S, llvm::ArrayRef<ConfigurationType> Configurations) |
| 38 | : State(S), Distribution(SetupType::getDistributions()[State.range(pos: 0)]), |
| 39 | Probabilities(Distribution.Probabilities), |
| 40 | SizeSampler(Probabilities.begin(), Probabilities.end()), |
| 41 | OffsetSampler(Setup.BufferSize, Probabilities.size() - 1, |
| 42 | kBenchmarkAlignment), |
| 43 | Configuration(Configurations[State.range(pos: 1)]) { |
| 44 | for (auto &P : Setup.Parameters) { |
| 45 | P.OffsetBytes = OffsetSampler(getGenerator()); |
| 46 | P.SizeBytes = SizeSampler(getGenerator()); |
| 47 | Setup.checkValid(P); |
| 48 | } |
| 49 | } |
| 50 | |
| 51 | ~Runner() { |
| 52 | const size_t TotalBytes = |
| 53 | (State.iterations() * Setup.getBatchBytes()) / Setup.BatchSize; |
| 54 | State.SetBytesProcessed(TotalBytes); |
| 55 | State.SetItemsProcessed(State.iterations()); |
| 56 | State.SetLabel((Twine(Configuration.Name) + "," + Distribution.Name).str()); |
| 57 | State.counters["bytes_per_cycle" ] = benchmark::Counter( |
| 58 | TotalBytes / benchmark::CPUInfo::Get().cycles_per_second, |
| 59 | benchmark::Counter::kIsRate); |
| 60 | } |
| 61 | |
| 62 | inline void runBatch() { |
| 63 | for (const auto &P : Setup.Parameters) |
| 64 | benchmark::DoNotOptimize(Setup.Call(P, Configuration.Function)); |
| 65 | } |
| 66 | |
| 67 | size_t getBatchSize() const { return Setup.BatchSize; } |
| 68 | |
| 69 | private: |
| 70 | SetupType Setup; |
| 71 | benchmark::State &State; |
| 72 | MemorySizeDistribution Distribution; |
| 73 | ArrayRef<double> Probabilities; |
| 74 | std::discrete_distribution<unsigned> SizeSampler; |
| 75 | OffsetDistribution OffsetSampler; |
| 76 | ConfigurationType Configuration; |
| 77 | }; |
| 78 | |
| 79 | #define BENCHMARK_MEMORY_FUNCTION(BM_NAME, SETUP, CONFIGURATION_TYPE, \ |
| 80 | CONFIGURATION_ARRAY_REF) \ |
| 81 | void BM_NAME(benchmark::State &State) { \ |
| 82 | Runner<SETUP, CONFIGURATION_TYPE> Setup(State, CONFIGURATION_ARRAY_REF); \ |
| 83 | const size_t BatchSize = Setup.getBatchSize(); \ |
| 84 | while (State.KeepRunningBatch(BatchSize)) \ |
| 85 | Setup.runBatch(); \ |
| 86 | } \ |
| 87 | BENCHMARK(BM_NAME)->Apply([](benchmark::internal::Benchmark *benchmark) { \ |
| 88 | const int64_t DistributionSize = SETUP::getDistributions().size(); \ |
| 89 | const int64_t ConfigurationSize = CONFIGURATION_ARRAY_REF.size(); \ |
| 90 | for (int64_t DistIndex = 0; DistIndex < DistributionSize; ++DistIndex) \ |
| 91 | for (int64_t ConfIndex = 0; ConfIndex < ConfigurationSize; ++ConfIndex) \ |
| 92 | benchmark->Args({DistIndex, ConfIndex}); \ |
| 93 | }) |
| 94 | |
| 95 | extern llvm::ArrayRef<MemcpyConfiguration> getMemcpyConfigurations(); |
| 96 | BENCHMARK_MEMORY_FUNCTION(BM_Memcpy, CopySetup, MemcpyConfiguration, |
| 97 | getMemcpyConfigurations()); |
| 98 | |
| 99 | extern llvm::ArrayRef<MemmoveConfiguration> getMemmoveConfigurations(); |
| 100 | BENCHMARK_MEMORY_FUNCTION(BM_Memmove, MoveSetup, MemmoveConfiguration, |
| 101 | getMemmoveConfigurations()); |
| 102 | |
| 103 | extern llvm::ArrayRef<MemcmpOrBcmpConfiguration> getMemcmpConfigurations(); |
| 104 | BENCHMARK_MEMORY_FUNCTION(BM_Memcmp, ComparisonSetup, MemcmpOrBcmpConfiguration, |
| 105 | getMemcmpConfigurations()); |
| 106 | |
| 107 | extern llvm::ArrayRef<MemcmpOrBcmpConfiguration> getBcmpConfigurations(); |
| 108 | BENCHMARK_MEMORY_FUNCTION(BM_Bcmp, ComparisonSetup, MemcmpOrBcmpConfiguration, |
| 109 | getBcmpConfigurations()); |
| 110 | |
| 111 | extern llvm::ArrayRef<MemsetConfiguration> getMemsetConfigurations(); |
| 112 | BENCHMARK_MEMORY_FUNCTION(BM_Memset, SetSetup, MemsetConfiguration, |
| 113 | getMemsetConfigurations()); |
| 114 | |
| 115 | extern llvm::ArrayRef<BzeroConfiguration> getBzeroConfigurations(); |
| 116 | BENCHMARK_MEMORY_FUNCTION(BM_Bzero, SetSetup, BzeroConfiguration, |
| 117 | getBzeroConfigurations()); |
| 118 | |