Skip to content

Commit fabc031

Browse files
committed
Merge bitcoin/bitcoin#26158: bench: add "priority level" to the benchmark framework
3e9d0be build: only run high priority benchmarks in 'make check' (furszy) 466b54b bench: surround main() execution with try/catch (furszy) 3da7cd2 bench: explicitly make all current benchmarks "high" priority (furszy) 05b8c76 bench: add "priority level" to the benchmark framework (furszy) f159378 bench: place benchmark implementation inside benchmark namespace (furszy) Pull request description: This is from today's meeting, a simple "priority level" for the benchmark framework. Will allow us to run certain benchmarks while skip non-prioritized ones in `make check`. By default, `bench_bitcoin` will run all the benchmarks. `make check`will only run the high priority ones, and have marked all the existent benchmarks as "high priority" to retain the current behavior. Could test it by modifying any benchmark priority to something different from "high", and run `bench_bitcoin -priority-level=high` and/or `bench_bitcoin -priority-level=medium,low` (the first command will skip the modified bench while the second one will include it). Note: the second commit could be avoided by having a default arg value for the priority level but.. an explicit set in every `BENCHMARK` macro call makes it less error-prone. ACKs for top commit: kouloumos: re-ACK 3e9d0be achow101: ACK 3e9d0be theStack: re-ACK 3e9d0be stickies-v: re-ACK bitcoin/bitcoin@3e9d0be Tree-SHA512: ece59bf424c5fc1db335f84caa507476fb8ad8c6151880f1f8289562e17023aae5b5e7de03e8cbba6337bf09215f9be331e9ef51c791c43bce43f7446813b054
2 parents 2ac71d2 + 3e9d0be commit fabc031

36 files changed

+184
-121
lines changed

src/Makefile.test.include

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -376,8 +376,8 @@ endif
376376
if TARGET_WINDOWS
377377
else
378378
if ENABLE_BENCH
379-
@echo "Running bench/bench_bitcoin (one iteration sanity check)..."
380-
$(BENCH_BINARY) --sanity-check > /dev/null
379+
@echo "Running bench/bench_bitcoin (one iteration sanity check, only high priority)..."
380+
$(BENCH_BINARY) -sanity-check -priority-level=high > /dev/null
381381
endif
382382
endif
383383
$(AM_V_at)$(MAKE) $(AM_MAKEFLAGS) -C secp256k1 check

src/bench/addrman.cpp

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -133,7 +133,7 @@ static void AddrManAddThenGood(benchmark::Bench& bench)
133133
});
134134
}
135135

136-
BENCHMARK(AddrManAdd);
137-
BENCHMARK(AddrManSelect);
138-
BENCHMARK(AddrManGetAddr);
139-
BENCHMARK(AddrManAddThenGood);
136+
BENCHMARK(AddrManAdd, benchmark::PriorityLevel::HIGH);
137+
BENCHMARK(AddrManSelect, benchmark::PriorityLevel::HIGH);
138+
BENCHMARK(AddrManGetAddr, benchmark::PriorityLevel::HIGH);
139+
BENCHMARK(AddrManAddThenGood, benchmark::PriorityLevel::HIGH);

src/bench/base58.cpp

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,6 @@ static void Base58Decode(benchmark::Bench& bench)
5050
}
5151

5252

53-
BENCHMARK(Base58Encode);
54-
BENCHMARK(Base58CheckEncode);
55-
BENCHMARK(Base58Decode);
53+
BENCHMARK(Base58Encode, benchmark::PriorityLevel::HIGH);
54+
BENCHMARK(Base58CheckEncode, benchmark::PriorityLevel::HIGH);
55+
BENCHMARK(Base58Decode, benchmark::PriorityLevel::HIGH);

src/bench/bech32.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -32,5 +32,5 @@ static void Bech32Decode(benchmark::Bench& bench)
3232
}
3333

3434

