Update benchmark to allow it to be built in runtimes driven mode. It is still useful to have an in-tree benchmark suite. On my side, I am working on some allocators related benchmarks. Due to the broken state of this in-tree benchmark suite, I have to frequently port changes between two workspace. Also, having benchmark suite can make it easier to track performance change in a consistent view. Assisted-by: AI tools, checked manually
126 lines
5.2 KiB
C++
126 lines
5.2 KiB
C++
#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 <chrono>
|
|
#include <cstdint>
|
|
#include <random>
|
|
#include <vector>
|
|
|
|
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 <typename SetupType, typename ConfigurationType> struct Runner {
|
|
Runner(benchmark::State &S, llvm::ArrayRef<ConfigurationType> 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<double> probabilities;
|
|
std::discrete_distribution<unsigned> 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, CONFIGURATION_TYPE> 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<MemcpyConfiguration> getMemcpyConfigurations();
|
|
BENCHMARK_MEMORY_FUNCTION(BM_Memcpy, CopySetup, MemcpyConfiguration,
|
|
getMemcpyConfigurations());
|
|
|
|
extern llvm::ArrayRef<MemmoveConfiguration> getMemmoveConfigurations();
|
|
BENCHMARK_MEMORY_FUNCTION(BM_Memmove, MoveSetup, MemmoveConfiguration,
|
|
getMemmoveConfigurations());
|
|
|
|
extern llvm::ArrayRef<MemcmpOrBcmpConfiguration> getMemcmpConfigurations();
|
|
BENCHMARK_MEMORY_FUNCTION(BM_Memcmp, ComparisonSetup, MemcmpOrBcmpConfiguration,
|
|
getMemcmpConfigurations());
|
|
|
|
extern llvm::ArrayRef<MemcmpOrBcmpConfiguration> getBcmpConfigurations();
|
|
BENCHMARK_MEMORY_FUNCTION(BM_Bcmp, ComparisonSetup, MemcmpOrBcmpConfiguration,
|
|
getBcmpConfigurations());
|
|
|
|
extern llvm::ArrayRef<MemsetConfiguration> getMemsetConfigurations();
|
|
BENCHMARK_MEMORY_FUNCTION(BM_Memset, SetSetup, MemsetConfiguration,
|
|
getMemsetConfigurations());
|
|
|
|
extern llvm::ArrayRef<BzeroConfiguration> getBzeroConfigurations();
|
|
BENCHMARK_MEMORY_FUNCTION(BM_Bzero, SetSetup, BzeroConfiguration,
|
|
getBzeroConfigurations());
|