[libc-commits] [libc] 59198d0 - [libc] Add a Google Benchmark target to support continuous monitoring of memory operation performance

Guillaume Chatelet via libc-commits libc-commits at lists.llvm.org
Mon Aug 2 05:14:22 PDT 2021


Author: Guillaume Chatelet
Date: 2021-08-02T12:14:11Z
New Revision: 59198d062f409387393ee3843b3c999b1dc9947e

URL: https://github.com/llvm/llvm-project/commit/59198d062f409387393ee3843b3c999b1dc9947e
DIFF: https://github.com/llvm/llvm-project/commit/59198d062f409387393ee3843b3c999b1dc9947e.diff

LOG: [libc] Add a Google Benchmark target to support continuous monitoring of memory operation performance

The next step is to be able to benchmark several implementations at once and compare which one performs best on a particular machine.

Differential Revision: https://reviews.llvm.org/D107265

Added: 
    libc/benchmarks/LibcMemoryGoogleBenchmarkMain.cpp

Modified: 
    libc/benchmarks/CMakeLists.txt
    libc/benchmarks/LibcMemoryBenchmark.cpp
    libc/benchmarks/LibcMemoryBenchmark.h

Removed: 
    


################################################################################
diff  --git a/libc/benchmarks/CMakeLists.txt b/libc/benchmarks/CMakeLists.txt
index 71dbf836e50df..ba46faeaca839 100644
--- a/libc/benchmarks/CMakeLists.txt
+++ b/libc/benchmarks/CMakeLists.txt
@@ -171,3 +171,25 @@ add_libc_multi_impl_benchmark(memcpy)
 add_libc_multi_impl_benchmark(memset)
 add_libc_multi_impl_benchmark(bzero)
 add_libc_multi_impl_benchmark(memcmp)
+
+#==============================================================================
+# Google Benchmarking tool
+#==============================================================================
+
+# This target uses the Google Benchmark facility to report throughput for llvm
+# libc memory functions compiled for the host machine. This is useful to
+# continuously monitor the performance of the memory functions.
+add_executable(libc.benchmarks.memory_functions.opt_host
+  EXCLUDE_FROM_ALL
+  LibcMemoryGoogleBenchmarkMain.cpp
+)
+
+target_link_libraries(libc.benchmarks.memory_functions.opt_host
+  PRIVATE
+  libc-memory-benchmark
+  libc.src.string.memcmp_opt_host
+  libc.src.string.memcpy_opt_host
+  libc.src.string.memset_opt_host
+  libc.src.string.bzero_opt_host
+  benchmark_main
+)

diff  --git a/libc/benchmarks/LibcMemoryBenchmark.cpp b/libc/benchmarks/LibcMemoryBenchmark.cpp
index 37173a98189e6..a1606568aff92 100644
--- a/libc/benchmarks/LibcMemoryBenchmark.cpp
+++ b/libc/benchmarks/LibcMemoryBenchmark.cpp
@@ -104,13 +104,6 @@ void ParameterBatch::checkValid(const ParameterType &P) const {
             .concat(llvm::Twine(BufferSize)));
 }
 
-const ArrayRef<MemorySizeDistribution> CopyHarness::Distributions =
-    getMemcpySizeDistributions();
-const ArrayRef<MemorySizeDistribution> ComparisonHarness::Distributions =
-    getMemcmpSizeDistributions();
-const ArrayRef<MemorySizeDistribution> SetHarness::Distributions =
-    getMemsetSizeDistributions();
-
 CopyHarness::CopyHarness()
     : ParameterBatch(2), SrcBuffer(ParameterBatch::BufferSize),
       DstBuffer(ParameterBatch::BufferSize) {}

