1 // Copyright (c) 2020-2020 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 <addrman.h>
6 #include <bench/bench.h>
7 #include <random.h>
8 #include <util/time.h>
9
10 #include <optional>
11 #include <vector>
12
13 /* A "source" is a source address from which we have received a bunch of other addresses. */
14
15 static constexpr size_t NUM_SOURCES = 64;
16 static constexpr size_t NUM_ADDRESSES_PER_SOURCE = 256;
17
18 static std::vector<CAddress> g_sources;
19 static std::vector<std::vector<CAddress>> g_addresses;
20
CreateAddresses()21 static void CreateAddresses()
22 {
23 if (g_sources.size() > 0) { // already created
24 return;
25 }
26
27 FastRandomContext rng(uint256(std::vector<unsigned char>(32, 123)));
28
29 auto randAddr = [&rng]() {
30 in6_addr addr;
31 memcpy(&addr, rng.randbytes(sizeof(addr)).data(), sizeof(addr));
32
33 uint16_t port;
34 memcpy(&port, rng.randbytes(sizeof(port)).data(), sizeof(port));
35 if (port == 0) {
36 port = 1;
37 }
38
39 CAddress ret(CService(addr, port), NODE_NETWORK);
40
41 ret.nTime = GetAdjustedTime();
42
43 return ret;
44 };
45
46 for (size_t source_i = 0; source_i < NUM_SOURCES; ++source_i) {
47 g_sources.emplace_back(randAddr());
48 g_addresses.emplace_back();
49 for (size_t addr_i = 0; addr_i < NUM_ADDRESSES_PER_SOURCE; ++addr_i) {
50 g_addresses[source_i].emplace_back(randAddr());
51 }
52 }
53 }
54
AddAddressesToAddrMan(CAddrMan & addrman)55 static void AddAddressesToAddrMan(CAddrMan& addrman)
56 {
57 for (size_t source_i = 0; source_i < NUM_SOURCES; ++source_i) {
58 addrman.Add(g_addresses[source_i], g_sources[source_i]);
59 }
60 }
61
FillAddrMan(CAddrMan & addrman)62 static void FillAddrMan(CAddrMan& addrman)
63 {
64 CreateAddresses();
65
66 AddAddressesToAddrMan(addrman);
67 }
68
69 /* Benchmarks */
70
AddrManAdd(benchmark::Bench & bench)71 static void AddrManAdd(benchmark::Bench& bench)
72 {
73 CreateAddresses();
74
75 CAddrMan addrman;
76
77 bench.run([&] {
78 AddAddressesToAddrMan(addrman);
79 addrman.Clear();
80 });
81 }
82
AddrManSelect(benchmark::Bench & bench)83 static void AddrManSelect(benchmark::Bench& bench)
84 {
85 CAddrMan addrman;
86
87 FillAddrMan(addrman);
88
89 bench.run([&] {
90 const auto& address = addrman.Select();
91 assert(address.GetPort() > 0);
92 });
93 }
94
AddrManGetAddr(benchmark::Bench & bench)95 static void AddrManGetAddr(benchmark::Bench& bench)
96 {
97 CAddrMan addrman;
98
99 FillAddrMan(addrman);
100
101 bench.run([&] {
102 const auto& addresses = addrman.GetAddr(/* max_addresses */ 2500, /* max_pct */ 23, /* network */ std::nullopt);
103 assert(addresses.size() > 0);
104 });
105 }
106
AddrManGood(benchmark::Bench & bench)107 static void AddrManGood(benchmark::Bench& bench)
108 {
109 /* Create many CAddrMan objects - one to be modified at each loop iteration.
110 * This is necessary because the CAddrMan::Good() method modifies the
111 * object, affecting the timing of subsequent calls to the same method and
112 * we want to do the same amount of work in every loop iteration. */
113
114 bench.epochs(5).epochIterations(1);
115
116 std::vector<CAddrMan> addrmans(bench.epochs() * bench.epochIterations());
117 for (auto& addrman : addrmans) {
118 FillAddrMan(addrman);
119 }
120
121 auto markSomeAsGood = [](CAddrMan& addrman) {
122 for (size_t source_i = 0; source_i < NUM_SOURCES; ++source_i) {
123 for (size_t addr_i = 0; addr_i < NUM_ADDRESSES_PER_SOURCE; ++addr_i) {
124 if (addr_i % 32 == 0) {
125 addrman.Good(g_addresses[source_i][addr_i]);
126 }
127 }
128 }
129 };
130
131 uint64_t i = 0;
132 bench.run([&] {
133 markSomeAsGood(addrmans.at(i));
134 ++i;
135 });
136 }
137
138 BENCHMARK(AddrManAdd);
139 BENCHMARK(AddrManSelect);
140 BENCHMARK(AddrManGetAddr);
141 BENCHMARK(AddrManGood);
142