35-
BENCHMARK(Bech32Encode);
36-
BENCHMARK(Bech32Decode);
35+
BENCHMARK(Bech32Encode, benchmark::PriorityLevel::HIGH);
36+
BENCHMARK(Bech32Decode, benchmark::PriorityLevel::HIGH);

src/bench/bench.cpp

Lines changed: 44 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66

77
#include <fs.h>
88
#include <test/util/setup_common.h>
9+
#include <util/string.h>
910

1011
#include <chrono>
1112
#include <fstream>
@@ -41,18 +42,42 @@ void GenerateTemplateResults(const std::vector<ankerl::nanobench::Result>& bench
4142

4243
} // namespace
4344

44-
benchmark::BenchRunner::BenchmarkMap& benchmark::BenchRunner::benchmarks()
45+
namespace benchmark {
46+
47+
// map a label to one or multiple priority levels
48+
std::map<std::string, uint8_t> map_label_priority = {
49+
{"high", PriorityLevel::HIGH},
50+
{"low", PriorityLevel::LOW},
51+
{"all", 0xff}
52+
};
53+
54+
std::string ListPriorities()
4555
{
46-
static std::map<std::string, BenchFunction> benchmarks_map;
56+
using item_t = std::pair<std::string, uint8_t>;
57+
auto sort_by_priority = [](item_t a, item_t b){ return a.second < b.second; };
58+
std::set<item_t, decltype(sort_by_priority)> sorted_priorities(map_label_priority.begin(), map_label_priority.end(), sort_by_priority);
59+
return Join(sorted_priorities, ',', [](const auto& entry){ return entry.first; });
60+
}
61+
62+
uint8_t StringToPriority(const std::string& str)
63+
{
64+
auto it = map_label_priority.find(str);
65+
if (it == map_label_priority.end()) throw std::runtime_error(strprintf("Unknown priority level %s", str));
66+
return it->second;
67+
}
68+
69+
BenchRunner::BenchmarkMap& BenchRunner::benchmarks()
70+
{
71+
static BenchmarkMap benchmarks_map;
4772
return benchmarks_map;
4873
}
4974

50-
benchmark::BenchRunner::BenchRunner(std::string name, benchmark::BenchFunction func)
75+
BenchRunner::BenchRunner(std::string name, BenchFunction func, PriorityLevel level)
5176
{
52-
benchmarks().insert(std::make_pair(name, func));
77+
benchmarks().insert(std::make_pair(name, std::make_pair(func, level)));
5378
}
5479

55-
void benchmark::BenchRunner::RunAll(const Args& args)
80+
void BenchRunner::RunAll(const Args& args)
5681
{
5782
std::regex reFilter(args.regex_filter);
5883
std::smatch baseMatch;
@@ -62,33 +87,39 @@ void benchmark::BenchRunner::RunAll(const Args& args)
6287
}
6388

6489
std::vector<ankerl::nanobench::Result> benchmarkResults;
65-
for (const auto& p : benchmarks()) {
66-
if (!std::regex_match(p.first, baseMatch, reFilter)) {
90+
for (const auto& [name, bench_func] : benchmarks()) {
91+
const auto& [func, priority_level] = bench_func;
92+
93+
if (!(priority_level & args.priority)) {
94+
continue;
95+
}
96+
97+
if (!std::regex_match(name, baseMatch, reFilter)) {
6798
continue;
6899
}
69100

70101
if (args.is_list_only) {
71-
std::cout << p.first << std::endl;
102+
std::cout << name << std::endl;
72103
continue;
73104
}
74105

75106
Bench bench;
76107
if (args.sanity_check) {
77108
bench.epochs(1).epochIterations(1);
78109
}
79-
bench.name(p.first);
110+
bench.name(name);
80111
if (args.min_time > 0ms) {
81112
// convert to nanos before dividing to reduce rounding errors
82113
std::chrono::nanoseconds min_time_ns = args.min_time;
83114
bench.minEpochTime(min_time_ns / bench.epochs());
84115
}
85116

86117
if (args.asymptote.empty()) {
87-
p.second(bench);
118+
func(bench);
88119
} else {
89120
for (auto n : args.asymptote) {
90121
bench.complexityN(n);
91-
p.second(bench);
122+
func(bench);
92123
}
93124
std::cout << bench.complexityBigO() << std::endl;
94125
}
@@ -103,3 +134,5 @@ void benchmark::BenchRunner::RunAll(const Args& args)
103134
"{{/result}}");
104135
GenerateTemplateResults(benchmarkResults, args.output_json, ankerl::nanobench::templates::json());
105136
}
137+
138+
} // namespace benchmark

src/bench/bench.h

Lines changed: 17 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,16 @@ using ankerl::nanobench::Bench;
4141

4242
typedef std::function<void(Bench&)> BenchFunction;
4343

44+
enum PriorityLevel : uint8_t
45+
{
46+
LOW = 1 << 0,
47+
HIGH = 1 << 2,
48+
};
49+
50+
// List priority labels, comma-separated and sorted by increasing priority
51+
std::string ListPriorities();
52+
uint8_t StringToPriority(const std::string& str);
53+
4454
struct Args {
4555
bool is_list_only;
4656
bool sanity_check;
@@ -49,22 +59,24 @@ struct Args {
4959
fs::path output_csv;
5060
fs::path output_json;
5161
std::string regex_filter;
62+
uint8_t priority;
5263
};
5364

5465
class BenchRunner
5566
{
56-
typedef std::map<std::string, BenchFunction> BenchmarkMap;
67+
// maps from "name" -> (function, priority_level)
68+
typedef std::map<std::string, std::pair<BenchFunction, PriorityLevel>> BenchmarkMap;
5769
static BenchmarkMap& benchmarks();
5870

5971
public:
60-
BenchRunner(std::string name, BenchFunction func);
72+
BenchRunner(std::string name, BenchFunction func, PriorityLevel level);
6173

6274
static void RunAll(const Args& args);
6375
};
6476
} // namespace benchmark
6577

66-
// BENCHMARK(foo) expands to: benchmark::BenchRunner bench_11foo("foo", foo);
67-
#define BENCHMARK(n) \
68-
benchmark::BenchRunner PASTE2(bench_, PASTE2(__LINE__, n))(STRINGIZE(n), n);
78+
// BENCHMARK(foo) expands to: benchmark::BenchRunner bench_11foo("foo", foo, priority_level);
79+
#define BENCHMARK(n, priority_level) \
80+
benchmark::BenchRunner PASTE2(bench_, PASTE2(__LINE__, n))(STRINGIZE(n), n, priority_level);
6981

7082
#endif // BITCOIN_BENCH_BENCH_H

src/bench/bench_bitcoin.cpp

Lines changed: 28 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,8 @@
1818

1919
static const char* DEFAULT_BENCH_FILTER = ".*";
2020
static constexpr int64_t DEFAULT_MIN_TIME_MS{10};
21+
/** Priority level default value, run "all" priority levels */
22+
static const std::string DEFAULT_PRIORITY{"all"};
2123

2224
static void SetupBenchArgs(ArgsManager& argsman)
2325
{
@@ -30,6 +32,8 @@ static void SetupBenchArgs(ArgsManager& argsman)
3032
argsman.AddArg("-output-csv=<output.csv>", "Generate CSV file with the most important benchmark results", ArgsManager::ALLOW_ANY, OptionsCategory::OPTIONS);
3133
argsman.AddArg("-output-json=<output.json>", "Generate JSON file with all benchmark results", ArgsManager::ALLOW_ANY, OptionsCategory::OPTIONS);
3234
argsman.AddArg("-sanity-check", "Run benchmarks for only one iteration", ArgsManager::ALLOW_ANY, OptionsCategory::OPTIONS);
35+
argsman.AddArg("-priority-level=<l1,l2,l3>", strprintf("Run benchmarks of one or multiple priority level(s) (%s), default: '%s'",
36+
benchmark::ListPriorities(), DEFAULT_PRIORITY), ArgsManager::ALLOW_ANY, OptionsCategory::OPTIONS);
3337
}
3438

3539
// parses a comma separated list like "10,20,30,50"
@@ -45,6 +49,14 @@ static std::vector<double> parseAsymptote(const std::string& str) {
4549
return numbers;
4650
}
4751

52+
static uint8_t parsePriorityLevel(const std::string& str) {
53+
uint8_t levels{0};
54+
for (const auto& level: SplitString(str, ',')) {
55+
levels |= benchmark::StringToPriority(level);
56+
}
57+
return levels;
58+
}
59+
4860
int main(int argc, char** argv)
4961
{
5062
ArgsManager argsman;
@@ -106,16 +118,22 @@ int main(int argc, char** argv)
106118
return EXIT_SUCCESS;
107119
}
108120

109-
benchmark::Args args;
110-
args.asymptote = parseAsymptote(argsman.GetArg("-asymptote", ""));
111-
args.is_list_only = argsman.GetBoolArg("-list", false);
112-
args.min_time = std::chrono::milliseconds(argsman.GetIntArg("-min-time", DEFAULT_MIN_TIME_MS));
113-
args.output_csv = argsman.GetPathArg("-output-csv");
114-
args.output_json = argsman.GetPathArg("-output-json");
115-
args.regex_filter = argsman.GetArg("-filter", DEFAULT_BENCH_FILTER);
116-
args.sanity_check = argsman.GetBoolArg("-sanity-check", false);
121+
try {
122+
benchmark::Args args;
123+
args.asymptote = parseAsymptote(argsman.GetArg("-asymptote", ""));
124+
args.is_list_only = argsman.GetBoolArg("-list", false);
125+
args.min_time = std::chrono::milliseconds(argsman.GetIntArg("-min-time", DEFAULT_MIN_TIME_MS));
126+
args.output_csv = argsman.GetPathArg("-output-csv");
127+
args.output_json = argsman.GetPathArg("-output-json");
128+
args.regex_filter = argsman.GetArg("-filter", DEFAULT_BENCH_FILTER);
129+
args.sanity_check = argsman.GetBoolArg("-sanity-check", false);
130+
args.priority = parsePriorityLevel(argsman.GetArg("-priority-level", DEFAULT_PRIORITY));
117131

118-
benchmark::BenchRunner::RunAll(args);
132+
benchmark::BenchRunner::RunAll(args);
119133

120-
return EXIT_SUCCESS;
134+
return EXIT_SUCCESS;
135+
} catch (const std::exception& e) {
136+
tfm::format(std::cerr, "Error: %s\n", e.what());
137+
return EXIT_FAILURE;
138+
}
121139
}

