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