blob: c042b29cad98ead1bbadc5dbf7fcd72739db9e0c [file] [log] [blame]
Paula Toth21b6e3d2020-04-08 17:16:301//===-- Benchmark ---------------------------------------------------------===//
Guillaume Chatelet2179e252020-01-06 12:17:042//
3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4// See https://llvm.org/LICENSE.txt for license information.
5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6//
7//===----------------------------------------------------------------------===//
8
Guillaume Chatelet2179e252020-01-06 12:17:049#include "JSON.h"
10#include "LibcBenchmark.h"
11#include "LibcMemoryBenchmark.h"
Guillaume Chateletd791c7d2020-12-17 13:16:1412#include "MemorySizeDistributions.h"
Petr Hosek75b31cf2024-07-12 16:28:4113#include "src/__support/macros/config.h"
Guillaume Chatelet2179e252020-01-06 12:17:0414#include "llvm/Support/CommandLine.h"
15#include "llvm/Support/ErrorHandling.h"
16#include "llvm/Support/FileSystem.h"
17#include "llvm/Support/JSON.h"
Guillaume Chatelet6a9cfe32021-07-28 14:52:2918#include "llvm/Support/MathExtras.h"
Guillaume Chatelet2179e252020-01-06 12:17:0419#include "llvm/Support/MemoryBuffer.h"
20#include "llvm/Support/raw_ostream.h"
21
Guillaume Chateletba694662021-06-23 14:19:4022#include <cstring>
Guillaume Chatelet6a9cfe32021-07-28 14:52:2923#include <unistd.h>
Guillaume Chateletba694662021-06-23 14:19:4024
Petr Hosek75b31cf2024-07-12 16:28:4125namespace LIBC_NAMESPACE_DECL {
Guillaume Chateletd791c7d2020-12-17 13:16:1426
27extern void *memcpy(void *__restrict, const void *__restrict, size_t);
Guillaume Chatelet9438e582021-11-30 10:46:1628extern void *memmove(void *, const void *, size_t);
Guillaume Chateletd791c7d2020-12-17 13:16:1429extern void *memset(void *, int, size_t);
Guillaume Chateletba694662021-06-23 14:19:4030extern void bzero(void *, size_t);
31extern int memcmp(const void *, const void *, size_t);
Guillaume Chateletf8391692021-08-19 17:55:1632extern int bcmp(const void *, const void *, size_t);
Guillaume Chateletd791c7d2020-12-17 13:16:1433
Petr Hosek75b31cf2024-07-12 16:28:4134} // namespace LIBC_NAMESPACE_DECL
Siva Chandra Reddy4960d182020-04-28 21:00:1235
Guillaume Chatelet2179e252020-01-06 12:17:0436namespace llvm {
37namespace libc_benchmarks {
38
Guillaume Chateletd791c7d2020-12-17 13:16:1439static cl::opt<std::string>
40 StudyName("study-name", cl::desc("The name for this study"), cl::Required);
41
Guillaume Chateletd791c7d2020-12-17 13:16:1442static cl::opt<std::string>
43 SizeDistributionName("size-distribution-name",
44 cl::desc("The name of the distribution to use"));
45
Dmitry Vyukov62bfa2a2023-10-26 09:06:1546static cl::opt<bool> SweepMode(
47 "sweep-mode",
48 cl::desc(
49 "If set, benchmark all sizes from sweep-min-size to sweep-max-size"));
50
51static cl::opt<uint32_t>
52 SweepMinSize("sweep-min-size",
53 cl::desc("The minimum size to use in sweep-mode"),
54 cl::init(0));
Guillaume Chateletd791c7d2020-12-17 13:16:1455
56static cl::opt<uint32_t>
57 SweepMaxSize("sweep-max-size",
58 cl::desc("The maximum size to use in sweep-mode"),
59 cl::init(256));
60
61static cl::opt<uint32_t>
62 AlignedAccess("aligned-access",
63 cl::desc("The alignment to use when accessing the buffers\n"
64 "Default is unaligned\n"
65 "Use 0 to disable address randomization"),
66 cl::init(1));
67
68static cl::opt<std::string> Output("output",
69 cl::desc("Specify output filename"),
Guillaume Chatelet2179e252020-01-06 12:17:0470 cl::value_desc("filename"), cl::init("-"));
71
Guillaume Chateletd791c7d2020-12-17 13:16:1472static cl::opt<uint32_t>
73 NumTrials("num-trials", cl::desc("The number of benchmarks run to perform"),
74 cl::init(1));
Guillaume Chatelet2179e252020-01-06 12:17:0475
Guillaume Chatelet57059102021-06-10 13:04:5676#if defined(LIBC_BENCHMARK_FUNCTION_MEMCPY)
Guillaume Chatelet6a9cfe32021-07-28 14:52:2977#define LIBC_BENCHMARK_FUNCTION LIBC_BENCHMARK_FUNCTION_MEMCPY
Andre Vieira62725b42021-08-04 08:17:1278using BenchmarkSetup = CopySetup;
Guillaume Chatelet9438e582021-11-30 10:46:1679#elif defined(LIBC_BENCHMARK_FUNCTION_MEMMOVE)
80#define LIBC_BENCHMARK_FUNCTION LIBC_BENCHMARK_FUNCTION_MEMMOVE
81using BenchmarkSetup = MoveSetup;
Guillaume Chatelet57059102021-06-10 13:04:5682#elif defined(LIBC_BENCHMARK_FUNCTION_MEMSET)
Guillaume Chatelet6a9cfe32021-07-28 14:52:2983#define LIBC_BENCHMARK_FUNCTION LIBC_BENCHMARK_FUNCTION_MEMSET
Andre Vieira62725b42021-08-04 08:17:1284using BenchmarkSetup = SetSetup;
Guillaume Chateletba694662021-06-23 14:19:4085#elif defined(LIBC_BENCHMARK_FUNCTION_BZERO)
Guillaume Chatelet6a9cfe32021-07-28 14:52:2986#define LIBC_BENCHMARK_FUNCTION LIBC_BENCHMARK_FUNCTION_BZERO
Andre Vieira62725b42021-08-04 08:17:1287using BenchmarkSetup = SetSetup;
Guillaume Chateletba694662021-06-23 14:19:4088#elif defined(LIBC_BENCHMARK_FUNCTION_MEMCMP)
Guillaume Chatelet6a9cfe32021-07-28 14:52:2989#define LIBC_BENCHMARK_FUNCTION LIBC_BENCHMARK_FUNCTION_MEMCMP
Andre Vieira62725b42021-08-04 08:17:1290using BenchmarkSetup = ComparisonSetup;
Guillaume Chateletf8391692021-08-19 17:55:1691#elif defined(LIBC_BENCHMARK_FUNCTION_BCMP)
92#define LIBC_BENCHMARK_FUNCTION LIBC_BENCHMARK_FUNCTION_BCMP
93using BenchmarkSetup = ComparisonSetup;
Guillaume Chatelet57059102021-06-10 13:04:5694#else
95#error "Missing LIBC_BENCHMARK_FUNCTION_XXX definition"
96#endif
Guillaume Chateletd791c7d2020-12-17 13:16:1497
Andre Vieira62725b42021-08-04 08:17:1298struct MemfunctionBenchmarkBase : public BenchmarkSetup {
Guillaume Chatelet6a9cfe32021-07-28 14:52:2999 MemfunctionBenchmarkBase() : ReportProgress(isatty(fileno(stdout))) {}
100 virtual ~MemfunctionBenchmarkBase() {}
Guillaume Chateletd791c7d2020-12-17 13:16:14101
Guillaume Chatelet6a9cfe32021-07-28 14:52:29102 virtual Study run() = 0;
103
104 CircularArrayRef<ParameterBatch::ParameterType>
105 generateBatch(size_t Iterations) {
106 randomize();
serge-sans-paille062579a2023-01-09 17:11:07107 return cycle(ArrayRef(Parameters), Iterations);
Guillaume Chateletd791c7d2020-12-17 13:16:14108 }
109
Guillaume Chatelet6a9cfe32021-07-28 14:52:29110protected:
111 Study createStudy() {
112 Study Study;
Andre Vieira62725b42021-08-04 08:17:12113 // Setup study.
Guillaume Chateletd791c7d2020-12-17 13:16:14114 Study.StudyName = StudyName;
115 Runtime &RI = Study.Runtime;
116 RI.Host = HostState::get();
117 RI.BufferSize = BufferSize;
Guillaume Chatelet6a9cfe32021-07-28 14:52:29118 RI.BatchParameterCount = BatchSize;
Guillaume Chateletd791c7d2020-12-17 13:16:14119
120 BenchmarkOptions &BO = RI.BenchmarkOptions;
121 BO.MinDuration = std::chrono::milliseconds(1);
122 BO.MaxDuration = std::chrono::seconds(1);
123 BO.MaxIterations = 10'000'000U;
124 BO.MinSamples = 4;
125 BO.MaxSamples = 1000;
126 BO.Epsilon = 0.01; // 1%
127 BO.ScalingFactor = 1.4;
128
129 StudyConfiguration &SC = Study.Configuration;
130 SC.NumTrials = NumTrials;
131 SC.IsSweepMode = SweepMode;
Guillaume Chateletd791c7d2020-12-17 13:16:14132 SC.AccessAlignment = MaybeAlign(AlignedAccess);
Guillaume Chatelet57059102021-06-10 13:04:56133 SC.Function = LIBC_BENCHMARK_FUNCTION_NAME;
Guillaume Chateletd791c7d2020-12-17 13:16:14134 return Study;
135 }
136
Guillaume Chatelet6a9cfe32021-07-28 14:52:29137 void runTrials(const BenchmarkOptions &Options,
138 std::vector<Duration> &Measurements) {
139 for (size_t i = 0; i < NumTrials; ++i) {
140 const BenchmarkResult Result = benchmark(
141 Options, *this, [this](ParameterBatch::ParameterType Parameter) {
142 return Call(Parameter, LIBC_BENCHMARK_FUNCTION);
143 });
144 Measurements.push_back(Result.BestGuess);
145 reportProgress(Measurements);
146 }
147 }
148
149 virtual void randomize() = 0;
150
Guillaume Chateletd791c7d2020-12-17 13:16:14151private:
Guillaume Chatelet6a9cfe32021-07-28 14:52:29152 bool ReportProgress;
Guillaume Chateletd791c7d2020-12-17 13:16:14153
Guillaume Chatelet6a9cfe32021-07-28 14:52:29154 void reportProgress(const std::vector<Duration> &Measurements) {
155 if (!ReportProgress)
156 return;
Guillaume Chatelet4ebed712021-01-13 14:06:36157 static size_t LastPercent = -1;
Guillaume Chatelet6a9cfe32021-07-28 14:52:29158 const size_t TotalSteps = Measurements.capacity();
159 const size_t Steps = Measurements.size();
Guillaume Chateletd791c7d2020-12-17 13:16:14160 const size_t Percent = 100 * Steps / TotalSteps;
Guillaume Chatelet4ebed712021-01-13 14:06:36161 if (Percent == LastPercent)
162 return;
163 LastPercent = Percent;
Guillaume Chateletd791c7d2020-12-17 13:16:14164 size_t I = 0;
165 errs() << '[';
166 for (; I <= Percent; ++I)
167 errs() << '#';
168 for (; I <= 100; ++I)
169 errs() << '_';
Guillaume Chatelet4ebed712021-01-13 14:06:36170 errs() << "] " << Percent << '%' << '\r';
Guillaume Chateletd791c7d2020-12-17 13:16:14171 }
Guillaume Chatelet6a9cfe32021-07-28 14:52:29172};
Guillaume Chateletd791c7d2020-12-17 13:16:14173
Guillaume Chatelet6a9cfe32021-07-28 14:52:29174struct MemfunctionBenchmarkSweep final : public MemfunctionBenchmarkBase {
175 MemfunctionBenchmarkSweep()
176 : OffsetSampler(MemfunctionBenchmarkBase::BufferSize, SweepMaxSize,
177 MaybeAlign(AlignedAccess)) {}
178
179 virtual void randomize() override {
180 for (auto &P : Parameters) {
181 P.OffsetBytes = OffsetSampler(Gen);
182 P.SizeBytes = CurrentSweepSize;
183 checkValid(P);
Guillaume Chateletd791c7d2020-12-17 13:16:14184 }
185 }
186
Guillaume Chatelet6a9cfe32021-07-28 14:52:29187 virtual Study run() override {
188 Study Study = createStudy();
189 Study.Configuration.SweepModeMaxSize = SweepMaxSize;
Guillaume Chateletd791c7d2020-12-17 13:16:14190 BenchmarkOptions &BO = Study.Runtime.BenchmarkOptions;
191 BO.MinDuration = std::chrono::milliseconds(1);
192 BO.InitialIterations = 100;
Guillaume Chatelet6a9cfe32021-07-28 14:52:29193 auto &Measurements = Study.Measurements;
194 Measurements.reserve(NumTrials * SweepMaxSize);
Dmitry Vyukov62bfa2a2023-10-26 09:06:15195 for (size_t Size = SweepMinSize; Size <= SweepMaxSize; ++Size) {
Guillaume Chatelet6a9cfe32021-07-28 14:52:29196 CurrentSweepSize = Size;
197 runTrials(BO, Measurements);
198 }
199 return Study;
200 }
201
202private:
203 size_t CurrentSweepSize = 0;
204 OffsetDistribution OffsetSampler;
205 std::mt19937_64 Gen;
206};
207
208struct MemfunctionBenchmarkDistribution final
209 : public MemfunctionBenchmarkBase {
210 MemfunctionBenchmarkDistribution(MemorySizeDistribution Distribution)
211 : Distribution(Distribution), Probabilities(Distribution.Probabilities),
212 SizeSampler(Probabilities.begin(), Probabilities.end()),
213 OffsetSampler(MemfunctionBenchmarkBase::BufferSize,
214 Probabilities.size() - 1, MaybeAlign(AlignedAccess)) {}
215
216 virtual void randomize() override {
217 for (auto &P : Parameters) {
218 P.OffsetBytes = OffsetSampler(Gen);
219 P.SizeBytes = SizeSampler(Gen);
220 checkValid(P);
Guillaume Chateletd791c7d2020-12-17 13:16:14221 }
222 }
223
Guillaume Chatelet6a9cfe32021-07-28 14:52:29224 virtual Study run() override {
225 Study Study = createStudy();
226 Study.Configuration.SizeDistributionName = Distribution.Name.str();
Guillaume Chateletd791c7d2020-12-17 13:16:14227 BenchmarkOptions &BO = Study.Runtime.BenchmarkOptions;
228 BO.MinDuration = std::chrono::milliseconds(10);
Guillaume Chatelet6a9cfe32021-07-28 14:52:29229 BO.InitialIterations = BatchSize * 10;
230 auto &Measurements = Study.Measurements;
231 Measurements.reserve(NumTrials);
232 runTrials(BO, Measurements);
233 return Study;
Guillaume Chateletd791c7d2020-12-17 13:16:14234 }
Guillaume Chatelet6a9cfe32021-07-28 14:52:29235
236private:
237 MemorySizeDistribution Distribution;
238 ArrayRef<double> Probabilities;
239 std::discrete_distribution<unsigned> SizeSampler;
240 OffsetDistribution OffsetSampler;
241 std::mt19937_64 Gen;
Guillaume Chateletd791c7d2020-12-17 13:16:14242};
243
Guillaume Chateletd791c7d2020-12-17 13:16:14244void writeStudy(const Study &S) {
Guillaume Chatelet2179e252020-01-06 12:17:04245 std::error_code EC;
246 raw_fd_ostream FOS(Output, EC);
247 if (EC)
248 report_fatal_error(Twine("Could not open file: ")
249 .concat(EC.message())
250 .concat(", ")
251 .concat(Output));
252 json::OStream JOS(FOS);
Guillaume Chateletd791c7d2020-12-17 13:16:14253 serializeToJson(S, JOS);
Guillaume Chatelet4ebed712021-01-13 14:06:36254 FOS << "\n";
Guillaume Chateletd791c7d2020-12-17 13:16:14255}
256
257void main() {
258 checkRequirements();
Guillaume Chatelet6a9cfe32021-07-28 14:52:29259 if (!isPowerOf2_32(AlignedAccess))
260 report_fatal_error(AlignedAccess.ArgStr +
261 Twine(" must be a power of two or zero"));
262
263 const bool HasDistributionName = !SizeDistributionName.empty();
264 if (SweepMode && HasDistributionName)
265 report_fatal_error("Select only one of `--" + Twine(SweepMode.ArgStr) +
266 "` or `--" + Twine(SizeDistributionName.ArgStr) + "`");
267
268 std::unique_ptr<MemfunctionBenchmarkBase> Benchmark;
269 if (SweepMode)
270 Benchmark.reset(new MemfunctionBenchmarkSweep());
271 else
272 Benchmark.reset(new MemfunctionBenchmarkDistribution(getDistributionOrDie(
Andre Vieira62725b42021-08-04 08:17:12273 BenchmarkSetup::getDistributions(), SizeDistributionName)));
Guillaume Chatelet6a9cfe32021-07-28 14:52:29274 writeStudy(Benchmark->run());
Guillaume Chatelet2179e252020-01-06 12:17:04275}
276
277} // namespace libc_benchmarks
278} // namespace llvm
279
Guillaume Chatelet6a9cfe32021-07-28 14:52:29280#ifndef NDEBUG
281#error For reproducibility benchmarks should not be compiled in DEBUG mode.
282#endif
283
Guillaume Chatelet2179e252020-01-06 12:17:04284int main(int argc, char **argv) {
285 llvm::cl::ParseCommandLineOptions(argc, argv);
Guillaume Chateletd791c7d2020-12-17 13:16:14286 llvm::libc_benchmarks::main();
Guillaume Chatelet2179e252020-01-06 12:17:04287 return EXIT_SUCCESS;
288}