Bitcoin Core  24.99.0
P2P Digital Currency
addrman.cpp
Go to the documentation of this file.
1 // Copyright (c) 2020-2021 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 <netgroup.h>
8 #include <random.h>
9 #include <util/check.h>
10 #include <util/time.h>
11 
12 #include <optional>
13 #include <vector>
14 
15 /* A "source" is a source address from which we have received a bunch of other addresses. */
16 
17 static constexpr size_t NUM_SOURCES = 64;
18 static constexpr size_t NUM_ADDRESSES_PER_SOURCE = 256;
19 
20 static NetGroupManager EMPTY_NETGROUPMAN{std::vector<bool>()};
21 static constexpr uint32_t ADDRMAN_CONSISTENCY_CHECK_RATIO{0};
22 
23 static std::vector<CAddress> g_sources;
24 static std::vector<std::vector<CAddress>> g_addresses;
25 
26 static void CreateAddresses()
27 {
28  if (g_sources.size() > 0) { // already created
29  return;
30  }
31 
32  FastRandomContext rng(uint256(std::vector<unsigned char>(32, 123)));
33 
34  auto randAddr = [&rng]() {
35  in6_addr addr;
36  memcpy(&addr, rng.randbytes(sizeof(addr)).data(), sizeof(addr));
37 
38  uint16_t port;
39  memcpy(&port, rng.randbytes(sizeof(port)).data(), sizeof(port));
40  if (port == 0) {
41  port = 1;
42  }
43 
44  CAddress ret(CService(addr, port), NODE_NETWORK);
45 
46  ret.nTime = Now<NodeSeconds>();
47 
48  return ret;
49  };
50 
51  for (size_t source_i = 0; source_i < NUM_SOURCES; ++source_i) {
52  g_sources.emplace_back(randAddr());
53  g_addresses.emplace_back();
54  for (size_t addr_i = 0; addr_i < NUM_ADDRESSES_PER_SOURCE; ++addr_i) {
55  g_addresses[source_i].emplace_back(randAddr());
56  }
57  }
58 }
59 
60 static void AddAddressesToAddrMan(AddrMan& addrman)
61 {
62  for (size_t source_i = 0; source_i < NUM_SOURCES; ++source_i) {
63  addrman.Add(g_addresses[source_i], g_sources[source_i]);
64  }
65 }
66 
67 static void FillAddrMan(AddrMan& addrman)
68 {
70 
71  AddAddressesToAddrMan(addrman);
72 }
73 
74 /* Benchmarks */
75 
76 static void AddrManAdd(benchmark::Bench& bench)
77 {
79 
80  bench.run([&] {
81  AddrMan addrman{EMPTY_NETGROUPMAN, /*deterministic=*/false, ADDRMAN_CONSISTENCY_CHECK_RATIO};
82  AddAddressesToAddrMan(addrman);
83  });
84 }
85 
86 static void AddrManSelect(benchmark::Bench& bench)
87 {
88  AddrMan addrman{EMPTY_NETGROUPMAN, /*deterministic=*/false, ADDRMAN_CONSISTENCY_CHECK_RATIO};
89 
90  FillAddrMan(addrman);
91 
92  bench.run([&] {
93  const auto& address = addrman.Select();
94  assert(address.first.GetPort() > 0);
95  });
96 }
97 
98 static void AddrManGetAddr(benchmark::Bench& bench)
99 {
100  AddrMan addrman{EMPTY_NETGROUPMAN, /*deterministic=*/false, ADDRMAN_CONSISTENCY_CHECK_RATIO};
101 
102  FillAddrMan(addrman);
103 
104  bench.run([&] {
105  const auto& addresses = addrman.GetAddr(/*max_addresses=*/2500, /*max_pct=*/23, /*network=*/std::nullopt);
106  assert(addresses.size() > 0);
107  });
108 }
109 
111 {
112  auto markSomeAsGood = [](AddrMan& addrman) {
113  for (size_t source_i = 0; source_i < NUM_SOURCES; ++source_i) {
114  for (size_t addr_i = 0; addr_i < NUM_ADDRESSES_PER_SOURCE; ++addr_i) {
115  addrman.Good(g_addresses[source_i][addr_i]);
116  }
117  }
118  };
119 
120  CreateAddresses();
121 
122  bench.run([&] {
123  // To make the benchmark independent of the number of evaluations, we always prepare a new addrman.
124  // This is necessary because AddrMan::Good() method modifies the object, affecting the timing of subsequent calls
125  // to the same method and we want to do the same amount of work in every loop iteration.
126  //
127  // This has some overhead (exactly the result of AddrManAdd benchmark), but that overhead is constant so improvements in
128  // AddrMan::Good() will still be noticeable.
129  AddrMan addrman{EMPTY_NETGROUPMAN, /*deterministic=*/false, ADDRMAN_CONSISTENCY_CHECK_RATIO};
130  AddAddressesToAddrMan(addrman);
131 
132  markSomeAsGood(addrman);
133  });
134 }
135 
static NetGroupManager EMPTY_NETGROUPMAN
Definition: addrman.cpp:20
static void FillAddrMan(AddrMan &addrman)
Definition: addrman.cpp:67
static void AddrManSelect(benchmark::Bench &bench)
Definition: addrman.cpp:86
static void AddrManAddThenGood(benchmark::Bench &bench)
Definition: addrman.cpp:110
static constexpr size_t NUM_SOURCES
Definition: addrman.cpp:17
BENCHMARK(AddrManAdd)
static constexpr uint32_t ADDRMAN_CONSISTENCY_CHECK_RATIO
Definition: addrman.cpp:21
static std::vector< CAddress > g_sources
Definition: addrman.cpp:23
static void AddrManGetAddr(benchmark::Bench &bench)
Definition: addrman.cpp:98
static constexpr size_t NUM_ADDRESSES_PER_SOURCE
Definition: addrman.cpp:18
static void CreateAddresses()
Definition: addrman.cpp:26
static void AddAddressesToAddrMan(AddrMan &addrman)
Definition: addrman.cpp:60
static void AddrManAdd(benchmark::Bench &bench)
Definition: addrman.cpp:76
static std::vector< std::vector< CAddress > > g_addresses
Definition: addrman.cpp:24
int ret
Stochastic address manager.
Definition: addrman.h:87
bool Add(const std::vector< CAddress > &vAddr, const CNetAddr &source, std::chrono::seconds time_penalty=0s)
Attempt to add one or more addresses to addrman's new table.
Definition: addrman.cpp:1194
A CService with information about it as peer.
Definition: protocol.h:355
A combination of a network address (CNetAddr) and a (TCP) port.
Definition: netaddress.h:521
Fast randomness source.
Definition: random.h:143
std::vector< unsigned char > randbytes(size_t len)
Generate random bytes.
Definition: random.cpp:617
Netgroup manager.
Definition: netgroup.h:16
Main entry point to nanobench's benchmarking facility.
Definition: nanobench.h:616
Bench & run(char const *benchmarkName, Op &&op)
Repeatedly calls op() based on the configuration, and performs measurements.
Definition: nanobench.h:1183
256-bit opaque blob.
Definition: uint256.h:119
@ NODE_NETWORK
Definition: protocol.h:273
assert(!tx.IsCoinBase())