1 //===-- Benchmark memcmp implementation -----------------------------------===//
2 //
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6 //
7 //===----------------------------------------------------------------------===//
8 
9 #include "LibcBenchmark.h"
10 #include "LibcMemoryBenchmark.h"
11 #include "LibcMemoryBenchmarkMain.h"
12 #include "llvm/ADT/StringSwitch.h"
13 #include "llvm/Support/raw_ostream.h"
14 
15 namespace llvm {
16 namespace libc_benchmarks {
17 
18 // The context encapsulates the buffers, parameters and the measure.
19 struct MemcmpContext : public BenchmarkRunner {
20   using FunctionPrototype = int (*)(const void *, const void *, size_t);
21 
22   struct ParameterType {
23     uint16_t Offset = 0;
24   };
25 
MemcmpContextllvm::libc_benchmarks::MemcmpContext26   explicit MemcmpContext(const StudyConfiguration &Conf)
27       : MOD(Conf), OD(Conf), ABuffer(Conf.BufferSize), BBuffer(Conf.BufferSize),
28         PP(*this) {
29     std::uniform_int_distribution<char> Dis;
30     // Generate random buffer A.
31     for (size_t I = 0; I < Conf.BufferSize; ++I)
32       ABuffer[I] = Dis(Gen);
33     // Copy buffer A to B.
34     ::memcpy(BBuffer.begin(), ABuffer.begin(), Conf.BufferSize);
35     if (Conf.MemcmpMismatchAt == 0)
36       return; // all same.
37     else if (Conf.MemcmpMismatchAt == 1)
38       for (char &c : BBuffer)
39         ++c; // all different.
40     else
41       for (const auto I : MOD.getMismatchIndices())
42         ++BBuffer[I];
43   }
44 
45   // Needed by the ParameterProvider to update the current batch of parameter.
Randomizellvm::libc_benchmarks::MemcmpContext46   void Randomize(MutableArrayRef<ParameterType> Parameters) {
47     if (MOD)
48       for (auto &P : Parameters)
49         P.Offset = MOD(Gen, CurrentSize);
50     else
51       for (auto &P : Parameters)
52         P.Offset = OD(Gen);
53   }
54 
getFunctionNamesllvm::libc_benchmarks::MemcmpContext55   ArrayRef<StringRef> getFunctionNames() const override {
56     static std::array<StringRef, 1> kFunctionNames = {"memcmp"};
57     return kFunctionNames;
58   }
59 
benchmarkllvm::libc_benchmarks::MemcmpContext60   BenchmarkResult benchmark(const BenchmarkOptions &Options,
61                             StringRef FunctionName, size_t Size) override {
62     CurrentSize = Size;
63     // FIXME: Add `bcmp` once we're guaranteed that the function is provided.
64     FunctionPrototype Function =
65         StringSwitch<FunctionPrototype>(FunctionName).Case("memcmp", &::memcmp);
66     return llvm::libc_benchmarks::benchmark(
67         Options, PP, [this, Function, Size](ParameterType p) {
68           return Function(ABuffer + p.Offset, BBuffer + p.Offset, Size);
69         });
70   }
71 
72 private:
73   std::default_random_engine Gen;
74   MismatchOffsetDistribution MOD;
75   OffsetDistribution OD;
76   size_t CurrentSize = 0;
77   AlignedBuffer ABuffer;
78   AlignedBuffer BBuffer;
79   SmallParameterProvider<MemcmpContext> PP;
80 };
81 
getRunner(const StudyConfiguration & Conf)82 std::unique_ptr<BenchmarkRunner> getRunner(const StudyConfiguration &Conf) {
83   return std::make_unique<MemcmpContext>(Conf);
84 }
85 
86 } // namespace libc_benchmarks
87 } // namespace llvm
88