From 7fd47e0e56087cd3b5fd76a532bdc3ac331e832e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?L=C5=91rinc?= Date: Wed, 14 May 2025 14:32:08 +0200 Subject: [PATCH] bench: make `MerkleRoot` benchmark more representative Two versions are run now, one with the mutation calculations, the other without. To avoid unwanted compiler optimizations, we assert the expected hash, which should inhibit aggressive optimization. To make the benchmark more similar to production `ComputeMerkleRoot` call sites, the input leaves-copying is made explicit before each run. > ./build/bin/bench_bitcoin -filter='MerkleRoot.*' -min-time=1000 | ns/leaf | leaf/s | err% | total | benchmark |--------------------:|--------------------:|--------:|----------:|:---------- | 44.18 | 22,634,858.70 | 0.0% | 1.10 | `MerkleRoot` | 44.66 | 22,390,601.03 | 0.0% | 1.10 | `MerkleRootWithMutation` Massif memory measurements show the excessive memory reservations: MB 1.332^ : | # : | # : | # : | # : | # @ : | # @ : | # @ : | # @ : | # @ : | # @ : | # @ : | # @ : | #::::@::::::::::::::::::::::::::::::::::::::::::::::::::::::@:::::@:::: | #: ::@::::: :::::::: :: ::: :::::: : : :: ::: ::: : : : ::::@:::::@:::: | #: ::@::::: :::::::: :: ::: :::::: : : :: ::: ::: : : : ::::@:::::@:::: | #: ::@::::: :::::::: :: ::: :::::: : : :: ::: ::: : : : ::::@:::::@:::: | #: ::@::::: :::::::: :: ::: :::::: : : :: ::: ::: : : : ::::@:::::@:::: | #: ::@::::: :::::::: :: ::: :::::: : : :: ::: ::: : : : ::::@:::::@:::: | #: ::@::::: :::::::: :: ::: :::::: : : :: ::: ::: : : : ::::@:::::@:::: 0 +----------------------------------------------------------------------->s 0 226.2 showing the reallocations clearly in the stacks: 97.87% (1,366,841B) (heap allocation functions) malloc/new/new[], --alloc-fns, etc. ->41.25% (576,064B) 0x969717: allocate (new_allocator.h:151) | ->41.25% (576,064B) 0x969717: allocate (allocator.h:203) | ->41.25% (576,064B) 0x969717: allocate (alloc_traits.h:614) | ->41.25% (576,064B) 0x969717: _M_allocate (stl_vector.h:387) | ->41.25% (576,064B) 0x969717: _M_realloc_append (vector.tcc:572) | ->41.25% (576,064B) 0x969717: push_back (stl_vector.h:1427) | ->41.25% (576,064B) 0x969717: ComputeMerkleRoot(std::vector >, bool*) (merkle.cpp:55) | ->41.25% (576,064B) 0x2235A7: operator() (merkle_root.cpp:31) | ->41.25% (576,064B) 0x2235A7: ankerl::nanobench::Bench& ankerl::nanobench::Bench::run --- src/bench/merkle_root.cpp | 30 +++++++++++++++++++++--------- 1 file changed, 21 insertions(+), 9 deletions(-) diff --git a/src/bench/merkle_root.cpp b/src/bench/merkle_root.cpp index 98ce197ea58..5be592707ff 100644 --- a/src/bench/merkle_root.cpp +++ b/src/bench/merkle_root.cpp @@ -7,21 +7,33 @@ #include #include +#include #include static void MerkleRoot(benchmark::Bench& bench) { - FastRandomContext rng(true); - std::vector leaves; - leaves.resize(9001); - for (auto& item : leaves) { + FastRandomContext rng{/*fDeterministic=*/true}; + + std::vector hashes{}; + hashes.resize(9001); + for (auto& item : hashes) { item = rng.rand256(); } - bench.batch(leaves.size()).unit("leaf").run([&] { - bool mutation = false; - uint256 hash = ComputeMerkleRoot(std::vector(leaves), &mutation); - leaves[mutation] = hash; - }); + + constexpr uint256 expected_root{"d8d4dfd014a533bc3941b8663fa6e7f3a8707af124f713164d75b0c3179ecb08"}; + for (bool mutate : {false, true}) { + bench.name(mutate ? "MerkleRootWithMutation" : "MerkleRoot").batch(hashes.size()).unit("leaf").run([&] { + std::vector leaves; + leaves.resize(hashes.size()); + for (size_t s = 0; s < hashes.size(); s++) { + leaves[s] = hashes[s]; + } + + bool mutated{false}; + const uint256 root{ComputeMerkleRoot(std::move(leaves), mutate ? &mutated : nullptr)}; + assert(root == expected_root); + }); + } } BENCHMARK(MerkleRoot, benchmark::PriorityLevel::HIGH);