• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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