JayBeams  0.1
Another project to have fun coding.
microbenchmark.hpp
Go to the documentation of this file.
1 #ifndef jb_testing_microbenchmark_hpp
2 #define jb_testing_microbenchmark_hpp
3 
6 
7 #include <type_traits>
8 #include <utility>
9 
10 namespace jb {
11 namespace testing {
12 
13 namespace detail {
14 /**
15  * A helper to call Fixture::iteration_setup() in the microbenchmarks.
16  *
17  * This is the no-op for fixtures that do not provide a
18  * iteration_setup() member function.
19  *
20  * @tparam Fixture the type of the Fixture
21  * @tparam Args unused, just a way for SFINAE to fallback on something.
22  */
23 template <typename Fixture, typename... Args>
24 void call_iteration_setup(Fixture&&, Args&&...) {
25 }
26 
27 /**
28  * A helper to call Fixture::iteration_setup() in the microbenchmarks.
29  *
30  * This is the version for fixtures that do provide a
31  * iteration_setup() member function.
32  *
33  * @tparam Fixture the type of the Fixture
34  */
35 template <
36  typename Fixture,
37  typename = decltype(std::declval<Fixture>().iteration_setup())>
38 void call_iteration_setup(Fixture&& fixture) {
39  fixture.iteration_setup();
40 }
41 
42 /**
43  * A helper to call Fixture::iteration_teardown() in the microbenchmarks.
44  *
45  * This is the no-op for fixtures that do not provide a
46  * iteration_teardown() member function.
47  *
48  * @tparam Fixture the type of the Fixture
49  * @tparam Args unused, just a way for SFINAE to fallback on something.
50  */
51 template <typename Fixture, typename... Args>
52 void call_iteration_teardown(Fixture&&, Args&&...) {
53 }
54 
55 /**
56  * A helper to call Fixture::iteration_teardown() in the microbenchmarks.
57  *
58  * This is the version for fixtures that do provide a
59  * iteration_teardown() member function.
60  *
61  * @tparam Fixture the type of the Fixture
62  */
63 template <
64  typename Fixture,
65  typename = decltype(std::declval<Fixture>().iteration_teardown())>
66 void call_iteration_teardown(Fixture&& fixture) {
67  fixture.iteration_teardown();
68 }
69 } // namespace detail
70 
71 /**
72  * Run a micro-benchmark on a given class.
73  *
74  * This class is used to run microbenchmarks. To use it, you wrap
75  * your function or class in a Fixture that constructs the unit under
76  * test and calls it. For example, consider a class like this:
77  *
78  * @code
79  * class Foo {
80  * public:
81  * Foo(std::string const& need_one_string);
82  *
83  * std::string bar(std::string const& need_another_string);
84  * };
85  * @endcode
86  *
87  * To test the bar() function you would create a Fixture class like
88  * this:
89  *
90  * @code
91  * class FooBarFixture {
92  * public:
93  * FooBarFixture(std::string const& pass_on)
94  * : foo_(pass_on), input_string_("some value") {}
95  * void run() const {
96  * foo_.bar(input_string_);
97  * }
98  * private:
99  * Foo foo_;
100  * std::string input_string_;
101  * };
102  * @endcode
103  *
104  * Then you can run the test using:
105  *
106  * @code
107  * jb::testing::microbenchmark<FooBarFixture> mb(jb::microbenchmark_config());
108  *
109  * auto results = mb.run(std::string("some other value");
110  * jb::microbenchmark_base::summary summary(results);
111  * std::cout << summary; // or something more clever...
112  * // for a full dump: mb.write_results(std::cout, results);
113  * @endcode
114  *
115  * The framework creates a single instance of the Fixture for the full
116  * test, it worries about running a warmup iteration, collecting the
117  * results with minimal overhead, and creating a sensible summary.
118  *
119  * @tparam Fixture A type meeting the following requirements:
120  * @code
121  * class Fixture {
122  * public:
123  * Fixture(Args ...); // default constructor, used for the default sized test
124  * Fixture(int s, Args ...); // constructor for a test of size 's'
125  *
126  * int run(); // run one iteration of the test, return the size used
127  * };
128  * @endcode
129  */
130 template <typename Fixture>
132 public:
134 
135  /**
136  * Default constructor, create a default configuration and
137  * initialize from it.
138  */
140  : microbenchmark(config()) {
141  }
142 
143  /**
144  * Constructor from a configuration
145  */
146  explicit microbenchmark(config const& cfg)
147  : microbenchmark_base(cfg) {
148  }
149 
150  /**
151  * Run the microbenchmaark.
152  *
153  * @param args the additional arguments, if any, for the Fixture
154  * constructor.
155  *
156  * @tparam Args the types for the additional arguments.
157  */
158  template <typename... Args>
159  results run(Args&&... args) {
160  if (config_.reconfigure_thread()) {
161  jb::detail::reconfigure_this_thread(config_.thread());
162  }
163  if (config_.size() != 0) {
164  return run_fixed_size(std::forward<Args>(args)...);
165  }
166  return run_unsized(std::forward<Args>(args)...);
167  }
168 
169 private:
170  /**
171  * Run a test without specifying the size and some additional
172  * arguments for the Fixture constructor.
173  *
174  * @param args additional arguments for the Fixture
175  * @tparam Args the types for the additional arguments
176  */
177  template <typename... Args>
178  results run_unsized(Args&&... args) {
179  Fixture fixture(std::forward<Args>(args)...);
180  results r;
181  run_base(fixture, r);
182  return r;
183  }
184 
185  /**
186  * Run a test without specifying the size and no additional
187  * arguments for the Fixture constructor.
188  */
190  Fixture fixture;
191  results r;
192  run_base(fixture, r);
193  return r;
194  }
195 
196  /**
197  * Run the test when the size is specified in the microbenchmark
198  * configuration.
199  *
200  * @param args additional arguments for the Fixture
201  * @tparam Args the types for the additional arguments
202  */
203  template <typename... Args>
204  results run_fixed_size(Args&&... args) {
205  results r;
206  run_sized(config_.size(), r, std::forward<Args>(args)...);
207  return r;
208  }
209 
210  /**
211  * Construct a fixture for the given size and run the microbenchmkark.
212  *
213  * @param size the size of the test
214  * @param r where to store the results of the test
215  * @param args additional arguments for the constructor, if any.
216  * @tparam Args the types of the additional arguments, if any.
217  */
218  template <typename... Args>
219  void run_sized(int size, results& r, Args&&... args) {
220  Fixture fixture(size, std::forward<Args>(args)...);
221  run_base(fixture, r);
222  }
223 
224  /**
225  * Run a microbenchmkark for a constructed fixture.
226  *
227  * Run the warmup iterations and then run the actual iterations for
228  * the test. The results of the test are ignored during the warmup
229  * phase.
230  *
231  * @param fixture the object under test
232  * @param r where to store the results of the test
233  */
234  void run_base(Fixture& fixture, results& r) {
235  for (int i = 0; i != config_.warmup_iterations(); ++i) {
236  (void)clock::now();
238  (void)fixture.run();
239  (void)clock::now();
241  }
242  r.reserve(r.size() + config_.iterations());
243  for (int i = 0; i != config_.iterations(); ++i) {
244  run_iteration(fixture, r);
245  }
246  }
247 
248  /**
249  * Run a single iteration of the test and return the results.
250  *
251  * @param fixture the object under test
252  * @param r where to store the results of the test
253  */
254  static void run_iteration(Fixture& fixture, results& r) {
256  auto start = clock::now();
257  int size = fixture.run();
258  auto stop = clock::now();
259 
260  r.emplace_back(std::make_pair(size, stop - start));
262  }
263 };
264 
265 } // namespace testing
266 } // namespace jb
267 
268 #endif // jb_testing_microbenchmark_hpp
void run_sized(int size, results &r, Args &&... args)
Construct a fixture for the given size and run the microbenchmkark.
void call_iteration_teardown(Fixture &&, Args &&...)
A helper to call Fixture::iteration_teardown() in the microbenchmarks.
static void run_iteration(Fixture &fixture, results &r)
Run a single iteration of the test and return the results.
results run(Args &&... args)
Run the microbenchmaark.
results run_fixed_size(Args &&... args)
Run the test when the size is specified in the microbenchmark configuration.
results run_unsized(Args &&... args)
Run a test without specifying the size and some additional arguments for the Fixture constructor...
void call_iteration_setup(Fixture &&, Args &&...)
A helper to call Fixture::iteration_setup() in the microbenchmarks.
void reconfigure_this_thread(thread_config const &config)
Change the current thread parameters based on the configuration.
microbenchmark(config const &cfg)
Constructor from a configuration.
Refactor non-template parts of the microbenchmark template class.
microbenchmark()
Default constructor, create a default configuration and initialize from it.
Run a micro-benchmark on a given class.
jb::testing::microbenchmark_config config
void run_base(Fixture &fixture, results &r)
Run a microbenchmkark for a constructed fixture.
results run_unsized()
Run a test without specifying the size and no additional arguments for the Fixture constructor...
The top-level namespace for the JayBeams library.
Definition: as_hhmmss.hpp:7