Bitcoin Core 28.0.0
P2P Digital Currency
Loading...
Searching...
No Matches
bench.cpp
Go to the documentation of this file.
1// Copyright (c) 2015-2022 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#include <bench/bench.h>
6
8#include <util/fs.h>
9#include <util/string.h>
10
11#include <chrono>
12#include <fstream>
13#include <functional>
14#include <iostream>
15#include <map>
16#include <regex>
17#include <string>
18#include <vector>
19
20using namespace std::chrono_literals;
21using util::Join;
22
23const std::function<void(const std::string&)> G_TEST_LOG_FUN{};
24
25const std::function<std::vector<const char*>()> G_TEST_COMMAND_LINE_ARGUMENTS{};
26
27const std::function<std::string()> G_TEST_GET_FULL_NAME{};
28
29namespace {
30
31void GenerateTemplateResults(const std::vector<ankerl::nanobench::Result>& benchmarkResults, const fs::path& file, const char* tpl)
32{
33 if (benchmarkResults.empty() || file.empty()) {
34 // nothing to write, bail out
35 return;
36 }
37 std::ofstream fout{file};
38 if (fout.is_open()) {
39 ankerl::nanobench::render(tpl, benchmarkResults, fout);
40 std::cout << "Created " << file << std::endl;
41 } else {
42 std::cout << "Could not write to file " << file << std::endl;
43 }
44}
45
46} // namespace
47
48namespace benchmark {
49
50// map a label to one or multiple priority levels
51std::map<std::string, uint8_t> map_label_priority = {
52 {"high", PriorityLevel::HIGH},
53 {"low", PriorityLevel::LOW},
54 {"all", 0xff}
55};
56
57std::string ListPriorities()
58{
59 using item_t = std::pair<std::string, uint8_t>;
60 auto sort_by_priority = [](item_t a, item_t b){ return a.second < b.second; };
61 std::set<item_t, decltype(sort_by_priority)> sorted_priorities(map_label_priority.begin(), map_label_priority.end(), sort_by_priority);
62 return Join(sorted_priorities, ',', [](const auto& entry){ return entry.first; });
63}
64
65uint8_t StringToPriority(const std::string& str)
66{
67 auto it = map_label_priority.find(str);
68 if (it == map_label_priority.end()) throw std::runtime_error(strprintf("Unknown priority level %s", str));
69 return it->second;
70}
71
73{
74 static BenchmarkMap benchmarks_map;
75 return benchmarks_map;
76}
77
79{
80 benchmarks().insert(std::make_pair(name, std::make_pair(func, level)));
81}
82
84{
85 std::regex reFilter(args.regex_filter);
86 std::smatch baseMatch;
87
88 if (args.sanity_check) {
89 std::cout << "Running with -sanity-check option, output is being suppressed as benchmark results will be useless." << std::endl;
90 }
91
92 std::vector<ankerl::nanobench::Result> benchmarkResults;
93 for (const auto& [name, bench_func] : benchmarks()) {
94 const auto& [func, priority_level] = bench_func;
95
96 if (!(priority_level & args.priority)) {
97 continue;
98 }
99
100 if (!std::regex_match(name, baseMatch, reFilter)) {
101 continue;
102 }
103
104 if (args.is_list_only) {
105 std::cout << name << std::endl;
106 continue;
107 }
108
109 Bench bench;
110 if (args.sanity_check) {
111 bench.epochs(1).epochIterations(1);
112 bench.output(nullptr);
113 }
114 bench.name(name);
115 if (args.min_time > 0ms) {
116 // convert to nanos before dividing to reduce rounding errors
117 std::chrono::nanoseconds min_time_ns = args.min_time;
118 bench.minEpochTime(min_time_ns / bench.epochs());
119 }
120
121 if (args.asymptote.empty()) {
122 func(bench);
123 } else {
124 for (auto n : args.asymptote) {
125 bench.complexityN(n);
126 func(bench);
127 }
128 std::cout << bench.complexityBigO() << std::endl;
129 }
130
131 if (!bench.results().empty()) {
132 benchmarkResults.push_back(bench.results().back());
133 }
134 }
135
136 GenerateTemplateResults(benchmarkResults, args.output_csv, "# Benchmark, evals, iterations, total, min, max, median\n"
137 "{{#result}}{{name}}, {{epochs}}, {{average(iterations)}}, {{sumProduct(iterations, elapsed)}}, {{minimum(elapsed)}}, {{maximum(elapsed)}}, {{median(elapsed)}}\n"
138 "{{/result}}");
139 GenerateTemplateResults(benchmarkResults, args.output_json, ankerl::nanobench::templates::json());
140}
141
142} // namespace benchmark
const std::function< void(const std::string &)> G_TEST_LOG_FUN
This is connected to the logger.
Definition bench.cpp:23
const std::function< std::vector< const char * >()> G_TEST_COMMAND_LINE_ARGUMENTS
Retrieve the command line arguments.
Definition bench.cpp:25
const std::function< std::string()> G_TEST_GET_FULL_NAME
Retrieve the unit test name.
Definition bench.cpp:27
ArgsManager & args
Definition bitcoind.cpp:270
Main entry point to nanobench's benchmarking facility.
Definition nanobench.h:627
Bench & epochs(size_t numEpochs) noexcept
Controls number of epochs, the number of measurements to perform.
ANKERL_NANOBENCH(NODISCARD) std Bench & name(char const *benchmarkName)
Gets the title of the benchmark.
std::vector< BigO > complexityBigO() const
ANKERL_NANOBENCH(NODISCARD) std ANKERL_NANOBENCH(NODISCARD) std Bench & output(std::ostream *outstream) noexcept
Set the output stream where the resulting markdown table will be printed to.
Bench & complexityN(T n) noexcept
Definition nanobench.h:1265
ANKERL_NANOBENCH(NODISCARD) std Bench & minEpochTime(std::chrono::nanoseconds t) noexcept
Minimum time each epoch should take.
Bench & epochIterations(uint64_t numIters) noexcept
Sets exactly the number of iterations for each epoch.
std::map< std::string, std::pair< BenchFunction, PriorityLevel > > BenchmarkMap
Definition bench.h:68
static void RunAll(const Args &args)
Definition bench.cpp:83
BenchRunner(std::string name, BenchFunction func, PriorityLevel level)
Definition bench.cpp:78
static BenchmarkMap & benchmarks()
Definition bench.cpp:72
Path class wrapper to block calls to the fs::path(std::string) implicit constructor and the fs::path:...
Definition fs.h:33
char const * json() noexcept
Template to generate JSON data.
void render(char const *mustacheTemplate, Bench const &bench, std::ostream &out)
Renders output from a mustache-like template and benchmark results.
std::string ListPriorities()
Definition bench.cpp:57
std::map< std::string, uint8_t > map_label_priority
Definition bench.cpp:51
std::function< void(Bench &)> BenchFunction
Definition bench.h:42
PriorityLevel
Definition bench.h:45
@ HIGH
Definition bench.h:47
@ LOW
Definition bench.h:46
uint8_t StringToPriority(const std::string &str)
Definition bench.cpp:65
auto Join(const C &container, const S &separator, UnaryOp unary_op)
Join all container items.
Definition string.h:115
const char * name
Definition rest.cpp:49
#define strprintf
Format arguments and return the string or write to given std::ostream (see tinyformat::format doc for...