1 #include "LibcBenchmark.h"
2 #include "LibcMemoryBenchmark.h"
3 #include "MemorySizeDistributions.h"
4 #include "benchmark/benchmark.h"
5 #include <cstdint>
6 #include <random>
7 #include <vector>
8 
9 namespace __llvm_libc {
10 
11 extern void *memcpy(void *__restrict, const void *__restrict, size_t);
12 extern void *memset(void *, int, size_t);
13 extern void bzero(void *, size_t);
14 extern int memcmp(const void *, const void *, size_t);
15 
16 } // namespace __llvm_libc
17 
18 using llvm::Align;
19 using llvm::ArrayRef;
20 using llvm::libc_benchmarks::ComparisonHarness;
21 using llvm::libc_benchmarks::CopyHarness;
22 using llvm::libc_benchmarks::MemorySizeDistribution;
23 using llvm::libc_benchmarks::OffsetDistribution;
24 using llvm::libc_benchmarks::SetHarness;
25 
26 static constexpr Align kBenchmarkAlignment = Align::Constant<1>();
27 
28 template <typename Harness> struct Randomized : public Harness {
29   Randomized(benchmark::State &State)
30       : State(State), Distribution(Harness::getDistributions()[State.range(0)]),
31         Probabilities(Distribution.Probabilities),
32         SizeSampler(Probabilities.begin(), Probabilities.end()),
33         OffsetSampler(Harness::BufferSize, Probabilities.size() - 1,
34                       kBenchmarkAlignment) {
35     for (auto &P : Harness::Parameters) {
36       P.OffsetBytes = OffsetSampler(Gen);
37       P.SizeBytes = SizeSampler(Gen);
38       Harness::checkValid(P);
39     }
40   }
41 
42   ~Randomized() {
43     const size_t AvgBytesPerIteration =
44         Harness::getBatchBytes() / Harness::BatchSize;
45     const size_t TotalBytes = State.iterations() * AvgBytesPerIteration;
46     State.SetBytesProcessed(TotalBytes);
47     State.SetLabel(Distribution.Name.str());
48     State.counters["bytes_per_cycle"] = benchmark::Counter(
49         TotalBytes / benchmark::CPUInfo::Get().cycles_per_second,
50         benchmark::Counter::kIsRate);
51   }
52 
53   template <typename Function> inline void runBatch(Function foo) {
54     for (const auto &P : Harness::Parameters)
55       benchmark::DoNotOptimize(Harness::Call(P, foo));
56   }
57 
58 private:
59   benchmark::State &State;
60   Harness UP;
61   MemorySizeDistribution Distribution;
62   ArrayRef<double> Probabilities;
63   std::discrete_distribution<unsigned> SizeSampler;
64   OffsetDistribution OffsetSampler;
65   std::mt19937_64 Gen;
66 };
67 
68 template <typename Harness> static int64_t getMaxIndex() {
69   return Harness::getDistributions().size() - 1;
70 }
71 
72 void BM_Memcpy(benchmark::State &State) {
73   Randomized<CopyHarness> Harness(State);
74   while (State.KeepRunningBatch(Harness.BatchSize))
75     Harness.runBatch(__llvm_libc::memcpy);
76 }
77 BENCHMARK(BM_Memcpy)->DenseRange(0, getMaxIndex<CopyHarness>());
78 
79 void BM_Memcmp(benchmark::State &State) {
80   Randomized<ComparisonHarness> Harness(State);
81   while (State.KeepRunningBatch(Harness.BatchSize))
82     Harness.runBatch(__llvm_libc::memcmp);
83 }
84 BENCHMARK(BM_Memcmp)->DenseRange(0, getMaxIndex<ComparisonHarness>());
85 
86 void BM_Memset(benchmark::State &State) {
87   Randomized<SetHarness> Harness(State);
88   while (State.KeepRunningBatch(Harness.BatchSize))
89     Harness.runBatch(__llvm_libc::memset);
90 }
91 BENCHMARK(BM_Memset)->DenseRange(0, getMaxIndex<SetHarness>());
92 
93 void BM_Bzero(benchmark::State &State) {
94   Randomized<SetHarness> Harness(State);
95   while (State.KeepRunningBatch(Harness.BatchSize))
96     Harness.runBatch(__llvm_libc::bzero);
97 }
98 BENCHMARK(BM_Bzero)->DenseRange(0, getMaxIndex<SetHarness>());
99