xref: /llvm-project/libc/benchmarks/LibcBenchmarkTest.cpp (revision b5516be05654ecdd4fd7e317b1f21f940c1a967b)
1438f7fc0SSiva Chandra Reddy //===-- Benchmark function tests -----------------------------------------===//
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 "LibcBenchmark.h"
10438f7fc0SSiva Chandra Reddy #include "llvm/ADT/ArrayRef.h"
11438f7fc0SSiva Chandra Reddy #include "llvm/ADT/SmallVector.h"
12438f7fc0SSiva Chandra Reddy #include "gmock/gmock.h"
13438f7fc0SSiva Chandra Reddy #include "gtest/gtest.h"
14438f7fc0SSiva Chandra Reddy #include <chrono>
15438f7fc0SSiva Chandra Reddy #include <limits>
16*b5516be0SKazu Hirata #include <optional>
17438f7fc0SSiva Chandra Reddy #include <queue>
18438f7fc0SSiva Chandra Reddy #include <vector>
19438f7fc0SSiva Chandra Reddy 
20438f7fc0SSiva Chandra Reddy using std::chrono::nanoseconds;
21438f7fc0SSiva Chandra Reddy using ::testing::ElementsAre;
22438f7fc0SSiva Chandra Reddy using ::testing::Field;
23438f7fc0SSiva Chandra Reddy using ::testing::IsEmpty;
24438f7fc0SSiva Chandra Reddy using ::testing::SizeIs;
25438f7fc0SSiva Chandra Reddy 
26438f7fc0SSiva Chandra Reddy namespace llvm {
27438f7fc0SSiva Chandra Reddy namespace libc_benchmarks {
28438f7fc0SSiva Chandra Reddy namespace {
29438f7fc0SSiva Chandra Reddy 
30438f7fc0SSiva Chandra Reddy // A simple parameter provider returning a zero initialized vector of size
31438f7fc0SSiva Chandra Reddy // `iterations`.
32438f7fc0SSiva Chandra Reddy struct DummyParameterProvider {
generateBatchllvm::libc_benchmarks::__anona9ea680e0111::DummyParameterProvider33438f7fc0SSiva Chandra Reddy   std::vector<char> generateBatch(size_t iterations) {
34438f7fc0SSiva Chandra Reddy     return std::vector<char>(iterations);
35438f7fc0SSiva Chandra Reddy   }
36438f7fc0SSiva Chandra Reddy };
37438f7fc0SSiva Chandra Reddy 
38438f7fc0SSiva Chandra Reddy class LibcBenchmark : public ::testing::Test {
39438f7fc0SSiva Chandra Reddy public:
40438f7fc0SSiva Chandra Reddy   // A Clock interface suitable for testing.
41438f7fc0SSiva Chandra Reddy   // - Either it returns 0,
42438f7fc0SSiva Chandra Reddy   // - Or a timepoint coming from the `setMeasurements` call.
now()43438f7fc0SSiva Chandra Reddy   Duration now() {
44438f7fc0SSiva Chandra Reddy     if (!MaybeTimepoints)
45438f7fc0SSiva Chandra Reddy       return {};
46438f7fc0SSiva Chandra Reddy     assert(!MaybeTimepoints->empty());
47438f7fc0SSiva Chandra Reddy     const Duration timepoint = MaybeTimepoints->front();
48438f7fc0SSiva Chandra Reddy     MaybeTimepoints->pop();
49438f7fc0SSiva Chandra Reddy     return timepoint;
50438f7fc0SSiva Chandra Reddy   }
51438f7fc0SSiva Chandra Reddy 
52438f7fc0SSiva Chandra Reddy protected:
SetUp()5379abf893SMichael Jones   void SetUp() override { Options.Log = BenchmarkLog::Full; }
54438f7fc0SSiva Chandra Reddy 
TearDown()5579abf893SMichael Jones   void TearDown() override {
56438f7fc0SSiva Chandra Reddy     // We make sure all the expected measurements were performed.
57438f7fc0SSiva Chandra Reddy     if (MaybeTimepoints)
58438f7fc0SSiva Chandra Reddy       EXPECT_THAT(*MaybeTimepoints, IsEmpty());
59438f7fc0SSiva Chandra Reddy   }
60438f7fc0SSiva Chandra Reddy 
run()61438f7fc0SSiva Chandra Reddy   BenchmarkResult run() {
62438f7fc0SSiva Chandra Reddy     return benchmark(Options, ParameterProvider, DummyFunction, *this);
63438f7fc0SSiva Chandra Reddy   }
64438f7fc0SSiva Chandra Reddy 
setMeasurements(llvm::ArrayRef<Duration> Durations)65438f7fc0SSiva Chandra Reddy   void setMeasurements(llvm::ArrayRef<Duration> Durations) {
66438f7fc0SSiva Chandra Reddy     MaybeTimepoints.emplace(); // Create the optional value.
67438f7fc0SSiva Chandra Reddy     Duration CurrentTime = nanoseconds(1);
68438f7fc0SSiva Chandra Reddy     for (const auto &Duration : Durations) {
69438f7fc0SSiva Chandra Reddy       MaybeTimepoints->push(CurrentTime);
70438f7fc0SSiva Chandra Reddy       CurrentTime += Duration;
71438f7fc0SSiva Chandra Reddy       MaybeTimepoints->push(CurrentTime);
72438f7fc0SSiva Chandra Reddy       CurrentTime += nanoseconds(1);
73438f7fc0SSiva Chandra Reddy     }
74438f7fc0SSiva Chandra Reddy   }
75438f7fc0SSiva Chandra Reddy 
76438f7fc0SSiva Chandra Reddy   BenchmarkOptions Options;
77438f7fc0SSiva Chandra Reddy 
78438f7fc0SSiva Chandra Reddy private:
79438f7fc0SSiva Chandra Reddy   DummyParameterProvider ParameterProvider;
DummyFunction(char Payload)80438f7fc0SSiva Chandra Reddy   static char DummyFunction(char Payload) { return Payload; }
81e1cdda57SKazu Hirata   std::optional<std::queue<Duration>> MaybeTimepoints;
82438f7fc0SSiva Chandra Reddy };
83438f7fc0SSiva Chandra Reddy 
TEST_F(LibcBenchmark,MaxSamplesReached)84438f7fc0SSiva Chandra Reddy TEST_F(LibcBenchmark, MaxSamplesReached) {
85438f7fc0SSiva Chandra Reddy   Options.MaxSamples = 1;
86438f7fc0SSiva Chandra Reddy   const auto Result = run();
87438f7fc0SSiva Chandra Reddy   EXPECT_THAT(Result.MaybeBenchmarkLog->size(), 1);
88438f7fc0SSiva Chandra Reddy   EXPECT_THAT(Result.TerminationStatus, BenchmarkStatus::MaxSamplesReached);
89438f7fc0SSiva Chandra Reddy }
90438f7fc0SSiva Chandra Reddy 
TEST_F(LibcBenchmark,MaxDurationReached)91438f7fc0SSiva Chandra Reddy TEST_F(LibcBenchmark, MaxDurationReached) {
92438f7fc0SSiva Chandra Reddy   Options.MaxDuration = nanoseconds(10);
93438f7fc0SSiva Chandra Reddy   setMeasurements({nanoseconds(11)});
94438f7fc0SSiva Chandra Reddy   const auto Result = run();
95438f7fc0SSiva Chandra Reddy   EXPECT_THAT(Result.MaybeBenchmarkLog->size(), 1);
96438f7fc0SSiva Chandra Reddy   EXPECT_THAT(Result.TerminationStatus, BenchmarkStatus::MaxDurationReached);
97438f7fc0SSiva Chandra Reddy }
98438f7fc0SSiva Chandra Reddy 
TEST_F(LibcBenchmark,MaxIterationsReached)99438f7fc0SSiva Chandra Reddy TEST_F(LibcBenchmark, MaxIterationsReached) {
100438f7fc0SSiva Chandra Reddy   Options.InitialIterations = 1;
101438f7fc0SSiva Chandra Reddy   Options.MaxIterations = 20;
102438f7fc0SSiva Chandra Reddy   Options.ScalingFactor = 2;
103438f7fc0SSiva Chandra Reddy   Options.Epsilon = 0; // unreachable.
104438f7fc0SSiva Chandra Reddy   const auto Result = run();
105438f7fc0SSiva Chandra Reddy   EXPECT_THAT(*Result.MaybeBenchmarkLog,
106438f7fc0SSiva Chandra Reddy               ElementsAre(Field(&BenchmarkState::LastSampleIterations, 1),
107438f7fc0SSiva Chandra Reddy                           Field(&BenchmarkState::LastSampleIterations, 2),
108438f7fc0SSiva Chandra Reddy                           Field(&BenchmarkState::LastSampleIterations, 4),
109438f7fc0SSiva Chandra Reddy                           Field(&BenchmarkState::LastSampleIterations, 8),
110438f7fc0SSiva Chandra Reddy                           Field(&BenchmarkState::LastSampleIterations, 16),
111438f7fc0SSiva Chandra Reddy                           Field(&BenchmarkState::LastSampleIterations, 32)));
112438f7fc0SSiva Chandra Reddy   EXPECT_THAT(Result.MaybeBenchmarkLog->size(), 6);
113438f7fc0SSiva Chandra Reddy   EXPECT_THAT(Result.TerminationStatus, BenchmarkStatus::MaxIterationsReached);
114438f7fc0SSiva Chandra Reddy }
115438f7fc0SSiva Chandra Reddy 
TEST_F(LibcBenchmark,MinSamples)116438f7fc0SSiva Chandra Reddy TEST_F(LibcBenchmark, MinSamples) {
117438f7fc0SSiva Chandra Reddy   Options.MinSamples = 4;
118438f7fc0SSiva Chandra Reddy   Options.ScalingFactor = 2;
119438f7fc0SSiva Chandra Reddy   Options.Epsilon = std::numeric_limits<double>::max(); // always reachable.
120438f7fc0SSiva Chandra Reddy   setMeasurements(
121438f7fc0SSiva Chandra Reddy       {nanoseconds(1), nanoseconds(2), nanoseconds(4), nanoseconds(8)});
122438f7fc0SSiva Chandra Reddy   const auto Result = run();
123438f7fc0SSiva Chandra Reddy   EXPECT_THAT(*Result.MaybeBenchmarkLog,
124438f7fc0SSiva Chandra Reddy               ElementsAre(Field(&BenchmarkState::LastSampleIterations, 1),
125438f7fc0SSiva Chandra Reddy                           Field(&BenchmarkState::LastSampleIterations, 2),
126438f7fc0SSiva Chandra Reddy                           Field(&BenchmarkState::LastSampleIterations, 4),
127438f7fc0SSiva Chandra Reddy                           Field(&BenchmarkState::LastSampleIterations, 8)));
128438f7fc0SSiva Chandra Reddy   EXPECT_THAT(Result.MaybeBenchmarkLog->size(), 4);
129438f7fc0SSiva Chandra Reddy   EXPECT_THAT(Result.TerminationStatus, BenchmarkStatus::PrecisionReached);
130438f7fc0SSiva Chandra Reddy }
131438f7fc0SSiva Chandra Reddy 
TEST_F(LibcBenchmark,Epsilon)132438f7fc0SSiva Chandra Reddy TEST_F(LibcBenchmark, Epsilon) {
133438f7fc0SSiva Chandra Reddy   Options.MinSamples = 4;
134438f7fc0SSiva Chandra Reddy   Options.ScalingFactor = 2;
135438f7fc0SSiva Chandra Reddy   Options.Epsilon = std::numeric_limits<double>::max(); // always reachable.
136438f7fc0SSiva Chandra Reddy   setMeasurements(
137438f7fc0SSiva Chandra Reddy       {nanoseconds(1), nanoseconds(2), nanoseconds(4), nanoseconds(8)});
138438f7fc0SSiva Chandra Reddy   const auto Result = run();
139438f7fc0SSiva Chandra Reddy   EXPECT_THAT(*Result.MaybeBenchmarkLog,
140438f7fc0SSiva Chandra Reddy               ElementsAre(Field(&BenchmarkState::LastSampleIterations, 1),
141438f7fc0SSiva Chandra Reddy                           Field(&BenchmarkState::LastSampleIterations, 2),
142438f7fc0SSiva Chandra Reddy                           Field(&BenchmarkState::LastSampleIterations, 4),
143438f7fc0SSiva Chandra Reddy                           Field(&BenchmarkState::LastSampleIterations, 8)));
144438f7fc0SSiva Chandra Reddy   EXPECT_THAT(Result.MaybeBenchmarkLog->size(), 4);
145438f7fc0SSiva Chandra Reddy   EXPECT_THAT(Result.TerminationStatus, BenchmarkStatus::PrecisionReached);
146438f7fc0SSiva Chandra Reddy }
147438f7fc0SSiva Chandra Reddy 
TEST(ArrayRefLoop,Cycle)148438f7fc0SSiva Chandra Reddy TEST(ArrayRefLoop, Cycle) {
149438f7fc0SSiva Chandra Reddy   std::array<int, 2> array = {1, 2};
150438f7fc0SSiva Chandra Reddy   EXPECT_THAT(cycle(array, 0), ElementsAre());
151438f7fc0SSiva Chandra Reddy   EXPECT_THAT(cycle(array, 1), ElementsAre(1));
152438f7fc0SSiva Chandra Reddy   EXPECT_THAT(cycle(array, 2), ElementsAre(1, 2));
153438f7fc0SSiva Chandra Reddy   EXPECT_THAT(cycle(array, 3), ElementsAre(1, 2, 1));
154438f7fc0SSiva Chandra Reddy   EXPECT_THAT(cycle(array, 4), ElementsAre(1, 2, 1, 2));
155438f7fc0SSiva Chandra Reddy   EXPECT_THAT(cycle(array, 5), ElementsAre(1, 2, 1, 2, 1));
156438f7fc0SSiva Chandra Reddy }
157438f7fc0SSiva Chandra Reddy 
TEST(ByteConstrainedArray,Simple)158438f7fc0SSiva Chandra Reddy TEST(ByteConstrainedArray, Simple) {
159438f7fc0SSiva Chandra Reddy   EXPECT_THAT((ByteConstrainedArray<char, 17>()), SizeIs(17));
160438f7fc0SSiva Chandra Reddy   EXPECT_THAT((ByteConstrainedArray<uint16_t, 17>()), SizeIs(8));
161438f7fc0SSiva Chandra Reddy   EXPECT_THAT((ByteConstrainedArray<uint32_t, 17>()), SizeIs(4));
162438f7fc0SSiva Chandra Reddy   EXPECT_THAT((ByteConstrainedArray<uint64_t, 17>()), SizeIs(2));
163438f7fc0SSiva Chandra Reddy 
164438f7fc0SSiva Chandra Reddy   EXPECT_LE(sizeof(ByteConstrainedArray<char, 17>), 17U);
165438f7fc0SSiva Chandra Reddy   EXPECT_LE(sizeof(ByteConstrainedArray<uint16_t, 17>), 17U);
166438f7fc0SSiva Chandra Reddy   EXPECT_LE(sizeof(ByteConstrainedArray<uint32_t, 17>), 17U);
167438f7fc0SSiva Chandra Reddy   EXPECT_LE(sizeof(ByteConstrainedArray<uint64_t, 17>), 17U);
168438f7fc0SSiva Chandra Reddy }
169438f7fc0SSiva Chandra Reddy 
TEST(ByteConstrainedArray,Cycle)170438f7fc0SSiva Chandra Reddy TEST(ByteConstrainedArray, Cycle) {
171438f7fc0SSiva Chandra Reddy   ByteConstrainedArray<uint64_t, 17> TwoValues{{1UL, 2UL}};
172438f7fc0SSiva Chandra Reddy   EXPECT_THAT(cycle(TwoValues, 5), ElementsAre(1, 2, 1, 2, 1));
173438f7fc0SSiva Chandra Reddy }
174438f7fc0SSiva Chandra Reddy } // namespace
175438f7fc0SSiva Chandra Reddy } // namespace libc_benchmarks
176438f7fc0SSiva Chandra Reddy } // namespace llvm
177