1438f7fc0SSiva Chandra Reddy //===-- Benchmark ---------------------------------------------------------===//
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 #include "JSON.h"
10438f7fc0SSiva Chandra Reddy #include "LibcBenchmark.h"
11438f7fc0SSiva Chandra Reddy #include "LibcMemoryBenchmark.h"
12deae7e98SGuillaume Chatelet #include "MemorySizeDistributions.h"
13438f7fc0SSiva Chandra Reddy #include "llvm/Support/CommandLine.h"
14438f7fc0SSiva Chandra Reddy #include "llvm/Support/ErrorHandling.h"
15438f7fc0SSiva Chandra Reddy #include "llvm/Support/FileSystem.h"
16438f7fc0SSiva Chandra Reddy #include "llvm/Support/JSON.h"
17438f7fc0SSiva Chandra Reddy #include "llvm/Support/MemoryBuffer.h"
18438f7fc0SSiva Chandra Reddy #include "llvm/Support/raw_ostream.h"
19438f7fc0SSiva Chandra Reddy 
20deae7e98SGuillaume Chatelet namespace __llvm_libc {
21deae7e98SGuillaume Chatelet 
22deae7e98SGuillaume Chatelet extern void *memcpy(void *__restrict, const void *__restrict, size_t);
23deae7e98SGuillaume Chatelet extern void *memset(void *, int, size_t);
24deae7e98SGuillaume Chatelet 
25deae7e98SGuillaume Chatelet } // namespace __llvm_libc
26438f7fc0SSiva Chandra Reddy 
27438f7fc0SSiva Chandra Reddy namespace llvm {
28438f7fc0SSiva Chandra Reddy namespace libc_benchmarks {
29438f7fc0SSiva Chandra Reddy 
30deae7e98SGuillaume Chatelet static cl::opt<std::string>
31deae7e98SGuillaume Chatelet     StudyName("study-name", cl::desc("The name for this study"), cl::Required);
32deae7e98SGuillaume Chatelet 
33deae7e98SGuillaume Chatelet static cl::opt<std::string>
34deae7e98SGuillaume Chatelet     SizeDistributionName("size-distribution-name",
35deae7e98SGuillaume Chatelet                          cl::desc("The name of the distribution to use"));
36deae7e98SGuillaume Chatelet 
37deae7e98SGuillaume Chatelet static cl::opt<bool>
38deae7e98SGuillaume Chatelet     SweepMode("sweep-mode",
39deae7e98SGuillaume Chatelet               cl::desc("If set, benchmark all sizes from 0 to sweep-max-size"));
40deae7e98SGuillaume Chatelet 
41deae7e98SGuillaume Chatelet static cl::opt<uint32_t>
42deae7e98SGuillaume Chatelet     SweepMaxSize("sweep-max-size",
43deae7e98SGuillaume Chatelet                  cl::desc("The maximum size to use in sweep-mode"),
44deae7e98SGuillaume Chatelet                  cl::init(256));
45deae7e98SGuillaume Chatelet 
46deae7e98SGuillaume Chatelet static cl::opt<uint32_t>
47deae7e98SGuillaume Chatelet     AlignedAccess("aligned-access",
48deae7e98SGuillaume Chatelet                   cl::desc("The alignment to use when accessing the buffers\n"
49deae7e98SGuillaume Chatelet                            "Default is unaligned\n"
50deae7e98SGuillaume Chatelet                            "Use 0 to disable address randomization"),
51deae7e98SGuillaume Chatelet                   cl::init(1));
52deae7e98SGuillaume Chatelet 
53deae7e98SGuillaume Chatelet static cl::opt<std::string> Output("output",
54deae7e98SGuillaume Chatelet                                    cl::desc("Specify output filename"),
55438f7fc0SSiva Chandra Reddy                                    cl::value_desc("filename"), cl::init("-"));
56438f7fc0SSiva Chandra Reddy 
57deae7e98SGuillaume Chatelet static cl::opt<uint32_t>
58deae7e98SGuillaume Chatelet     NumTrials("num-trials", cl::desc("The number of benchmarks run to perform"),
59deae7e98SGuillaume Chatelet               cl::init(1));
60438f7fc0SSiva Chandra Reddy 
61deae7e98SGuillaume Chatelet static constexpr int64_t KiB = 1024;
62deae7e98SGuillaume Chatelet static constexpr int64_t ParameterStorageBytes = 4 * KiB;
63deae7e98SGuillaume Chatelet static constexpr int64_t L1LeftAsideBytes = 1 * KiB;
64438f7fc0SSiva Chandra Reddy 
65deae7e98SGuillaume Chatelet struct ParameterType {
66deae7e98SGuillaume Chatelet   unsigned OffsetBytes : 16; // max : 16 KiB - 1
67deae7e98SGuillaume Chatelet   unsigned SizeBytes : 16;   // max : 16 KiB - 1
68deae7e98SGuillaume Chatelet };
69438f7fc0SSiva Chandra Reddy 
70*8d64ed85SGuillaume Chatelet #if defined(LIBC_BENCHMARK_FUNCTION_MEMCPY)
71*8d64ed85SGuillaume Chatelet struct Benchmark {
72deae7e98SGuillaume Chatelet   static constexpr auto GetDistributions = &getMemcpySizeDistributions;
73deae7e98SGuillaume Chatelet   static constexpr size_t BufferCount = 2;
74438f7fc0SSiva Chandra Reddy 
75*8d64ed85SGuillaume Chatelet   Benchmark(const size_t BufferSize)
76deae7e98SGuillaume Chatelet       : SrcBuffer(BufferSize), DstBuffer(BufferSize) {}
77deae7e98SGuillaume Chatelet 
78deae7e98SGuillaume Chatelet   inline auto functor() {
79deae7e98SGuillaume Chatelet     return [this](ParameterType P) {
80deae7e98SGuillaume Chatelet       __llvm_libc::memcpy(DstBuffer + P.OffsetBytes, SrcBuffer + P.OffsetBytes,
81deae7e98SGuillaume Chatelet                           P.SizeBytes);
82deae7e98SGuillaume Chatelet       return DstBuffer + P.OffsetBytes;
83deae7e98SGuillaume Chatelet     };
84438f7fc0SSiva Chandra Reddy   }
85438f7fc0SSiva Chandra Reddy 
86deae7e98SGuillaume Chatelet   AlignedBuffer SrcBuffer;
87deae7e98SGuillaume Chatelet   AlignedBuffer DstBuffer;
88deae7e98SGuillaume Chatelet };
89*8d64ed85SGuillaume Chatelet #elif defined(LIBC_BENCHMARK_FUNCTION_MEMSET)
90*8d64ed85SGuillaume Chatelet struct Benchmark {
91deae7e98SGuillaume Chatelet   static constexpr auto GetDistributions = &getMemsetSizeDistributions;
92deae7e98SGuillaume Chatelet   static constexpr size_t BufferCount = 1;
93deae7e98SGuillaume Chatelet 
94*8d64ed85SGuillaume Chatelet   Benchmark(const size_t BufferSize) : DstBuffer(BufferSize) {}
95deae7e98SGuillaume Chatelet 
96deae7e98SGuillaume Chatelet   inline auto functor() {
97deae7e98SGuillaume Chatelet     return [this](ParameterType P) {
98deae7e98SGuillaume Chatelet       __llvm_libc::memset(DstBuffer + P.OffsetBytes, P.OffsetBytes & 0xFF,
99deae7e98SGuillaume Chatelet                           P.SizeBytes);
100deae7e98SGuillaume Chatelet       return DstBuffer + P.OffsetBytes;
101deae7e98SGuillaume Chatelet     };
102deae7e98SGuillaume Chatelet   }
103deae7e98SGuillaume Chatelet 
104deae7e98SGuillaume Chatelet   AlignedBuffer DstBuffer;
105deae7e98SGuillaume Chatelet };
106*8d64ed85SGuillaume Chatelet #else
107*8d64ed85SGuillaume Chatelet #error "Missing LIBC_BENCHMARK_FUNCTION_XXX definition"
108*8d64ed85SGuillaume Chatelet #endif
109deae7e98SGuillaume Chatelet 
110*8d64ed85SGuillaume Chatelet struct Harness : Benchmark {
111deae7e98SGuillaume Chatelet 
112deae7e98SGuillaume Chatelet   Harness(const size_t BufferSize, size_t BatchParameterCount,
113deae7e98SGuillaume Chatelet           std::function<unsigned()> SizeSampler,
114deae7e98SGuillaume Chatelet           std::function<unsigned()> OffsetSampler)
115deae7e98SGuillaume Chatelet       : Benchmark(BufferSize), BufferSize(BufferSize),
116deae7e98SGuillaume Chatelet         Parameters(BatchParameterCount), SizeSampler(SizeSampler),
117deae7e98SGuillaume Chatelet         OffsetSampler(OffsetSampler) {}
118deae7e98SGuillaume Chatelet 
119deae7e98SGuillaume Chatelet   CircularArrayRef<ParameterType> generateBatch(size_t Iterations) {
120deae7e98SGuillaume Chatelet     for (auto &P : Parameters) {
121deae7e98SGuillaume Chatelet       P.OffsetBytes = OffsetSampler();
122deae7e98SGuillaume Chatelet       P.SizeBytes = SizeSampler();
123deae7e98SGuillaume Chatelet       if (P.OffsetBytes + P.SizeBytes >= BufferSize)
124deae7e98SGuillaume Chatelet         report_fatal_error("Call would result in buffer overflow");
125deae7e98SGuillaume Chatelet     }
126deae7e98SGuillaume Chatelet     return cycle(makeArrayRef(Parameters), Iterations);
127deae7e98SGuillaume Chatelet   }
128deae7e98SGuillaume Chatelet 
129deae7e98SGuillaume Chatelet private:
130deae7e98SGuillaume Chatelet   const size_t BufferSize;
131deae7e98SGuillaume Chatelet   std::vector<ParameterType> Parameters;
132deae7e98SGuillaume Chatelet   std::function<unsigned()> SizeSampler;
133deae7e98SGuillaume Chatelet   std::function<unsigned()> OffsetSampler;
134deae7e98SGuillaume Chatelet };
135deae7e98SGuillaume Chatelet 
136deae7e98SGuillaume Chatelet size_t getL1DataCacheSize() {
137deae7e98SGuillaume Chatelet   const std::vector<CacheInfo> &CacheInfos = HostState::get().Caches;
138deae7e98SGuillaume Chatelet   const auto IsL1DataCache = [](const CacheInfo &CI) {
139deae7e98SGuillaume Chatelet     return CI.Type == "Data" && CI.Level == 1;
140deae7e98SGuillaume Chatelet   };
141deae7e98SGuillaume Chatelet   const auto CacheIt = find_if(CacheInfos, IsL1DataCache);
142deae7e98SGuillaume Chatelet   if (CacheIt != CacheInfos.end())
143deae7e98SGuillaume Chatelet     return CacheIt->Size;
144deae7e98SGuillaume Chatelet   report_fatal_error("Unable to read L1 Cache Data Size");
145deae7e98SGuillaume Chatelet }
146deae7e98SGuillaume Chatelet 
147*8d64ed85SGuillaume Chatelet struct MemfunctionBenchmark {
148deae7e98SGuillaume Chatelet   MemfunctionBenchmark(int64_t L1Size = getL1DataCacheSize())
149deae7e98SGuillaume Chatelet       : AvailableSize(L1Size - L1LeftAsideBytes - ParameterStorageBytes),
150deae7e98SGuillaume Chatelet         BufferSize(AvailableSize / Benchmark::BufferCount),
151deae7e98SGuillaume Chatelet         BatchParameterCount(BufferSize / sizeof(ParameterType)) {
152deae7e98SGuillaume Chatelet     // Handling command line flags
153deae7e98SGuillaume Chatelet     if (AvailableSize <= 0 || BufferSize <= 0 || BatchParameterCount < 100)
154deae7e98SGuillaume Chatelet       report_fatal_error("Not enough L1 cache");
155deae7e98SGuillaume Chatelet 
156deae7e98SGuillaume Chatelet     if (!isPowerOfTwoOrZero(AlignedAccess))
157deae7e98SGuillaume Chatelet       report_fatal_error(AlignedAccess.ArgStr +
158deae7e98SGuillaume Chatelet                          Twine(" must be a power of two or zero"));
159deae7e98SGuillaume Chatelet 
160deae7e98SGuillaume Chatelet     const bool HasDistributionName = !SizeDistributionName.empty();
161deae7e98SGuillaume Chatelet     if (SweepMode && HasDistributionName)
162deae7e98SGuillaume Chatelet       report_fatal_error("Select only one of `--" + Twine(SweepMode.ArgStr) +
163deae7e98SGuillaume Chatelet                          "` or `--" + Twine(SizeDistributionName.ArgStr) + "`");
164deae7e98SGuillaume Chatelet 
165deae7e98SGuillaume Chatelet     if (SweepMode) {
166deae7e98SGuillaume Chatelet       MaxSizeValue = SweepMaxSize;
167deae7e98SGuillaume Chatelet     } else {
168deae7e98SGuillaume Chatelet       std::map<StringRef, MemorySizeDistribution> Map;
169deae7e98SGuillaume Chatelet       for (MemorySizeDistribution Distribution : Benchmark::GetDistributions())
170deae7e98SGuillaume Chatelet         Map[Distribution.Name] = Distribution;
171deae7e98SGuillaume Chatelet       if (Map.count(SizeDistributionName) == 0) {
172deae7e98SGuillaume Chatelet         std::string Message;
173deae7e98SGuillaume Chatelet         raw_string_ostream Stream(Message);
174deae7e98SGuillaume Chatelet         Stream << "Unknown --" << SizeDistributionName.ArgStr << "='"
175deae7e98SGuillaume Chatelet                << SizeDistributionName << "', available distributions:\n";
176deae7e98SGuillaume Chatelet         for (const auto &Pair : Map)
177deae7e98SGuillaume Chatelet           Stream << "'" << Pair.first << "'\n";
178deae7e98SGuillaume Chatelet         report_fatal_error(Stream.str());
179deae7e98SGuillaume Chatelet       }
180deae7e98SGuillaume Chatelet       SizeDistribution = Map[SizeDistributionName];
181deae7e98SGuillaume Chatelet       MaxSizeValue = SizeDistribution.Probabilities.size() - 1;
182deae7e98SGuillaume Chatelet     }
183deae7e98SGuillaume Chatelet 
184deae7e98SGuillaume Chatelet     // Setup study.
185deae7e98SGuillaume Chatelet     Study.StudyName = StudyName;
186deae7e98SGuillaume Chatelet     Runtime &RI = Study.Runtime;
187deae7e98SGuillaume Chatelet     RI.Host = HostState::get();
188deae7e98SGuillaume Chatelet     RI.BufferSize = BufferSize;
189deae7e98SGuillaume Chatelet     RI.BatchParameterCount = BatchParameterCount;
190deae7e98SGuillaume Chatelet 
191deae7e98SGuillaume Chatelet     BenchmarkOptions &BO = RI.BenchmarkOptions;
192deae7e98SGuillaume Chatelet     BO.MinDuration = std::chrono::milliseconds(1);
193deae7e98SGuillaume Chatelet     BO.MaxDuration = std::chrono::seconds(1);
194deae7e98SGuillaume Chatelet     BO.MaxIterations = 10'000'000U;
195deae7e98SGuillaume Chatelet     BO.MinSamples = 4;
196deae7e98SGuillaume Chatelet     BO.MaxSamples = 1000;
197deae7e98SGuillaume Chatelet     BO.Epsilon = 0.01; // 1%
198deae7e98SGuillaume Chatelet     BO.ScalingFactor = 1.4;
199deae7e98SGuillaume Chatelet 
200deae7e98SGuillaume Chatelet     StudyConfiguration &SC = Study.Configuration;
201deae7e98SGuillaume Chatelet     SC.NumTrials = NumTrials;
202deae7e98SGuillaume Chatelet     SC.IsSweepMode = SweepMode;
203deae7e98SGuillaume Chatelet     if (SweepMode)
204deae7e98SGuillaume Chatelet       SC.SweepModeMaxSize = SweepMaxSize;
205deae7e98SGuillaume Chatelet     else
206deae7e98SGuillaume Chatelet       SC.SizeDistributionName = SizeDistributionName;
207deae7e98SGuillaume Chatelet     SC.AccessAlignment = MaybeAlign(AlignedAccess);
208*8d64ed85SGuillaume Chatelet     SC.Function = LIBC_BENCHMARK_FUNCTION_NAME;
209deae7e98SGuillaume Chatelet   }
210deae7e98SGuillaume Chatelet 
211*8d64ed85SGuillaume Chatelet   Study run() {
212deae7e98SGuillaume Chatelet     if (SweepMode)
213deae7e98SGuillaume Chatelet       runSweepMode();
214deae7e98SGuillaume Chatelet     else
215deae7e98SGuillaume Chatelet       runDistributionMode();
216deae7e98SGuillaume Chatelet     return Study;
217deae7e98SGuillaume Chatelet   }
218deae7e98SGuillaume Chatelet 
219deae7e98SGuillaume Chatelet private:
220deae7e98SGuillaume Chatelet   const int64_t AvailableSize;
221deae7e98SGuillaume Chatelet   const int64_t BufferSize;
222deae7e98SGuillaume Chatelet   const size_t BatchParameterCount;
223deae7e98SGuillaume Chatelet   size_t MaxSizeValue = 0;
224deae7e98SGuillaume Chatelet   MemorySizeDistribution SizeDistribution;
225deae7e98SGuillaume Chatelet   Study Study;
226deae7e98SGuillaume Chatelet   std::mt19937_64 Gen;
227deae7e98SGuillaume Chatelet 
228deae7e98SGuillaume Chatelet   static constexpr bool isPowerOfTwoOrZero(size_t Value) {
229deae7e98SGuillaume Chatelet     return (Value & (Value - 1U)) == 0;
230deae7e98SGuillaume Chatelet   }
231deae7e98SGuillaume Chatelet 
232deae7e98SGuillaume Chatelet   std::function<unsigned()> geOffsetSampler() {
233deae7e98SGuillaume Chatelet     return [this]() {
234deae7e98SGuillaume Chatelet       static OffsetDistribution OD(BufferSize, MaxSizeValue,
235deae7e98SGuillaume Chatelet                                    Study.Configuration.AccessAlignment);
236deae7e98SGuillaume Chatelet       return OD(Gen);
237deae7e98SGuillaume Chatelet     };
238deae7e98SGuillaume Chatelet   }
239deae7e98SGuillaume Chatelet 
240deae7e98SGuillaume Chatelet   std::function<unsigned()> getSizeSampler() {
241deae7e98SGuillaume Chatelet     return [this]() {
242deae7e98SGuillaume Chatelet       static std::discrete_distribution<unsigned> Distribution(
243deae7e98SGuillaume Chatelet           SizeDistribution.Probabilities.begin(),
244deae7e98SGuillaume Chatelet           SizeDistribution.Probabilities.end());
245deae7e98SGuillaume Chatelet       return Distribution(Gen);
246deae7e98SGuillaume Chatelet     };
247deae7e98SGuillaume Chatelet   }
248deae7e98SGuillaume Chatelet 
249ab577807SGuillaume Chatelet   void reportProgress() {
250ab577807SGuillaume Chatelet     static size_t LastPercent = -1;
251deae7e98SGuillaume Chatelet     const size_t TotalSteps = Study.Measurements.capacity();
252deae7e98SGuillaume Chatelet     const size_t Steps = Study.Measurements.size();
253deae7e98SGuillaume Chatelet     const size_t Percent = 100 * Steps / TotalSteps;
254ab577807SGuillaume Chatelet     if (Percent == LastPercent)
255ab577807SGuillaume Chatelet       return;
256ab577807SGuillaume Chatelet     LastPercent = Percent;
257deae7e98SGuillaume Chatelet     size_t I = 0;
258deae7e98SGuillaume Chatelet     errs() << '[';
259deae7e98SGuillaume Chatelet     for (; I <= Percent; ++I)
260deae7e98SGuillaume Chatelet       errs() << '#';
261deae7e98SGuillaume Chatelet     for (; I <= 100; ++I)
262deae7e98SGuillaume Chatelet       errs() << '_';
263ab577807SGuillaume Chatelet     errs() << "] " << Percent << '%' << '\r';
264deae7e98SGuillaume Chatelet   }
265deae7e98SGuillaume Chatelet 
266deae7e98SGuillaume Chatelet   void runTrials(const BenchmarkOptions &Options,
267deae7e98SGuillaume Chatelet                  std::function<unsigned()> SizeSampler,
268deae7e98SGuillaume Chatelet                  std::function<unsigned()> OffsetSampler) {
269*8d64ed85SGuillaume Chatelet     Harness B(BufferSize, BatchParameterCount, SizeSampler, OffsetSampler);
270deae7e98SGuillaume Chatelet     for (size_t i = 0; i < NumTrials; ++i) {
271deae7e98SGuillaume Chatelet       const BenchmarkResult Result = benchmark(Options, B, B.functor());
272deae7e98SGuillaume Chatelet       Study.Measurements.push_back(Result.BestGuess);
273ab577807SGuillaume Chatelet       reportProgress();
274deae7e98SGuillaume Chatelet     }
275deae7e98SGuillaume Chatelet   }
276deae7e98SGuillaume Chatelet 
277deae7e98SGuillaume Chatelet   void runSweepMode() {
278deae7e98SGuillaume Chatelet     Study.Measurements.reserve(NumTrials * SweepMaxSize);
279deae7e98SGuillaume Chatelet 
280deae7e98SGuillaume Chatelet     BenchmarkOptions &BO = Study.Runtime.BenchmarkOptions;
281deae7e98SGuillaume Chatelet     BO.MinDuration = std::chrono::milliseconds(1);
282deae7e98SGuillaume Chatelet     BO.InitialIterations = 100;
283deae7e98SGuillaume Chatelet 
284deae7e98SGuillaume Chatelet     for (size_t Size = 0; Size <= SweepMaxSize; ++Size) {
285deae7e98SGuillaume Chatelet       const auto SizeSampler = [Size]() { return Size; };
286deae7e98SGuillaume Chatelet       runTrials(BO, SizeSampler, geOffsetSampler());
287deae7e98SGuillaume Chatelet     }
288deae7e98SGuillaume Chatelet   }
289deae7e98SGuillaume Chatelet 
290deae7e98SGuillaume Chatelet   void runDistributionMode() {
291deae7e98SGuillaume Chatelet     Study.Measurements.reserve(NumTrials);
292deae7e98SGuillaume Chatelet 
293deae7e98SGuillaume Chatelet     BenchmarkOptions &BO = Study.Runtime.BenchmarkOptions;
294deae7e98SGuillaume Chatelet     BO.MinDuration = std::chrono::milliseconds(10);
295deae7e98SGuillaume Chatelet     BO.InitialIterations = BatchParameterCount * 10;
296deae7e98SGuillaume Chatelet 
297deae7e98SGuillaume Chatelet     runTrials(BO, getSizeSampler(), geOffsetSampler());
298deae7e98SGuillaume Chatelet   }
299deae7e98SGuillaume Chatelet };
300deae7e98SGuillaume Chatelet 
301deae7e98SGuillaume Chatelet void writeStudy(const Study &S) {
302438f7fc0SSiva Chandra Reddy   std::error_code EC;
303438f7fc0SSiva Chandra Reddy   raw_fd_ostream FOS(Output, EC);
304438f7fc0SSiva Chandra Reddy   if (EC)
305438f7fc0SSiva Chandra Reddy     report_fatal_error(Twine("Could not open file: ")
306438f7fc0SSiva Chandra Reddy                            .concat(EC.message())
307438f7fc0SSiva Chandra Reddy                            .concat(", ")
308438f7fc0SSiva Chandra Reddy                            .concat(Output));
309438f7fc0SSiva Chandra Reddy   json::OStream JOS(FOS);
310deae7e98SGuillaume Chatelet   serializeToJson(S, JOS);
311ab577807SGuillaume Chatelet   FOS << "\n";
312deae7e98SGuillaume Chatelet }
313deae7e98SGuillaume Chatelet 
314deae7e98SGuillaume Chatelet void main() {
315deae7e98SGuillaume Chatelet   checkRequirements();
316*8d64ed85SGuillaume Chatelet   MemfunctionBenchmark MB;
317*8d64ed85SGuillaume Chatelet   writeStudy(MB.run());
318438f7fc0SSiva Chandra Reddy }
319438f7fc0SSiva Chandra Reddy 
320438f7fc0SSiva Chandra Reddy } // namespace libc_benchmarks
321438f7fc0SSiva Chandra Reddy } // namespace llvm
322438f7fc0SSiva Chandra Reddy 
323438f7fc0SSiva Chandra Reddy int main(int argc, char **argv) {
324438f7fc0SSiva Chandra Reddy   llvm::cl::ParseCommandLineOptions(argc, argv);
325deae7e98SGuillaume Chatelet #ifndef NDEBUG
326deae7e98SGuillaume Chatelet   static_assert(
327deae7e98SGuillaume Chatelet       false,
328deae7e98SGuillaume Chatelet       "For reproducibility benchmarks should not be compiled in DEBUG mode.");
329deae7e98SGuillaume Chatelet #endif
330deae7e98SGuillaume Chatelet   llvm::libc_benchmarks::main();
331438f7fc0SSiva Chandra Reddy   return EXIT_SUCCESS;
332438f7fc0SSiva Chandra Reddy }
333