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