Bitcoin Core 32.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 <cstddef>
13#include <cstdint>
14#include <memory>
15#include <utility>
16#include <vector>
17
18namespace {
19
20std::strong_ordering PointerComparator(const TxGraph::Ref& a, const TxGraph::Ref& b) noexcept
21{
22 return (&a) <=> (&b);
23}
24
25void BenchTxGraphTrim(benchmark::Bench& bench)
26{
27 // The from-block transactions consist of 1000 fully linear clusters, each with 64
28 // transactions. The mempool contains 11 transactions that together merge all of these into
29 // a single cluster.
30 //
31 // (1000 chains of 64 transactions, 64000 T's total)
32 //
33 // T T T T T T T T
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 // (64 long) (64 long) (64 long) (64 long) (64 long) (64 long) (64 long) (64 long)
41 // | | | | | | | |
42 // | | / \ | / \ | | /
43 // \----------+--------/ \--------+--------/ \--------+-----+----+--------/
44 // | | |
45 // B B B
46 //
47 // (11 B's, each attaching to up to 100 chains of 64 T's)
48 //
50 static constexpr int MAX_CLUSTER_COUNT = 64;
52 static constexpr int NUM_TOP_CHAINS = 1000;
54 static constexpr int NUM_TX_PER_TOP_CHAIN = MAX_CLUSTER_COUNT;
56 static constexpr int NUM_DEPS_PER_BOTTOM_TX = 100;
58 static constexpr int32_t MAX_CLUSTER_SIZE = 100'000 * 100;
61 static constexpr uint64_t HIGH_ACCEPTABLE_COST = 100'000'000;
62
64 std::vector<TxGraph::Ref> top_refs;
66 std::vector<TxGraph::Ref> bottom_refs;
70 std::vector<size_t> top_components;
71
73 auto graph = MakeTxGraph(MAX_CLUSTER_COUNT, MAX_CLUSTER_SIZE, HIGH_ACCEPTABLE_COST, PointerComparator);
74
75 // Construct the top chains.
76 for (int chain = 0; chain < NUM_TOP_CHAINS; ++chain) {
77 for (int chaintx = 0; chaintx < NUM_TX_PER_TOP_CHAIN; ++chaintx) {
78 int64_t fee = rng.randbits<27>() + 100;
79 FeePerWeight feerate{fee, 1};
80 graph->AddTransaction(top_refs.emplace_back(), feerate);
81 // Add internal dependencies linking the chain transactions together.
82 if (chaintx > 0) {
83 graph->AddDependency(*(top_refs.rbegin()), *(top_refs.rbegin() + 1));
84 }
85 }
86 // Remember the last transaction in each chain, to attach the bottom transactions to.
87 top_components.push_back(top_refs.size() - 1);
88 }
89
90 // Make the graph linearize all clusters acceptably.
91 graph->GetBlockBuilder();
92
93 // Construct the bottom transactions, and dependencies to the top chains.
94 while (top_components.size() > 1) {
95 // Construct the transaction.
96 int64_t fee = rng.randbits<27>() + 100;
97 FeePerWeight feerate{fee, 1};
98 TxGraph::Ref bottom_tx;
99 graph->AddTransaction(bottom_tx, feerate);
100 // Determine the number of dependencies this transaction will have.
101 int deps = std::min<int>(NUM_DEPS_PER_BOTTOM_TX, top_components.size());
102 for (int dep = 0; dep < deps; ++dep) {
103 // Pick an transaction in top_components to attach to.
104 auto idx = rng.randrange(top_components.size());
105 // Add dependency.
106 graph->AddDependency(/*parent=*/top_refs[top_components[idx]], /*child=*/bottom_tx);
107 // Unless this is the last dependency being added, remove from top_components, as
108 // the component will be merged with that one.
109 if (dep < deps - 1) {
110 // Move entry top the back.
111 if (idx != top_components.size() - 1) std::swap(top_components.back(), top_components[idx]);
112 // And pop it.
113 top_components.pop_back();
114 }
115 }
116 bottom_refs.push_back(std::move(bottom_tx));
117 }
118
119 // Run the benchmark exactly once. Running it multiple times would require the setup to be
120 // redone, which takes a very non-negligible time compared to the trimming itself.
121 bench.epochIterations(1).epochs(1).run([&] {
122 // Call Trim() to remove transactions and bring the cluster back within limits.
123 graph->Trim();
124 // And relinearize everything that remains acceptably.
125 graph->GetBlockBuilder();
126 });
127
128 assert(!graph->IsOversized(TxGraph::Level::TOP));
129 // At least 99% of chains must survive.
130 assert(graph->GetTransactionCount(TxGraph::Level::TOP) >= (NUM_TOP_CHAINS * NUM_TX_PER_TOP_CHAIN * 99) / 100);
131}
132
133} // namespace
134
135static void TxGraphTrim(benchmark::Bench& bench) { BenchTxGraphTrim(bench); }
136
static void TxGraphTrim(benchmark::Bench &bench)
Definition: txgraph.cpp:135
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:191
FastRandomContext rng
Definition: dbwrapper.cpp:413
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:3583
assert(!tx.IsCoinBase())