diff  --git a/libc/benchmarks/LibcMemoryBenchmark.h b/libc/benchmarks/LibcMemoryBenchmark.h
index 319e2d85811b9..23c9f0fa0c6a4 100644
--- a/libc/benchmarks/LibcMemoryBenchmark.h
+++ b/libc/benchmarks/LibcMemoryBenchmark.h
@@ -190,7 +190,9 @@ struct ParameterBatch {
 struct CopyHarness : public ParameterBatch {
   CopyHarness();
 
-  static const ArrayRef<MemorySizeDistribution> Distributions;
+  inline static const ArrayRef<MemorySizeDistribution> getDistributions() {
+    return getMemcpySizeDistributions();
+  }
 
   inline void *Call(ParameterType Parameter,
                     void *(*memcpy)(void *__restrict, const void *__restrict,
@@ -209,7 +211,9 @@ struct CopyHarness : public ParameterBatch {
 struct SetHarness : public ParameterBatch {
   SetHarness();
 
-  static const ArrayRef<MemorySizeDistribution> Distributions;
+  inline static const ArrayRef<MemorySizeDistribution> getDistributions() {
+    return getMemsetSizeDistributions();
+  }
 
   inline void *Call(ParameterType Parameter,
                     void *(*memset)(void *, int, size_t)) {
@@ -231,7 +235,9 @@ struct SetHarness : public ParameterBatch {
 struct ComparisonHarness : public ParameterBatch {
   ComparisonHarness();
 
-  static const ArrayRef<MemorySizeDistribution> Distributions;
+  inline static const ArrayRef<MemorySizeDistribution> getDistributions() {
+    return getMemcmpSizeDistributions();
+  }
 
   inline int Call(ParameterType Parameter,
                   int (*memcmp)(const void *, const void *, size_t)) {

diff  --git a/libc/benchmarks/LibcMemoryGoogleBenchmarkMain.cpp b/libc/benchmarks/LibcMemoryGoogleBenchmarkMain.cpp
new file mode 100644
index 0000000000000..39bf0950bafc0
--- /dev/null
+++ b/libc/benchmarks/LibcMemoryGoogleBenchmarkMain.cpp
@@ -0,0 +1,98 @@
+#include "LibcBenchmark.h"
+#include "LibcMemoryBenchmark.h"
+#include "MemorySizeDistributions.h"
+#include "benchmark/benchmark.h"
+#include <cstdint>
+#include <random>
+#include <vector>
+
+namespace __llvm_libc {
+
+extern void *memcpy(void *__restrict, const void *__restrict, size_t);
+extern void *memset(void *, int, size_t);
+extern void bzero(void *, size_t);
+extern int memcmp(const void *, const void *, size_t);
+
+} // namespace __llvm_libc
+
+using llvm::Align;
+using llvm::ArrayRef;
+using llvm::libc_benchmarks::ComparisonHarness;
+using llvm::libc_benchmarks::CopyHarness;
+using llvm::libc_benchmarks::MemorySizeDistribution;
+using llvm::libc_benchmarks::OffsetDistribution;
+using llvm::libc_benchmarks::SetHarness;
+
+static constexpr Align kBenchmarkAlignment = Align::Constant<1>();
+
+template <typename Harness> struct Randomized : public Harness {
+  Randomized(benchmark::State &State)
+      : State(State), Distribution(Harness::getDistributions()[State.range(0)]),
+        Probabilities(Distribution.Probabilities),
+        SizeSampler(Probabilities.begin(), Probabilities.end()),
+        OffsetSampler(Harness::BufferSize, Probabilities.size() - 1,
+                      kBenchmarkAlignment) {
+    for (auto &P : Harness::Parameters) {
+      P.OffsetBytes = OffsetSampler(Gen);
+      P.SizeBytes = SizeSampler(Gen);
+      Harness::checkValid(P);
+    }
+  }
+
+  ~Randomized() {
+    const size_t AvgBytesPerIteration =
+        Harness::getBatchBytes() / Harness::BatchSize;
+    const size_t TotalBytes = State.iterations() * AvgBytesPerIteration;
+    State.SetBytesProcessed(TotalBytes);
+    State.SetLabel(Distribution.Name.str());
+    State.counters["bytes_per_cycle"] = benchmark::Counter(
+        TotalBytes / benchmark::CPUInfo::Get().cycles_per_second,
+        benchmark::Counter::kIsRate);
+  }
+
+  template <typename Function> inline void runBatch(Function foo) {
+    for (const auto &P : Harness::Parameters)
+      benchmark::DoNotOptimize(Harness::Call(P, foo));
+  }
+
+private:
+  benchmark::State &State;
+  Harness UP;
+  MemorySizeDistribution Distribution;
+  ArrayRef<double> Probabilities;
+  std::discrete_distribution<unsigned> SizeSampler;
+  OffsetDistribution OffsetSampler;
+  std::mt19937_64 Gen;
+};
+
+template <typename Harness> static int64_t getMaxIndex() {
+  return Harness::getDistributions().size() - 1;
+}
+
+void BM_Memcpy(benchmark::State &State) {
+  Randomized<CopyHarness> Harness(State);
+  while (State.KeepRunningBatch(Harness.BatchSize))
+    Harness.runBatch(__llvm_libc::memcpy);
+}
+BENCHMARK(BM_Memcpy)->DenseRange(0, getMaxIndex<CopyHarness>());
+
+void BM_Memcmp(benchmark::State &State) {
+  Randomized<ComparisonHarness> Harness(State);
+  while (State.KeepRunningBatch(Harness.BatchSize))
+    Harness.runBatch(__llvm_libc::memcmp);
+}
+BENCHMARK(BM_Memcmp)->DenseRange(0, getMaxIndex<ComparisonHarness>());
+
+void BM_Memset(benchmark::State &State) {
+  Randomized<SetHarness> Harness(State);
+  while (State.KeepRunningBatch(Harness.BatchSize))
+    Harness.runBatch(__llvm_libc::memset);
+}
+BENCHMARK(BM_Memset)->DenseRange(0, getMaxIndex<SetHarness>());
+
+void BM_Bzero(benchmark::State &State) {
+  Randomized<SetHarness> Harness(State);
+  while (State.KeepRunningBatch(Harness.BatchSize))
+    Harness.runBatch(__llvm_libc::bzero);
+}
+BENCHMARK(BM_Bzero)->DenseRange(0, getMaxIndex<SetHarness>());


        


More information about the libc-commits mailing list