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