1 // Copyright 2022 The Pigweed Authors 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); you may not 4 // use this file except in compliance with the License. You may obtain a copy of 5 // the License at 6 // 7 // https://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 11 // WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 12 // License for the specific language governing permissions and limitations under 13 // the License. 14 #pragma once 15 16 #include <cstdint> 17 #include <limits> 18 19 #include "pw_assert/assert.h" 20 #include "pw_perf_test/event_handler.h" 21 #include "pw_perf_test/internal/duration_unit.h" 22 #include "pw_perf_test/internal/timer.h" 23 #include "pw_preprocessor/arguments.h" 24 25 #define PW_PERF_TEST(name, function, ...) \ 26 const ::pw::perf_test::internal::TestInfo PwPerfTest_##name( \ 27 #name, [](::pw::perf_test::State& pw_perf_test_state) { \ 28 static_cast<void>( \ 29 function(pw_perf_test_state PW_COMMA_ARGS(__VA_ARGS__))); \ 30 }) 31 32 #define PW_PERF_TEST_SIMPLE(name, function, ...) \ 33 PW_PERF_TEST( \ 34 name, \ 35 [](::pw::perf_test::State& pw_perf_test_simple_state, \ 36 const auto&... args) { \ 37 while (pw_perf_test_simple_state.KeepRunning()) { \ 38 function(args...); \ 39 } \ 40 }, \ 41 __VA_ARGS__) 42 43 namespace pw::perf_test { 44 45 class State; 46 47 namespace internal { 48 49 class TestInfo; 50 51 // Allows access to the private State object constructor 52 State CreateState(int durations, 53 EventHandler& event_handler, 54 const char* test_name); 55 56 class Framework { 57 public: Framework()58 constexpr Framework() 59 : event_handler_(nullptr), 60 tests_(nullptr), 61 run_info_{.total_tests = 0, .default_iterations = kDefaultIterations} {} 62 Get()63 static Framework& Get() { return framework_; } 64 RegisterEventHandler(EventHandler & event_handler)65 void RegisterEventHandler(EventHandler& event_handler) { 66 event_handler_ = &event_handler; 67 } 68 69 void RegisterTest(TestInfo&); 70 71 int RunAllTests(); 72 73 private: 74 static constexpr int kDefaultIterations = 10; 75 76 EventHandler* event_handler_; 77 78 // Pointer to the list of tests 79 TestInfo* tests_; 80 81 TestRunInfo run_info_; 82 83 static Framework framework_; 84 }; 85 86 class TestInfo { 87 public: TestInfo(const char * test_name,void (* function_body)(State &))88 TestInfo(const char* test_name, void (*function_body)(State&)) 89 : run_(function_body), test_name_(test_name) { 90 // Once a TestInfo object is created by the macro, this adds itself to the 91 // list of registered tests 92 Framework::Get().RegisterTest(*this); 93 } 94 95 // Returns the next registered test next()96 TestInfo* next() const { return next_; } 97 SetNext(TestInfo * next)98 void SetNext(TestInfo* next) { next_ = next; } 99 Run(State & state)100 void Run(State& state) const { run_(state); } 101 test_name()102 const char* test_name() const { return test_name_; } 103 104 private: 105 // Function pointer to the code that will be measured 106 void (*run_)(State&); 107 108 // Intrusively linked list, this acts as a pointer to the next test 109 TestInfo* next_ = nullptr; 110 111 const char* test_name_; 112 }; 113 114 } // namespace internal 115 116 class State { 117 public: 118 // KeepRunning() should be called in a while loop. Responsible for managing 119 // iterations and timestamps. 120 bool KeepRunning(); 121 122 private: 123 // Allows the framework to create state objects and unit tests for the state 124 // class 125 friend State internal::CreateState(int durations, 126 EventHandler& event_handler, 127 const char* test_name); 128 129 // Privated constructor to prevent unauthorized instances of the state class. State(int iterations,EventHandler & event_handler,const char * test_name)130 constexpr State(int iterations, 131 EventHandler& event_handler, 132 const char* test_name) 133 : mean_(-1), 134 test_iterations_(iterations), 135 total_duration_(0), 136 min_(std::numeric_limits<int64_t>::max()), 137 max_(std::numeric_limits<int64_t>::min()), 138 iteration_start_(), 139 current_iteration_(-1), 140 event_handler_(&event_handler), 141 test_info{.name = test_name} { 142 PW_ASSERT(test_iterations_ > 0); 143 } 144 // Set public after deciding how exactly to set user-defined iterations SetIterations(int iterations)145 void SetIterations(int iterations) { 146 PW_ASSERT(current_iteration_ == -1); 147 test_iterations_ = iterations; 148 PW_ASSERT(test_iterations_ > 0); 149 } 150 151 int64_t mean_; 152 153 // Stores the total number of iterations wanted 154 int test_iterations_; 155 156 // Stores the total duration of the tests. 157 int64_t total_duration_; 158 159 // Smallest value of the iterations 160 int64_t min_; 161 162 // Largest value of the iterations 163 int64_t max_; 164 165 // Time at the start of the iteration 166 internal::Timestamp iteration_start_; 167 168 // The current iteration 169 int current_iteration_; 170 171 EventHandler* event_handler_; 172 173 TestCase test_info; 174 }; 175 176 void RunAllTests(pw::perf_test::EventHandler& handler); 177 178 } // namespace pw::perf_test 179