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<const uint256&> (vector.tcc:572)
|         ->41.25% (576,064B) 0x969717: push_back (stl_vector.h:1427)
|           ->41.25% (576,064B) 0x969717: ComputeMerkleRoot(std::vector<uint256, std::allocator<uint256> >, 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<MerkleRoot(ankerl::nanobench::Bench&)::{lambda()

Co-authored-by: Hodlinator <172445034+hodlinator@users.noreply.github.com>
This commit is contained in:
Lőrinc 2025-05-14 14:32:08 +02:00
parent f0a2183108
commit 7fd47e0e56
No known key found for this signature in database
GPG Key ID: 669FFF0FFA477A76

View File

@ -7,21 +7,33 @@
#include <random.h>
#include <uint256.h>
#include <cassert>
#include <vector>
static void MerkleRoot(benchmark::Bench& bench)
{
FastRandomContext rng(true);
std::vector<uint256> leaves;
leaves.resize(9001);
for (auto& item : leaves) {
FastRandomContext rng{/*fDeterministic=*/true};
std::vector<uint256> 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<uint256>(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<uint256> 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);