Files
bitcoin/src/bench/addrman.cpp
Lőrinc 8825051e08 refactor: improve benchmark setup and execution for various tests
Note that `make_hard_case` already clears the UTXO pool in `coin_selection.cpp`.

./build/bin/bench_bitcoin -filter='^(BnBExhaustion|AddrManAddThenGood|DeserializeBlockTest|DeserializeAndCheckBlockTest|CheckBlockTest|LoadExternalBlockFile|FindByte|WalletCreatePlain|WalletCreateEncrypted|WalletLoadingDescriptors)$'

|               ns/op |                op/s |    err% |     total | benchmark
|--------------------:|--------------------:|--------:|----------:|:----------
|       15,088,500.00 |               66.28 |    0.2% |      0.17 | `AddrManAddThenGood`
|          179,208.00 |            5,580.11 |    2.0% |      0.00 | `BnBExhaustion`

|            ns/block |             block/s |    err% |     total | benchmark
|--------------------:|--------------------:|--------:|----------:|:----------
|          318,166.00 |            3,143.01 |    3.5% |      0.00 | `CheckBlockTest`
|          886,750.00 |            1,127.71 |    0.8% |      0.01 | `DeserializeBlockTest`

|               ns/op |                op/s |    err% |     total | benchmark
|--------------------:|--------------------:|--------:|----------:|:----------
|               42.00 |       23,809,523.81 |    2.4% |      0.00 | `FindByte`
|        5,473,208.00 |              182.71 |    0.4% |      0.06 | `LoadExternalBlockFile`
|      584,168,041.00 |                1.71 |    0.3% |      6.43 | `WalletCreateEncrypted`
|      168,040,458.00 |                5.95 |    1.1% |      1.85 | `WalletCreatePlain`
|      155,446,625.00 |                6.43 |    0.7% |      0.78 | `WalletLoadingDescriptors`

|               ns/op |                op/s |    err% |     total | benchmark
|--------------------:|--------------------:|--------:|----------:|:----------
|       14,894,917.00 |               67.14 |    0.3% |      0.16 | `AddrManAddThenGood`
|          177,667.00 |            5,628.51 |    1.3% |      0.00 | `BnBExhaustion`

|            ns/block |             block/s |    err% |     total | benchmark
|--------------------:|--------------------:|--------:|----------:|:----------
|          313,791.00 |            3,186.83 |    3.8% |      0.00 | `CheckBlockTest`
|          888,208.00 |            1,125.86 |    0.7% |      0.01 | `DeserializeBlockTest`

|               ns/op |                op/s |    err% |     total | benchmark
|--------------------:|--------------------:|--------:|----------:|:----------
|               41.00 |       24,390,243.90 |    2.4% |      0.00 | `FindByte`
|        5,445,208.00 |              183.65 |    1.0% |      0.06 | `LoadExternalBlockFile`
|      581,800,500.00 |                1.72 |    0.4% |      6.40 | `WalletCreateEncrypted`
|      166,035,583.00 |                6.02 |    0.5% |      1.82 | `WalletCreatePlain`
|      153,574,792.00 |                6.51 |    0.1% |      0.77 | `WalletLoadingDescriptors`
2026-03-08 12:02:18 +00:00

179 lines
5.0 KiB
C++

