Bitcoin Core  0.19.99
P2P Digital Currency
bench.h
Go to the documentation of this file.
1 // Copyright (c) 2015-2020 The Bitcoin Core developers
2 // Distributed under the MIT software license, see the accompanying
3 // file COPYING or http://www.opensource.org/licenses/mit-license.php.
4 
5 #ifndef BITCOIN_BENCH_BENCH_H
6 #define BITCOIN_BENCH_BENCH_H
7 
8 #include <functional>
9 #include <map>
10 #include <string>
11 #include <vector>
12 #include <chrono>
13 
14 #include <boost/preprocessor/cat.hpp>
15 #include <boost/preprocessor/stringize.hpp>
16 
17 struct RegTestingSetup;
18 extern const RegTestingSetup* g_testing_setup;
19 
20 // Simple micro-benchmarking framework; API mostly matches a subset of the Google Benchmark
21 // framework (see https://github.com/google/benchmark)
22 // Why not use the Google Benchmark framework? Because adding Yet Another Dependency
23 // (that uses cmake as its build system and has lots of features we don't need) isn't
24 // worth it.
25 
26 /*
27  * Usage:
28 
29 static void CODE_TO_TIME(benchmark::State& state)
30 {
31  ... do any setup needed...
32  while (state.KeepRunning()) {
33  ... do stuff you want to time...
34  }
35  ... do any cleanup needed...
36 }
37 
38 // default to running benchmark for 5000 iterations
39 BENCHMARK(CODE_TO_TIME, 5000);
40 
41  */
42 
43 namespace benchmark {
44 // In case high_resolution_clock is steady, prefer that, otherwise use steady_clock.
45 struct best_clock {
46  using hi_res_clock = std::chrono::high_resolution_clock;
47  using steady_clock = std::chrono::steady_clock;
48  using type = std::conditional<hi_res_clock::is_steady, hi_res_clock, steady_clock>::type;
49 };
53 
54 class Printer;
55 
56 class State
57 {
58 public:
59  std::string m_name;
60  uint64_t m_num_iters_left;
61  const uint64_t m_num_iters;
62  const uint64_t m_num_evals;
63  std::vector<double> m_elapsed_results;
65 
66  bool UpdateTimer(time_point finish_time);
67 
68  State(std::string name, uint64_t num_evals, double num_iters, Printer& printer) : m_name(name), m_num_iters_left(0), m_num_iters(num_iters), m_num_evals(num_evals)
69  {
70  }
71 
72  inline bool KeepRunning()
73  {
74  if (m_num_iters_left--) {
75  return true;
76  }
77 
78  bool result = UpdateTimer(clock::now());
79  // measure again so runtime of UpdateTimer is not included
80  m_start_time = clock::now();
81  return result;
82  }
83 };
84 
85 typedef std::function<void(State&)> BenchFunction;
86 
88 {
89  struct Bench {
90  BenchFunction func;
92  };
93  typedef std::map<std::string, Bench> BenchmarkMap;
94  static BenchmarkMap& benchmarks();
95 
96 public:
97  BenchRunner(std::string name, BenchFunction func, uint64_t num_iters_for_one_second);
98 
99  static void RunAll(Printer& printer, uint64_t num_evals, double scaling, const std::string& filter, bool is_list_only);
100 };
101 
102 // interface to output benchmark results.
103 class Printer
104 {
105 public:
106  virtual ~Printer() {}
107  virtual void header() = 0;
108  virtual void result(const State& state) = 0;
109  virtual void footer() = 0;
110 };
111 
112 // default printer to console, shows min, max, median.
113 class ConsolePrinter : public Printer
114 {
115 public:
116  void header() override;
117  void result(const State& state) override;
118  void footer() override;
119 };
120 
121 // creates box plot with plotly.js
122 class PlotlyPrinter : public Printer
123 {
124 public:
125  PlotlyPrinter(std::string plotly_url, int64_t width, int64_t height);
126  void header() override;
127  void result(const State& state) override;
128  void footer() override;
129 
130 private:
131  std::string m_plotly_url;
132  int64_t m_width;
133  int64_t m_height;
134 };
135 }
136 
137 
138 // BENCHMARK(foo, num_iters_for_one_second) expands to: benchmark::BenchRunner bench_11foo("foo", num_iterations);
139 // Choose a num_iters_for_one_second that takes roughly 1 second. The goal is that all benchmarks should take approximately
140 // the same time, and scaling factor can be used that the total time is appropriate for your system.
141 #define BENCHMARK(n, num_iters_for_one_second) \
142  benchmark::BenchRunner BOOST_PP_CAT(bench_, BOOST_PP_CAT(__LINE__, n))(BOOST_PP_STRINGIZE(n), n, (num_iters_for_one_second));
143 
144 #endif // BITCOIN_BENCH_BENCH_H
const uint64_t m_num_iters
Definition: bench.h:61
std::string m_plotly_url
Definition: bench.h:131
std::chrono::steady_clock steady_clock
Definition: bench.h:47
std::vector< double > m_elapsed_results
Definition: bench.h:63
bool KeepRunning()
Definition: bench.h:72
time_point m_start_time
Definition: bench.h:64
uint64_t m_num_iters_left
Definition: bench.h:60
best_clock::type clock
Definition: bench.h:50
const char * name
Definition: rest.cpp:40
clock::duration duration
Definition: bench.h:52
BenchFunction func
Definition: bench.h:90
State(std::string name, uint64_t num_evals, double num_iters, Printer &printer)
Definition: bench.h:68
const uint64_t m_num_evals
Definition: bench.h:62
std::function< void(State &)> BenchFunction
Definition: bench.h:85
std::chrono::high_resolution_clock hi_res_clock
Definition: bench.h:46
std::map< std::string, Bench > BenchmarkMap
Definition: bench.h:93
std::conditional< hi_res_clock::is_steady, hi_res_clock, steady_clock >::type type
Definition: bench.h:48
std::string m_name
Definition: bench.h:59
uint64_t num_iters_for_one_second
Definition: bench.h:91
clock::time_point time_point
Definition: bench.h:51
const RegTestingSetup * g_testing_setup
A pointer to the current testing setup.
Definition: bench.cpp:18
virtual ~Printer()
Definition: bench.h:106