#include "LibcBenchmark.h" #include "LibcMemoryBenchmark.h" #include "MemorySizeDistributions.h" #include "benchmark/benchmark.h" #include "llvm/ADT/ArrayRef.h" #ifdef LIBC_BENCHMARKS_HAS_LLVM_SUPPORT #include "llvm/ADT/Twine.h" #endif #include #include #include #include using llvm::Align; using llvm::ArrayRef; #ifdef LIBC_BENCHMARKS_HAS_LLVM_SUPPORT using llvm::Twine; #endif using llvm::libc_benchmarks::BzeroConfiguration; using llvm::libc_benchmarks::ComparisonSetup; using llvm::libc_benchmarks::CopySetup; using llvm::libc_benchmarks::MemcmpOrBcmpConfiguration; using llvm::libc_benchmarks::MemcpyConfiguration; using llvm::libc_benchmarks::MemmoveConfiguration; using llvm::libc_benchmarks::MemorySizeDistribution; using llvm::libc_benchmarks::MemsetConfiguration; using llvm::libc_benchmarks::MoveSetup; using llvm::libc_benchmarks::OffsetDistribution; using llvm::libc_benchmarks::SetSetup; // Alignment to use for when accessing the buffers. static constexpr Align kBenchmarkAlignment = Align::Constant<1>(); static std::mt19937_64 &getGenerator() { static std::mt19937_64 Generator( std::chrono::system_clock::now().time_since_epoch().count()); return Generator; } template struct Runner { Runner(benchmark::State &S, llvm::ArrayRef Configurations) : State(S), distribution(SetupType::get_distributions()[State.range(0)]), probabilities(distribution.probabilities), size_sampler(probabilities.begin(), probabilities.end()), offset_sampler(Setup.buffer_size, probabilities.size() - 1, kBenchmarkAlignment), configuration(Configurations[State.range(1)]) { for (auto &p : Setup.parameters) { p.offset_bytes = offset_sampler(getGenerator()); p.size_bytes = size_sampler(getGenerator()); Setup.check_valid(p); } } ~Runner() { const size_t total_bytes = (State.iterations() * Setup.get_batch_bytes()) / Setup.batch_size; State.SetBytesProcessed(total_bytes); State.SetItemsProcessed(State.iterations()); #ifdef LIBC_BENCHMARKS_HAS_LLVM_SUPPORT State.SetLabel((Twine(configuration.name) + "," + distribution.name).str()); #else State.SetLabel(configuration.name.str() + "," + distribution.name.str()); #endif State.counters["bytes_per_cycle"] = benchmark::Counter( total_bytes / benchmark::CPUInfo::Get().cycles_per_second, benchmark::Counter::kIsRate); } inline void run_batch() { for (const auto &p : Setup.parameters) benchmark::DoNotOptimize(Setup.call(p, configuration.function)); } size_t get_batch_size() const { return Setup.batch_size; } private: SetupType Setup; benchmark::State &State; MemorySizeDistribution distribution; ArrayRef probabilities; std::discrete_distribution size_sampler; OffsetDistribution offset_sampler; ConfigurationType configuration; }; #define BENCHMARK_MEMORY_FUNCTION(BM_NAME, SETUP, CONFIGURATION_TYPE, \ CONFIGURATION_ARRAY_REF) \ void BM_NAME(benchmark::State &State) { \ Runner Setup(State, CONFIGURATION_ARRAY_REF); \ const size_t batch_size_val = Setup.get_batch_size(); \ while (State.KeepRunningBatch(batch_size_val)) \ Setup.run_batch(); \ } \ BENCHMARK(BM_NAME)->Apply([](benchmark::internal::Benchmark *benchmark) { \ const int64_t DistributionSize = SETUP::get_distributions().size(); \ const int64_t ConfigurationSize = CONFIGURATION_ARRAY_REF.size(); \ for (int64_t DistIndex = 0; DistIndex < DistributionSize; ++DistIndex) \ for (int64_t ConfIndex = 0; ConfIndex < ConfigurationSize; ++ConfIndex) \ benchmark->Args({DistIndex, ConfIndex}); \ }) extern llvm::ArrayRef getMemcpyConfigurations(); BENCHMARK_MEMORY_FUNCTION(BM_Memcpy, CopySetup, MemcpyConfiguration, getMemcpyConfigurations()); extern llvm::ArrayRef getMemmoveConfigurations(); BENCHMARK_MEMORY_FUNCTION(BM_Memmove, MoveSetup, MemmoveConfiguration, getMemmoveConfigurations()); extern llvm::ArrayRef getMemcmpConfigurations(); BENCHMARK_MEMORY_FUNCTION(BM_Memcmp, ComparisonSetup, MemcmpOrBcmpConfiguration, getMemcmpConfigurations()); extern llvm::ArrayRef getBcmpConfigurations(); BENCHMARK_MEMORY_FUNCTION(BM_Bcmp, ComparisonSetup, MemcmpOrBcmpConfiguration, getBcmpConfigurations()); extern llvm::ArrayRef getMemsetConfigurations(); BENCHMARK_MEMORY_FUNCTION(BM_Memset, SetSetup, MemsetConfiguration, getMemsetConfigurations()); extern llvm::ArrayRef getBzeroConfigurations(); BENCHMARK_MEMORY_FUNCTION(BM_Bzero, SetSetup, BzeroConfiguration, getBzeroConfigurations());