Bitcoin Core 31.99.0
P2P Digital Currency
txgraph.cpp
Go to the documentation of this file.
1// Copyright (c) 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 <bench/bench.h>
6#include <random.h>
7#include <txgraph.h>
8#include <util/check.h>
9#include <util/feefrac.h>
10
11#include <algorithm>
12#include <compare>
13#include <cstddef>
14#include <cstdint>
15#include <functional>
16#include <memory>
17#include <utility>
18#include <vector>
19
20namespace {
21
22std::strong_ordering PointerComparator(const TxGraph::Ref& a, const TxGraph::Ref& b) noexcept
23{
24 return (&a) <=> (&b);
25}
26
27void BenchTxGraphTrim(benchmark::Bench& bench)
28{
29 // The from-block transactions consist of 1000 fully linear clusters, each with 64
30 // transactions. The mempool contains 11 transactions that together merge all of these into
31 // a single cluster.
32 //
33 // (1000 chains of 64 transactions, 64000 T's total)
34 //
35 // T T T T T T T T
36 // | | | | | | | |
37 // T T T T T T T T
38 // | | | | | | | |
39 // T T T T T T T T
40 // | | | | | | | |
41 // T T T T T T T T
42 // (64 long) (64 long) (64 long) (64 long) (64 long) (64 long) (64 long) (64 long)
43 // | | | | | | | |
44 // | | / \ | / \ | | /
45 // \----------+--------/ \--------+--------/ \--------+-----+----+--------/
46 // | | |
47 // B B B
48 //
49 // (11 B's, each attaching to up to 100 chains of 64 T's)
50 //
52 static constexpr int MAX_CLUSTER_COUNT = 64;
54 static constexpr int NUM_TOP_CHAINS = 1000;
56 static constexpr int NUM_TX_PER_TOP_CHAIN = MAX_CLUSTER_COUNT;
58 static constexpr int NUM_DEPS_PER_BOTTOM_TX = 100;
60 static constexpr int32_t MAX_CLUSTER_SIZE = 100'000 * 100;
63 static constexpr uint64_t HIGH_ACCEPTABLE_COST = 100'000'000;
64
66 std::vector<TxGraph::Ref> top_refs;
68 std::vector<TxGraph::Ref> bottom_refs;
72 std::vector<size_t> top_components;
73
75 auto graph = MakeTxGraph(MAX_CLUSTER_COUNT, MAX_CLUSTER_SIZE, HIGH_ACCEPTABLE_COST, PointerComparator);
76
77 // Construct the top chains.
78 for (int chain = 0; chain < NUM_TOP_CHAINS; ++chain) {
79 for (int chaintx = 0; chaintx < NUM_TX_PER_TOP_CHAIN; ++chaintx) {
80 int64_t fee = rng.randbits<27>() + 100;
81 FeePerWeight feerate{fee, 1};
82 graph->AddTransaction(top_refs.emplace_back(), feerate);
83 // Add internal dependencies linking the chain transactions together.
84 if (chaintx > 0) {
85 graph->AddDependency(*(top_refs.rbegin()), *(top_refs.rbegin() + 1));
86 }
87 }
88 // Remember the last transaction in each chain, to attach the bottom transactions to.
89 top_components.push_back(top_refs.size() - 1);
90 }
91
92 // Make the graph linearize all clusters acceptably.
93 graph->GetBlockBuilder();
94
95 // Construct the bottom transactions, and dependencies to the top chains.
96 while (top_components.size() > 1) {
97 // Construct the transaction.
98 int64_t fee = rng.randbits<27>() + 100;
99 FeePerWeight feerate{fee, 1};
100 TxGraph::Ref bottom_tx;
101 graph->AddTransaction(bottom_tx, feerate);
102 // Determine the number of dependencies this transaction will have.
103 int deps = std::min<int>(NUM_DEPS_PER_BOTTOM_TX, top_components.size());
104 for (int dep = 0; dep < deps; ++dep) {
105 // Pick an transaction in top_components to attach to.
106 auto idx = rng.randrange(top_components.size());
107 // Add dependency.
108 graph->AddDependency(/*parent=*/top_refs[top_components[idx]], /*child=*/bottom_tx);
109 // Unless this is the last dependency being added, remove from top_components, as
110 // the component will be merged with that one.
111 if (dep < deps - 1) {
112 // Move entry top the back.
113 if (idx != top_components.size() - 1) std::swap(top_components.back(), top_components[idx]);
114 // And pop it.
115 top_components.pop_back();
116 }
117 }
118 bottom_refs.push_back(std::move(bottom_tx));
119 }
120
121 // Run the benchmark exactly once. Running it multiple times would require the setup to be
122 // redone, which takes a very non-negligible time compared to the trimming itself.
123 bench.epochIterations(1).epochs(1).run([&] {
124 // Call Trim() to remove transactions and bring the cluster back within limits.
125 graph->Trim();
126 // And relinearize everything that remains acceptably.
127 graph->GetBlockBuilder();
128 });
129
130 assert(!graph->IsOversized(TxGraph::Level::TOP));
131 // At least 99% of chains must survive.
132 assert(graph->GetTransactionCount(TxGraph::Level::TOP) >= (NUM_TOP_CHAINS * NUM_TX_PER_TOP_CHAIN * 99) / 100);
133}
134
135} // namespace
136
137static void TxGraphTrim(benchmark::Bench& bench) { BenchTxGraphTrim(bench); }
138
static void TxGraphTrim(benchmark::Bench &bench)
Definition: txgraph.cpp:137
BENCHMARK(TxGraphTrim)
xoroshiro128++ PRNG.
Definition: random.h:425
I randrange(I range) noexcept
Generate a random integer in the range [0..range), with range > 0.
Definition: random.h:254
uint64_t randbits(int bits) noexcept
Generate a random (bits)-bit integer.
Definition: random.h:204
@ TOP
Refers to staging if it exists, main otherwise.
Main entry point to nanobench's benchmarking facility.
Definition: nanobench.h:649
Bench & run(char const *benchmarkName, Op &&op)
Repeatedly calls op() based on the configuration, and performs measurements.
Definition: nanobench.h:1308
Bench & epochs(size_t numEpochs) noexcept
Controls number of epochs, the number of measurements to perform.
Bench & epochIterations(uint64_t numIters) noexcept
Sets exactly the number of iterations for each epoch.
uint64_t fee
Tagged wrapper around FeeFrac to avoid unit confusion.
Definition: feefrac.h:192
FastRandomContext rng
Definition: dbwrapper.cpp:414
std::unique_ptr< TxGraph > MakeTxGraph(unsigned max_cluster_count, uint64_t max_cluster_size, uint64_t acceptable_cost, const std::function< std::strong_ordering(const TxGraph::Ref &, const TxGraph::Ref &)> &fallback_order) noexcept
Construct a new TxGraph with the specified limit on the number of transactions within a cluster,...
Definition: txgraph.cpp:3570
assert(!tx.IsCoinBase())