1 //===-- Benchmark function tests -----------------------------------------===// 2 // 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 9 #include "LibcBenchmark.h" 10 #include "llvm/ADT/ArrayRef.h" 11 #include "llvm/ADT/Optional.h" 12 #include "llvm/ADT/SmallVector.h" 13 #include "gmock/gmock.h" 14 #include "gtest/gtest.h" 15 #include <chrono> 16 #include <limits> 17 #include <queue> 18 #include <vector> 19 20 using std::chrono::nanoseconds; 21 using ::testing::ElementsAre; 22 using ::testing::Field; 23 using ::testing::IsEmpty; 24 using ::testing::SizeIs; 25 26 namespace llvm { 27 namespace libc_benchmarks { 28 namespace { 29 30 // A simple parameter provider returning a zero initialized vector of size 31 // `iterations`. 32 struct DummyParameterProvider { 33 std::vector<char> generateBatch(size_t iterations) { 34 return std::vector<char>(iterations); 35 } 36 }; 37 38 class LibcBenchmark : public ::testing::Test { 39 public: 40 // A Clock interface suitable for testing. 41 // - Either it returns 0, 42 // - Or a timepoint coming from the `setMeasurements` call. 43 Duration now() { 44 if (!MaybeTimepoints) 45 return {}; 46 assert(!MaybeTimepoints->empty()); 47 const Duration timepoint = MaybeTimepoints->front(); 48 MaybeTimepoints->pop(); 49 return timepoint; 50 } 51 52 protected: 53 void set_up() override { Options.Log = BenchmarkLog::Full; } 54 55 void tear_down() override { 56 // We make sure all the expected measurements were performed. 57 if (MaybeTimepoints) 58 EXPECT_THAT(*MaybeTimepoints, IsEmpty()); 59 } 60 61 BenchmarkResult run() { 62 return benchmark(Options, ParameterProvider, DummyFunction, *this); 63 } 64 65 void setMeasurements(llvm::ArrayRef<Duration> Durations) { 66 MaybeTimepoints.emplace(); // Create the optional value. 67 Duration CurrentTime = nanoseconds(1); 68 for (const auto &Duration : Durations) { 69 MaybeTimepoints->push(CurrentTime); 70 CurrentTime += Duration; 71 MaybeTimepoints->push(CurrentTime); 72 CurrentTime += nanoseconds(1); 73 } 74 } 75 76 BenchmarkOptions Options; 77 78 private: 79 DummyParameterProvider ParameterProvider; 80 static char DummyFunction(char Payload) { return Payload; } 81 llvm::Optional<std::queue<Duration>> MaybeTimepoints; 82 }; 83 84 TEST_F(LibcBenchmark, MaxSamplesReached) { 85 Options.MaxSamples = 1; 86 const auto Result = run(); 87 EXPECT_THAT(Result.MaybeBenchmarkLog->size(), 1); 88 EXPECT_THAT(Result.TerminationStatus, BenchmarkStatus::MaxSamplesReached); 89 } 90 91 TEST_F(LibcBenchmark, MaxDurationReached) { 92 Options.MaxDuration = nanoseconds(10); 93 setMeasurements({nanoseconds(11)}); 94 const auto Result = run(); 95 EXPECT_THAT(Result.MaybeBenchmarkLog->size(), 1); 96 EXPECT_THAT(Result.TerminationStatus, BenchmarkStatus::MaxDurationReached); 97 } 98 99 TEST_F(LibcBenchmark, MaxIterationsReached) { 100 Options.InitialIterations = 1; 101 Options.MaxIterations = 20; 102 Options.ScalingFactor = 2; 103 Options.Epsilon = 0; // unreachable. 104 const auto Result = run(); 105 EXPECT_THAT(*Result.MaybeBenchmarkLog, 106 ElementsAre(Field(&BenchmarkState::LastSampleIterations, 1), 107 Field(&BenchmarkState::LastSampleIterations, 2), 108 Field(&BenchmarkState::LastSampleIterations, 4), 109 Field(&BenchmarkState::LastSampleIterations, 8), 110 Field(&BenchmarkState::LastSampleIterations, 16), 111 Field(&BenchmarkState::LastSampleIterations, 32))); 112 EXPECT_THAT(Result.MaybeBenchmarkLog->size(), 6); 113 EXPECT_THAT(Result.TerminationStatus, BenchmarkStatus::MaxIterationsReached); 114 } 115 116 TEST_F(LibcBenchmark, MinSamples) { 117 Options.MinSamples = 4; 118 Options.ScalingFactor = 2; 119 Options.Epsilon = std::numeric_limits<double>::max(); // always reachable. 120 setMeasurements( 121 {nanoseconds(1), nanoseconds(2), nanoseconds(4), nanoseconds(8)}); 122 const auto Result = run(); 123 EXPECT_THAT(*Result.MaybeBenchmarkLog, 124 ElementsAre(Field(&BenchmarkState::LastSampleIterations, 1), 125 Field(&BenchmarkState::LastSampleIterations, 2), 126 Field(&BenchmarkState::LastSampleIterations, 4), 127 Field(&BenchmarkState::LastSampleIterations, 8))); 128 EXPECT_THAT(Result.MaybeBenchmarkLog->size(), 4); 129 EXPECT_THAT(Result.TerminationStatus, BenchmarkStatus::PrecisionReached); 130 } 131 132 TEST_F(LibcBenchmark, Epsilon) { 133 Options.MinSamples = 4; 134 Options.ScalingFactor = 2; 135 Options.Epsilon = std::numeric_limits<double>::max(); // always reachable. 136 setMeasurements( 137 {nanoseconds(1), nanoseconds(2), nanoseconds(4), nanoseconds(8)}); 138 const auto Result = run(); 139 EXPECT_THAT(*Result.MaybeBenchmarkLog, 140 ElementsAre(Field(&BenchmarkState::LastSampleIterations, 1), 141 Field(&BenchmarkState::LastSampleIterations, 2), 142 Field(&BenchmarkState::LastSampleIterations, 4), 143 Field(&BenchmarkState::LastSampleIterations, 8))); 144 EXPECT_THAT(Result.MaybeBenchmarkLog->size(), 4); 145 EXPECT_THAT(Result.TerminationStatus, BenchmarkStatus::PrecisionReached); 146 } 147 148 TEST(ArrayRefLoop, Cycle) { 149 std::array<int, 2> array = {1, 2}; 150 EXPECT_THAT(cycle(array, 0), ElementsAre()); 151 EXPECT_THAT(cycle(array, 1), ElementsAre(1)); 152 EXPECT_THAT(cycle(array, 2), ElementsAre(1, 2)); 153 EXPECT_THAT(cycle(array, 3), ElementsAre(1, 2, 1)); 154 EXPECT_THAT(cycle(array, 4), ElementsAre(1, 2, 1, 2)); 155 EXPECT_THAT(cycle(array, 5), ElementsAre(1, 2, 1, 2, 1)); 156 } 157 158 TEST(ByteConstrainedArray, Simple) { 159 EXPECT_THAT((ByteConstrainedArray<char, 17>()), SizeIs(17)); 160 EXPECT_THAT((ByteConstrainedArray<uint16_t, 17>()), SizeIs(8)); 161 EXPECT_THAT((ByteConstrainedArray<uint32_t, 17>()), SizeIs(4)); 162 EXPECT_THAT((ByteConstrainedArray<uint64_t, 17>()), SizeIs(2)); 163 164 EXPECT_LE(sizeof(ByteConstrainedArray<char, 17>), 17U); 165 EXPECT_LE(sizeof(ByteConstrainedArray<uint16_t, 17>), 17U); 166 EXPECT_LE(sizeof(ByteConstrainedArray<uint32_t, 17>), 17U); 167 EXPECT_LE(sizeof(ByteConstrainedArray<uint64_t, 17>), 17U); 168 } 169 170 TEST(ByteConstrainedArray, Cycle) { 171 ByteConstrainedArray<uint64_t, 17> TwoValues{{1UL, 2UL}}; 172 EXPECT_THAT(cycle(TwoValues, 5), ElementsAre(1, 2, 1, 2, 1)); 173 } 174 } // namespace 175 } // namespace libc_benchmarks 176 } // namespace llvm 177