|  | //===-- Benchmark memcmp implementation -----------------------------------===// | 
|  | // | 
|  | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. | 
|  | // See https://llvm.org/LICENSE.txt for license information. | 
|  | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception | 
|  | // | 
|  | //===----------------------------------------------------------------------===// | 
|  |  | 
|  | #include "LibcBenchmark.h" | 
|  | #include "LibcMemoryBenchmark.h" | 
|  | #include "LibcMemoryBenchmarkMain.h" | 
|  | #include "llvm/ADT/StringSwitch.h" | 
|  | #include "llvm/Support/raw_ostream.h" | 
|  |  | 
|  | namespace llvm { | 
|  | namespace libc_benchmarks { | 
|  |  | 
|  | // The context encapsulates the buffers, parameters and the measure. | 
|  | struct MemcmpContext : public BenchmarkRunner { | 
|  | using FunctionPrototype = int (*)(const void *, const void *, size_t); | 
|  |  | 
|  | struct ParameterType { | 
|  | uint16_t Offset = 0; | 
|  | }; | 
|  |  | 
|  | explicit MemcmpContext(const StudyConfiguration &Conf) | 
|  | : MOD(Conf), OD(Conf), ABuffer(Conf.BufferSize), BBuffer(Conf.BufferSize), | 
|  | PP(*this) { | 
|  | std::uniform_int_distribution<char> Dis; | 
|  | // Generate random buffer A. | 
|  | for (size_t I = 0; I < Conf.BufferSize; ++I) | 
|  | ABuffer[I] = Dis(Gen); | 
|  | // Copy buffer A to B. | 
|  | ::memcpy(BBuffer.begin(), ABuffer.begin(), Conf.BufferSize); | 
|  | if (Conf.MemcmpMismatchAt == 0) | 
|  | return; // all same. | 
|  | else if (Conf.MemcmpMismatchAt == 1) | 
|  | for (char &c : BBuffer) | 
|  | ++c; // all different. | 
|  | else | 
|  | for (const auto I : MOD.getMismatchIndices()) | 
|  | ++BBuffer[I]; | 
|  | } | 
|  |  | 
|  | // Needed by the ParameterProvider to update the current batch of parameter. | 
|  | void Randomize(MutableArrayRef<ParameterType> Parameters) { | 
|  | if (MOD) | 
|  | for (auto &P : Parameters) | 
|  | P.Offset = MOD(Gen, CurrentSize); | 
|  | else | 
|  | for (auto &P : Parameters) | 
|  | P.Offset = OD(Gen); | 
|  | } | 
|  |  | 
|  | ArrayRef<StringRef> getFunctionNames() const override { | 
|  | static std::array<StringRef, 1> kFunctionNames = {"memcmp"}; | 
|  | return kFunctionNames; | 
|  | } | 
|  |  | 
|  | BenchmarkResult benchmark(const BenchmarkOptions &Options, | 
|  | StringRef FunctionName, size_t Size) override { | 
|  | CurrentSize = Size; | 
|  | // FIXME: Add `bcmp` once we're guaranteed that the function is provided. | 
|  | FunctionPrototype Function = | 
|  | StringSwitch<FunctionPrototype>(FunctionName).Case("memcmp", &::memcmp); | 
|  | return llvm::libc_benchmarks::benchmark( | 
|  | Options, PP, [this, Function, Size](ParameterType p) { | 
|  | return Function(ABuffer + p.Offset, BBuffer + p.Offset, Size); | 
|  | }); | 
|  | } | 
|  |  | 
|  | private: | 
|  | std::default_random_engine Gen; | 
|  | MismatchOffsetDistribution MOD; | 
|  | OffsetDistribution OD; | 
|  | size_t CurrentSize = 0; | 
|  | AlignedBuffer ABuffer; | 
|  | AlignedBuffer BBuffer; | 
|  | SmallParameterProvider<MemcmpContext> PP; | 
|  | }; | 
|  |  | 
|  | std::unique_ptr<BenchmarkRunner> getRunner(const StudyConfiguration &Conf) { | 
|  | return std::make_unique<MemcmpContext>(Conf); | 
|  | } | 
|  |  | 
|  | } // namespace libc_benchmarks | 
|  | } // namespace llvm |