src/bench/block_assemble.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -47,4 +47,4 @@ static void AssembleBlock(benchmark::Bench& bench)
4747
});
4848
}
4949

50-
BENCHMARK(AssembleBlock);
50+
BENCHMARK(AssembleBlock, benchmark::PriorityLevel::HIGH);

src/bench/ccoins_caching.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -51,4 +51,4 @@ static void CCoinsCaching(benchmark::Bench& bench)
5151
ECC_Stop();
5252
}
5353

54-
BENCHMARK(CCoinsCaching);
54+
BENCHMARK(CCoinsCaching, benchmark::PriorityLevel::HIGH);

src/bench/chacha20.cpp

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,6 @@ static void CHACHA20_1MB(benchmark::Bench& bench)
3939
CHACHA20(bench, BUFFER_SIZE_LARGE);
4040
}
4141

42-
BENCHMARK(CHACHA20_64BYTES);
43-
BENCHMARK(CHACHA20_256BYTES);
44-
BENCHMARK(CHACHA20_1MB);
42+
BENCHMARK(CHACHA20_64BYTES, benchmark::PriorityLevel::HIGH);
43+
BENCHMARK(CHACHA20_256BYTES, benchmark::PriorityLevel::HIGH);
44+
BENCHMARK(CHACHA20_1MB, benchmark::PriorityLevel::HIGH);

0 commit comments

Comments
 (0)