xref: /llvm-project/libc/benchmarks/LibcBenchmark.h (revision 081a80f2b56763422183542ad10b5a6b0814312e)
1438f7fc0SSiva Chandra Reddy //===-- Benchmark function --------------------------------------*- C++ -*-===//
2438f7fc0SSiva Chandra Reddy //
3438f7fc0SSiva Chandra Reddy // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4438f7fc0SSiva Chandra Reddy // See https://llvm.org/LICENSE.txt for license information.
5438f7fc0SSiva Chandra Reddy // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6438f7fc0SSiva Chandra Reddy //
7438f7fc0SSiva Chandra Reddy //===----------------------------------------------------------------------===//
8438f7fc0SSiva Chandra Reddy 
9438f7fc0SSiva Chandra Reddy // This file mainly defines a `Benchmark` function.
10438f7fc0SSiva Chandra Reddy //
11438f7fc0SSiva Chandra Reddy // The benchmarking process is as follows:
12438f7fc0SSiva Chandra Reddy // - We start by measuring the time it takes to run the function
13438f7fc0SSiva Chandra Reddy // `InitialIterations` times. This is called a Sample. From this we can derive
14438f7fc0SSiva Chandra Reddy // the time it took to run a single iteration.
15438f7fc0SSiva Chandra Reddy //
16438f7fc0SSiva Chandra Reddy // - We repeat the previous step with a greater number of iterations to lower
17438f7fc0SSiva Chandra Reddy // the impact of the measurement. We can derive a more precise estimation of the
18438f7fc0SSiva Chandra Reddy // runtime for a single iteration.
19438f7fc0SSiva Chandra Reddy //
20438f7fc0SSiva Chandra Reddy // - Each sample gives a more accurate estimation of the runtime for a single
21438f7fc0SSiva Chandra Reddy // iteration but also takes more time to run. We stop the process when:
22438f7fc0SSiva Chandra Reddy //   * The measure stabilize under a certain precision (Epsilon),
23438f7fc0SSiva Chandra Reddy //   * The overall benchmarking time is greater than MaxDuration,
24438f7fc0SSiva Chandra Reddy //   * The overall sample count is greater than MaxSamples,
25438f7fc0SSiva Chandra Reddy //   * The last sample used more than MaxIterations iterations.
26438f7fc0SSiva Chandra Reddy //
27438f7fc0SSiva Chandra Reddy // - We also makes sure that the benchmark doesn't run for a too short period of
28438f7fc0SSiva Chandra Reddy // time by defining MinDuration and MinSamples.
29438f7fc0SSiva Chandra Reddy 
30438f7fc0SSiva Chandra Reddy #ifndef LLVM_LIBC_UTILS_BENCHMARK_BENCHMARK_H
31438f7fc0SSiva Chandra Reddy #define LLVM_LIBC_UTILS_BENCHMARK_BENCHMARK_H
32438f7fc0SSiva Chandra Reddy 
33438f7fc0SSiva Chandra Reddy #include "benchmark/benchmark.h"
34438f7fc0SSiva Chandra Reddy #include "llvm/ADT/ArrayRef.h"
35438f7fc0SSiva Chandra Reddy #include "llvm/ADT/SmallVector.h"
36438f7fc0SSiva Chandra Reddy #include <array>
37438f7fc0SSiva Chandra Reddy #include <chrono>
38c2ab3d2cSSimon Pilgrim #include <cmath>
39438f7fc0SSiva Chandra Reddy #include <cstdint>
40b5516be0SKazu Hirata #include <optional>
41438f7fc0SSiva Chandra Reddy 
42438f7fc0SSiva Chandra Reddy namespace llvm {
43438f7fc0SSiva Chandra Reddy namespace libc_benchmarks {
44438f7fc0SSiva Chandra Reddy 
45438f7fc0SSiva Chandra Reddy using Duration = std::chrono::duration<double>;
46438f7fc0SSiva Chandra Reddy 
47438f7fc0SSiva Chandra Reddy enum class BenchmarkLog {
48438f7fc0SSiva Chandra Reddy   None, // Don't keep the internal state of the benchmark.
49438f7fc0SSiva Chandra Reddy   Last, // Keep only the last batch.
50438f7fc0SSiva Chandra Reddy   Full  // Keep all iterations states, useful for testing or debugging.
51438f7fc0SSiva Chandra Reddy };
52438f7fc0SSiva Chandra Reddy 
53438f7fc0SSiva Chandra Reddy // An object to configure the benchmark stopping conditions.
54438f7fc0SSiva Chandra Reddy // See documentation at the beginning of the file for the overall algorithm and
55438f7fc0SSiva Chandra Reddy // meaning of each field.
56438f7fc0SSiva Chandra Reddy struct BenchmarkOptions {
57438f7fc0SSiva Chandra Reddy   // The minimum time for which the benchmark is running.
58438f7fc0SSiva Chandra Reddy   Duration MinDuration = std::chrono::seconds(0);
59438f7fc0SSiva Chandra Reddy   // The maximum time for which the benchmark is running.
60438f7fc0SSiva Chandra Reddy   Duration MaxDuration = std::chrono::seconds(10);
61438f7fc0SSiva Chandra Reddy   // The number of iterations in the first sample.
62438f7fc0SSiva Chandra Reddy   uint32_t InitialIterations = 1;
63438f7fc0SSiva Chandra Reddy   // The maximum number of iterations for any given sample.
64438f7fc0SSiva Chandra Reddy   uint32_t MaxIterations = 10000000;
65438f7fc0SSiva Chandra Reddy   // The minimum number of samples.
66438f7fc0SSiva Chandra Reddy   uint32_t MinSamples = 4;
67438f7fc0SSiva Chandra Reddy   // The maximum number of samples.
68438f7fc0SSiva Chandra Reddy   uint32_t MaxSamples = 1000;
69d28f6729SChris Gyurgyik   // The benchmark will stop if the relative difference between the current and
70438f7fc0SSiva Chandra Reddy   // the last estimation is less than epsilon. This is 1% by default.
71438f7fc0SSiva Chandra Reddy   double Epsilon = 0.01;
72438f7fc0SSiva Chandra Reddy   // The number of iterations grows exponentially between each sample.
73438f7fc0SSiva Chandra Reddy   // Must be greater or equal to 1.
74438f7fc0SSiva Chandra Reddy   double ScalingFactor = 1.4;
75438f7fc0SSiva Chandra Reddy   BenchmarkLog Log = BenchmarkLog::None;
76438f7fc0SSiva Chandra Reddy };
77438f7fc0SSiva Chandra Reddy 
78438f7fc0SSiva Chandra Reddy // The state of a benchmark.
79438f7fc0SSiva Chandra Reddy enum class BenchmarkStatus {
80438f7fc0SSiva Chandra Reddy   Running,
81438f7fc0SSiva Chandra Reddy   MaxDurationReached,
82438f7fc0SSiva Chandra Reddy   MaxIterationsReached,
83438f7fc0SSiva Chandra Reddy   MaxSamplesReached,
84438f7fc0SSiva Chandra Reddy   PrecisionReached,
85438f7fc0SSiva Chandra Reddy };
86438f7fc0SSiva Chandra Reddy 
87438f7fc0SSiva Chandra Reddy // The internal state of the benchmark, useful to debug, test or report
88438f7fc0SSiva Chandra Reddy // statistics.
89438f7fc0SSiva Chandra Reddy struct BenchmarkState {
90438f7fc0SSiva Chandra Reddy   size_t LastSampleIterations;
91438f7fc0SSiva Chandra Reddy   Duration LastBatchElapsed;
92438f7fc0SSiva Chandra Reddy   BenchmarkStatus CurrentStatus;
93438f7fc0SSiva Chandra Reddy   Duration CurrentBestGuess; // The time estimation for a single run of `foo`.
94438f7fc0SSiva Chandra Reddy   double ChangeRatio; // The change in time estimation between previous and
95438f7fc0SSiva Chandra Reddy                       // current samples.
96438f7fc0SSiva Chandra Reddy };
97438f7fc0SSiva Chandra Reddy 
98438f7fc0SSiva Chandra Reddy // A lightweight result for a benchmark.
99438f7fc0SSiva Chandra Reddy struct BenchmarkResult {
100438f7fc0SSiva Chandra Reddy   BenchmarkStatus TerminationStatus = BenchmarkStatus::Running;
101438f7fc0SSiva Chandra Reddy   Duration BestGuess = {};
102e1cdda57SKazu Hirata   std::optional<llvm::SmallVector<BenchmarkState, 16>> MaybeBenchmarkLog;
103438f7fc0SSiva Chandra Reddy };
104438f7fc0SSiva Chandra Reddy 
105438f7fc0SSiva Chandra Reddy // Stores information about a cache in the host memory system.
106438f7fc0SSiva Chandra Reddy struct CacheInfo {
107438f7fc0SSiva Chandra Reddy   std::string Type; //  e.g. "Instruction", "Data", "Unified".
108438f7fc0SSiva Chandra Reddy   int Level;        // 0 is closest to processing unit.
109438f7fc0SSiva Chandra Reddy   int Size;         // In bytes.
110438f7fc0SSiva Chandra Reddy   int NumSharing;   // The number of processing units (Hyper-Threading Thread)
111438f7fc0SSiva Chandra Reddy                     // with which this cache is shared.
112438f7fc0SSiva Chandra Reddy };
113438f7fc0SSiva Chandra Reddy 
114438f7fc0SSiva Chandra Reddy // Stores information about the host.
115438f7fc0SSiva Chandra Reddy struct HostState {
116438f7fc0SSiva Chandra Reddy   std::string CpuName; // returns a string compatible with the -march option.
117438f7fc0SSiva Chandra Reddy   double CpuFrequency; // in Hertz.
118438f7fc0SSiva Chandra Reddy   std::vector<CacheInfo> Caches;
119438f7fc0SSiva Chandra Reddy 
120438f7fc0SSiva Chandra Reddy   static HostState get();
121438f7fc0SSiva Chandra Reddy };
122438f7fc0SSiva Chandra Reddy 
123438f7fc0SSiva Chandra Reddy namespace internal {
124438f7fc0SSiva Chandra Reddy 
125438f7fc0SSiva Chandra Reddy struct Measurement {
126438f7fc0SSiva Chandra Reddy   size_t Iterations = 0;
127438f7fc0SSiva Chandra Reddy   Duration Elapsed = {};
128438f7fc0SSiva Chandra Reddy };
129438f7fc0SSiva Chandra Reddy 
130438f7fc0SSiva Chandra Reddy // Updates the estimation of the elapsed time for a single iteration.
131438f7fc0SSiva Chandra Reddy class RefinableRuntimeEstimation {
132438f7fc0SSiva Chandra Reddy   Duration TotalTime = {};
133438f7fc0SSiva Chandra Reddy   size_t TotalIterations = 0;
134438f7fc0SSiva Chandra Reddy 
135438f7fc0SSiva Chandra Reddy public:
136438f7fc0SSiva Chandra Reddy   Duration update(const Measurement &M) {
137438f7fc0SSiva Chandra Reddy     assert(M.Iterations > 0);
138438f7fc0SSiva Chandra Reddy     // Duration is encoded as a double (see definition).
139438f7fc0SSiva Chandra Reddy     // `TotalTime` and `M.Elapsed` are of the same magnitude so we don't expect
140438f7fc0SSiva Chandra Reddy     // loss of precision due to radically different scales.
141438f7fc0SSiva Chandra Reddy     TotalTime += M.Elapsed;
142438f7fc0SSiva Chandra Reddy     TotalIterations += M.Iterations;
143438f7fc0SSiva Chandra Reddy     return TotalTime / TotalIterations;
144438f7fc0SSiva Chandra Reddy   }
145438f7fc0SSiva Chandra Reddy };
146438f7fc0SSiva Chandra Reddy 
147438f7fc0SSiva Chandra Reddy // This class tracks the progression of the runtime estimation.
148438f7fc0SSiva Chandra Reddy class RuntimeEstimationProgression {
149438f7fc0SSiva Chandra Reddy   RefinableRuntimeEstimation RRE;
150438f7fc0SSiva Chandra Reddy 
151438f7fc0SSiva Chandra Reddy public:
152438f7fc0SSiva Chandra Reddy   Duration CurrentEstimation = {};
153438f7fc0SSiva Chandra Reddy 
154438f7fc0SSiva Chandra Reddy   // Returns the change ratio between our best guess so far and the one from the
155438f7fc0SSiva Chandra Reddy   // new measurement.
156438f7fc0SSiva Chandra Reddy   double computeImprovement(const Measurement &M) {
157438f7fc0SSiva Chandra Reddy     const Duration NewEstimation = RRE.update(M);
158438f7fc0SSiva Chandra Reddy     const double Ratio = fabs(((CurrentEstimation / NewEstimation) - 1.0));
159438f7fc0SSiva Chandra Reddy     CurrentEstimation = NewEstimation;
160438f7fc0SSiva Chandra Reddy     return Ratio;
161438f7fc0SSiva Chandra Reddy   }
162438f7fc0SSiva Chandra Reddy };
163438f7fc0SSiva Chandra Reddy 
164438f7fc0SSiva Chandra Reddy } // namespace internal
165438f7fc0SSiva Chandra Reddy 
166438f7fc0SSiva Chandra Reddy // Measures the runtime of `foo` until conditions defined by `Options` are met.
167438f7fc0SSiva Chandra Reddy //
168438f7fc0SSiva Chandra Reddy // To avoid measurement's imprecisions we measure batches of `foo`.
169438f7fc0SSiva Chandra Reddy // The batch size is growing by `ScalingFactor` to minimize the effect of
170438f7fc0SSiva Chandra Reddy // measuring.
171438f7fc0SSiva Chandra Reddy //
172438f7fc0SSiva Chandra Reddy // Note: The benchmark is not responsible for serializing the executions of
173438f7fc0SSiva Chandra Reddy // `foo`. It is not suitable for measuring, very small & side effect free
174438f7fc0SSiva Chandra Reddy // functions, as the processor is free to execute several executions in
175438f7fc0SSiva Chandra Reddy // parallel.
176438f7fc0SSiva Chandra Reddy //
177438f7fc0SSiva Chandra Reddy // - Options: A set of parameters controlling the stopping conditions for the
178438f7fc0SSiva Chandra Reddy //     benchmark.
179438f7fc0SSiva Chandra Reddy // - foo: The function under test. It takes one value and returns one value.
180438f7fc0SSiva Chandra Reddy //     The input value is used to randomize the execution of `foo` as part of a
181438f7fc0SSiva Chandra Reddy //     batch to mitigate the effect of the branch predictor. Signature:
182438f7fc0SSiva Chandra Reddy //     `ProductType foo(ParameterProvider::value_type value);`
183438f7fc0SSiva Chandra Reddy //     The output value is a product of the execution of `foo` and prevents the
184438f7fc0SSiva Chandra Reddy //     compiler from optimizing out foo's body.
185438f7fc0SSiva Chandra Reddy // - ParameterProvider: An object responsible for providing a range of
186438f7fc0SSiva Chandra Reddy //     `Iterations` values to use as input for `foo`. The `value_type` of the
187438f7fc0SSiva Chandra Reddy //     returned container has to be compatible with `foo` argument.
188438f7fc0SSiva Chandra Reddy //     Must implement one of:
189438f7fc0SSiva Chandra Reddy //     `Container<ParameterType> generateBatch(size_t Iterations);`
190438f7fc0SSiva Chandra Reddy //     `const Container<ParameterType>& generateBatch(size_t Iterations);`
191438f7fc0SSiva Chandra Reddy // - Clock: An object providing the current time. Must implement:
192438f7fc0SSiva Chandra Reddy //     `std::chrono::time_point now();`
193438f7fc0SSiva Chandra Reddy template <typename Function, typename ParameterProvider,
194438f7fc0SSiva Chandra Reddy           typename BenchmarkClock = const std::chrono::high_resolution_clock>
195438f7fc0SSiva Chandra Reddy BenchmarkResult benchmark(const BenchmarkOptions &Options,
196438f7fc0SSiva Chandra Reddy                           ParameterProvider &PP, Function foo,
197438f7fc0SSiva Chandra Reddy                           BenchmarkClock &Clock = BenchmarkClock()) {
198438f7fc0SSiva Chandra Reddy   BenchmarkResult Result;
199438f7fc0SSiva Chandra Reddy   internal::RuntimeEstimationProgression REP;
200438f7fc0SSiva Chandra Reddy   Duration TotalBenchmarkDuration = {};
201438f7fc0SSiva Chandra Reddy   size_t Iterations = std::max(Options.InitialIterations, uint32_t(1));
202438f7fc0SSiva Chandra Reddy   size_t Samples = 0;
203438f7fc0SSiva Chandra Reddy   if (Options.ScalingFactor < 1.0)
204438f7fc0SSiva Chandra Reddy     report_fatal_error("ScalingFactor should be >= 1");
205438f7fc0SSiva Chandra Reddy   if (Options.Log != BenchmarkLog::None)
206438f7fc0SSiva Chandra Reddy     Result.MaybeBenchmarkLog.emplace();
207438f7fc0SSiva Chandra Reddy   for (;;) {
208438f7fc0SSiva Chandra Reddy     // Request a new Batch of size `Iterations`.
209438f7fc0SSiva Chandra Reddy     const auto &Batch = PP.generateBatch(Iterations);
210438f7fc0SSiva Chandra Reddy 
211438f7fc0SSiva Chandra Reddy     // Measuring this Batch.
212438f7fc0SSiva Chandra Reddy     const auto StartTime = Clock.now();
213438f7fc0SSiva Chandra Reddy     for (const auto Parameter : Batch) {
214*081a80f2SDavid Peixotto       auto Production = foo(Parameter);
215438f7fc0SSiva Chandra Reddy       benchmark::DoNotOptimize(Production);
216438f7fc0SSiva Chandra Reddy     }
217438f7fc0SSiva Chandra Reddy     const auto EndTime = Clock.now();
218438f7fc0SSiva Chandra Reddy     const Duration Elapsed = EndTime - StartTime;
219438f7fc0SSiva Chandra Reddy 
220438f7fc0SSiva Chandra Reddy     // Updating statistics.
221438f7fc0SSiva Chandra Reddy     ++Samples;
222438f7fc0SSiva Chandra Reddy     TotalBenchmarkDuration += Elapsed;
223438f7fc0SSiva Chandra Reddy     const double ChangeRatio = REP.computeImprovement({Iterations, Elapsed});
224438f7fc0SSiva Chandra Reddy     Result.BestGuess = REP.CurrentEstimation;
225438f7fc0SSiva Chandra Reddy 
226438f7fc0SSiva Chandra Reddy     // Stopping condition.
227438f7fc0SSiva Chandra Reddy     if (TotalBenchmarkDuration >= Options.MinDuration &&
228438f7fc0SSiva Chandra Reddy         Samples >= Options.MinSamples && ChangeRatio < Options.Epsilon)
229438f7fc0SSiva Chandra Reddy       Result.TerminationStatus = BenchmarkStatus::PrecisionReached;
230438f7fc0SSiva Chandra Reddy     else if (Samples >= Options.MaxSamples)
231438f7fc0SSiva Chandra Reddy       Result.TerminationStatus = BenchmarkStatus::MaxSamplesReached;
232438f7fc0SSiva Chandra Reddy     else if (TotalBenchmarkDuration >= Options.MaxDuration)
233438f7fc0SSiva Chandra Reddy       Result.TerminationStatus = BenchmarkStatus::MaxDurationReached;
234438f7fc0SSiva Chandra Reddy     else if (Iterations >= Options.MaxIterations)
235438f7fc0SSiva Chandra Reddy       Result.TerminationStatus = BenchmarkStatus::MaxIterationsReached;
236438f7fc0SSiva Chandra Reddy 
237438f7fc0SSiva Chandra Reddy     if (Result.MaybeBenchmarkLog) {
238438f7fc0SSiva Chandra Reddy       auto &BenchmarkLog = *Result.MaybeBenchmarkLog;
239438f7fc0SSiva Chandra Reddy       if (Options.Log == BenchmarkLog::Last && !BenchmarkLog.empty())
240438f7fc0SSiva Chandra Reddy         BenchmarkLog.pop_back();
241438f7fc0SSiva Chandra Reddy       BenchmarkState BS;
242438f7fc0SSiva Chandra Reddy       BS.LastSampleIterations = Iterations;
243438f7fc0SSiva Chandra Reddy       BS.LastBatchElapsed = Elapsed;
244438f7fc0SSiva Chandra Reddy       BS.CurrentStatus = Result.TerminationStatus;
245438f7fc0SSiva Chandra Reddy       BS.CurrentBestGuess = Result.BestGuess;
246438f7fc0SSiva Chandra Reddy       BS.ChangeRatio = ChangeRatio;
247438f7fc0SSiva Chandra Reddy       BenchmarkLog.push_back(BS);
248438f7fc0SSiva Chandra Reddy     }
249438f7fc0SSiva Chandra Reddy 
250438f7fc0SSiva Chandra Reddy     if (Result.TerminationStatus != BenchmarkStatus::Running)
251438f7fc0SSiva Chandra Reddy       return Result;
252438f7fc0SSiva Chandra Reddy 
253438f7fc0SSiva Chandra Reddy     if (Options.ScalingFactor > 1 &&
254438f7fc0SSiva Chandra Reddy         Iterations * Options.ScalingFactor == Iterations)
255438f7fc0SSiva Chandra Reddy       report_fatal_error(
256438f7fc0SSiva Chandra Reddy           "`Iterations *= ScalingFactor` is idempotent, increase ScalingFactor "
257438f7fc0SSiva Chandra Reddy           "or InitialIterations.");
258438f7fc0SSiva Chandra Reddy 
259438f7fc0SSiva Chandra Reddy     Iterations *= Options.ScalingFactor;
260438f7fc0SSiva Chandra Reddy   }
261438f7fc0SSiva Chandra Reddy }
262438f7fc0SSiva Chandra Reddy 
263438f7fc0SSiva Chandra Reddy // Interprets `Array` as a circular buffer of `Size` elements.
264438f7fc0SSiva Chandra Reddy template <typename T> class CircularArrayRef {
265438f7fc0SSiva Chandra Reddy   llvm::ArrayRef<T> Array;
266438f7fc0SSiva Chandra Reddy   size_t Size;
267438f7fc0SSiva Chandra Reddy 
268438f7fc0SSiva Chandra Reddy public:
269438f7fc0SSiva Chandra Reddy   using value_type = T;
270438f7fc0SSiva Chandra Reddy   using reference = T &;
271438f7fc0SSiva Chandra Reddy   using const_reference = const T &;
272438f7fc0SSiva Chandra Reddy   using difference_type = ssize_t;
273438f7fc0SSiva Chandra Reddy   using size_type = size_t;
274438f7fc0SSiva Chandra Reddy 
27512c62a67SSchrodinger ZHU Yifan   class const_iterator {
27612c62a67SSchrodinger ZHU Yifan     using iterator_category = std::input_iterator_tag;
277438f7fc0SSiva Chandra Reddy     llvm::ArrayRef<T> Array;
278438f7fc0SSiva Chandra Reddy     size_t Index;
279223a6f94SGuillaume Chatelet     size_t Offset;
280438f7fc0SSiva Chandra Reddy 
281438f7fc0SSiva Chandra Reddy   public:
282438f7fc0SSiva Chandra Reddy     explicit const_iterator(llvm::ArrayRef<T> Array, size_t Index = 0)
283223a6f94SGuillaume Chatelet         : Array(Array), Index(Index), Offset(Index % Array.size()) {}
284438f7fc0SSiva Chandra Reddy     const_iterator &operator++() {
285438f7fc0SSiva Chandra Reddy       ++Index;
286223a6f94SGuillaume Chatelet       ++Offset;
287223a6f94SGuillaume Chatelet       if (Offset == Array.size())
288223a6f94SGuillaume Chatelet         Offset = 0;
289438f7fc0SSiva Chandra Reddy       return *this;
290438f7fc0SSiva Chandra Reddy     }
291438f7fc0SSiva Chandra Reddy     bool operator==(const_iterator Other) const { return Index == Other.Index; }
292438f7fc0SSiva Chandra Reddy     bool operator!=(const_iterator Other) const { return !(*this == Other); }
293223a6f94SGuillaume Chatelet     const T &operator*() const { return Array[Offset]; }
294438f7fc0SSiva Chandra Reddy   };
295438f7fc0SSiva Chandra Reddy 
296438f7fc0SSiva Chandra Reddy   CircularArrayRef(llvm::ArrayRef<T> Array, size_t Size)
297438f7fc0SSiva Chandra Reddy       : Array(Array), Size(Size) {
298438f7fc0SSiva Chandra Reddy     assert(Array.size() > 0);
299438f7fc0SSiva Chandra Reddy   }
300438f7fc0SSiva Chandra Reddy 
301438f7fc0SSiva Chandra Reddy   const_iterator begin() const { return const_iterator(Array); }
302438f7fc0SSiva Chandra Reddy   const_iterator end() const { return const_iterator(Array, Size); }
303438f7fc0SSiva Chandra Reddy };
304438f7fc0SSiva Chandra Reddy 
305438f7fc0SSiva Chandra Reddy // A convenient helper to produce a CircularArrayRef from an ArrayRef.
306438f7fc0SSiva Chandra Reddy template <typename T>
307438f7fc0SSiva Chandra Reddy CircularArrayRef<T> cycle(llvm::ArrayRef<T> Array, size_t Size) {
308438f7fc0SSiva Chandra Reddy   return {Array, Size};
309438f7fc0SSiva Chandra Reddy }
310438f7fc0SSiva Chandra Reddy 
311438f7fc0SSiva Chandra Reddy // Creates an std::array which storage size is constrained under `Bytes`.
312438f7fc0SSiva Chandra Reddy template <typename T, size_t Bytes>
313438f7fc0SSiva Chandra Reddy using ByteConstrainedArray = std::array<T, Bytes / sizeof(T)>;
314438f7fc0SSiva Chandra Reddy 
315438f7fc0SSiva Chandra Reddy // A convenient helper to produce a CircularArrayRef from a
316438f7fc0SSiva Chandra Reddy // ByteConstrainedArray.
317438f7fc0SSiva Chandra Reddy template <typename T, size_t N>
318438f7fc0SSiva Chandra Reddy CircularArrayRef<T> cycle(const std::array<T, N> &Container, size_t Size) {
319438f7fc0SSiva Chandra Reddy   return {llvm::ArrayRef<T>(Container.cbegin(), Container.cend()), Size};
320438f7fc0SSiva Chandra Reddy }
321438f7fc0SSiva Chandra Reddy 
322deae7e98SGuillaume Chatelet // Makes sure the binary was compiled in release mode and that frequency
323deae7e98SGuillaume Chatelet // governor is set on performance.
324deae7e98SGuillaume Chatelet void checkRequirements();
325deae7e98SGuillaume Chatelet 
326438f7fc0SSiva Chandra Reddy } // namespace libc_benchmarks
327438f7fc0SSiva Chandra Reddy } // namespace llvm
328438f7fc0SSiva Chandra Reddy 
329438f7fc0SSiva Chandra Reddy #endif // LLVM_LIBC_UTILS_BENCHMARK_BENCHMARK_H
330