// Copyright (c) 2020-present The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
#include <addrman.h>
#include <bench/bench.h>
#include <compat/compat.h>
#include <netaddress.h>
#include <netbase.h>
#include <netgroup.h>
#include <protocol.h>
#include <random.h>
#include <span.h>
#include <uint256.h>
#include <util/check.h>
#include <util/time.h>
#include <cstring>
#include <optional>
#include <vector>
/* A "source" is a source address from which we have received a bunch of other addresses. */
static constexpr size_t NUM_SOURCES = 64;
static constexpr size_t NUM_ADDRESSES_PER_SOURCE = 256;
static auto EMPTY_NETGROUPMAN{NetGroupManager::NoAsmap()};
static constexpr uint32_t ADDRMAN_CONSISTENCY_CHECK_RATIO{0};
static std::vector<CAddress> g_sources;
static std::vector<std::vector<CAddress>> g_addresses;
static void CreateAddresses()
{
if (g_sources.size() > 0) { // already created
return;
}
FastRandomContext rng(uint256(std::vector<unsigned char>(32, 123)));
auto randAddr = [&rng]() {
in6_addr addr;
memcpy(&addr, rng.randbytes(sizeof(addr)).data(), sizeof(addr));
uint16_t port;
memcpy(&port, rng.randbytes(sizeof(port)).data(), sizeof(port));
if (port == 0) {
port = 1;
}
CAddress ret(CService(addr, port), NODE_NETWORK);
ret.nTime = Now<NodeSeconds>();
return ret;
};
for (size_t source_i = 0; source_i < NUM_SOURCES; ++source_i) {
g_sources.emplace_back(randAddr());
g_addresses.emplace_back();
for (size_t addr_i = 0; addr_i < NUM_ADDRESSES_PER_SOURCE; ++addr_i) {
g_addresses[source_i].emplace_back(randAddr());
}
}
}
static void AddAddressesToAddrMan(AddrMan& addrman)
{
for (size_t source_i = 0; source_i < NUM_SOURCES; ++source_i) {
addrman.Add(g_addresses[source_i], g_sources[source_i]);
}
}
static void FillAddrMan(AddrMan& addrman)
{
CreateAddresses();
AddAddressesToAddrMan(addrman);
}
/* Benchmarks */
static void AddrManAdd(benchmark::Bench& bench)
{
CreateAddresses();
bench.run([&] {
AddrMan addrman{EMPTY_NETGROUPMAN, /*deterministic=*/false, ADDRMAN_CONSISTENCY_CHECK_RATIO};
AddAddressesToAddrMan(addrman);
});
}
static void AddrManSelect(benchmark::Bench& bench)
{
AddrMan addrman{EMPTY_NETGROUPMAN, /*deterministic=*/false, ADDRMAN_CONSISTENCY_CHECK_RATIO};
FillAddrMan(addrman);
bench.run([&] {
const auto& address = addrman.Select();
assert(address.first.GetPort() > 0);
});
}
// The worst case performance of the Select() function is when there is only
// one address on the table, because it linearly searches every position of
// several buckets before identifying the correct bucket
static void AddrManSelectFromAlmostEmpty(benchmark::Bench& bench)
{
AddrMan addrman{EMPTY_NETGROUPMAN, /*deterministic=*/false, ADDRMAN_CONSISTENCY_CHECK_RATIO};
// Add one address to the new table
CService addr = Lookup("250.3.1.1", 8333, false).value();
addrman.Add({CAddress(addr, NODE_NONE)}, addr);
bench.run([&] {
(void)addrman.Select();
});
}
static void AddrManSelectByNetwork(benchmark::Bench& bench)
{
AddrMan addrman{EMPTY_NETGROUPMAN, /*deterministic=*/false, ADDRMAN_CONSISTENCY_CHECK_RATIO};
// add single I2P address to new table
CService i2p_service;
i2p_service.SetSpecial("udhdrtrcetjm5sxzskjyr5ztpeszydbh4dpl3pl4utgqqw2v4jna.b32.i2p");
CAddress i2p_address(i2p_service, NODE_NONE);
i2p_address.nTime = Now<NodeSeconds>();
const CNetAddr source{LookupHost("252.2.2.2", false).value()};
addrman.Add({i2p_address}, source);
FillAddrMan(addrman);
bench.run([&] {
(void)addrman.Select(/*new_only=*/false, {NET_I2P});
});
}
static void AddrManGetAddr(benchmark::Bench& bench)
{
AddrMan addrman{EMPTY_NETGROUPMAN, /*deterministic=*/false, ADDRMAN_CONSISTENCY_CHECK_RATIO};
FillAddrMan(addrman);
bench.run([&] {
const auto& addresses = addrman.GetAddr(/*max_addresses=*/2500, /*max_pct=*/23, /*network=*/std::nullopt);
assert(addresses.size() > 0);
});
}
static void AddrManAddThenGood(benchmark::Bench& bench)
{
auto markSomeAsGood = [](AddrMan& addrman) {
for (size_t source_i = 0; source_i < NUM_SOURCES; ++source_i) {
for (size_t addr_i = 0; addr_i < NUM_ADDRESSES_PER_SOURCE; ++addr_i) {
addrman.Good(g_addresses[source_i][addr_i]);
}
}
};
CreateAddresses();
std::optional<AddrMan> addrman;
bench.epochIterations(1)
.setup([&] {
addrman.emplace(EMPTY_NETGROUPMAN, /*deterministic=*/false, ADDRMAN_CONSISTENCY_CHECK_RATIO);
AddAddressesToAddrMan(*addrman);
})
.run([&] { markSomeAsGood(*addrman); });
}
BENCHMARK(AddrManAdd);
BENCHMARK(AddrManSelect);
BENCHMARK(AddrManSelectFromAlmostEmpty);
BENCHMARK(AddrManSelectByNetwork);
BENCHMARK(AddrManGetAddr);
BENCHMARK(AddrManAddThenGood);