Bitcoin Core  28.1.0
P2P Digital Currency
cluster_linearize.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 
7 #include <util/bitset.h>
8 #include <cluster_linearize.h>
9 
10 using namespace cluster_linearize;
11 
12 namespace {
13 
18 template<typename SetType>
19 DepGraph<SetType> MakeLinearGraph(ClusterIndex ntx)
20 {
21  DepGraph<SetType> depgraph;
22  for (ClusterIndex i = 0; i < ntx; ++i) {
23  depgraph.AddTransaction({-int32_t(i), 1});
24  if (i > 0) depgraph.AddDependency(i - 1, i);
25  }
26  return depgraph;
27 }
28 
33 template<typename SetType>
34 DepGraph<SetType> MakeWideGraph(ClusterIndex ntx)
35 {
36  DepGraph<SetType> depgraph;
37  for (ClusterIndex i = 0; i < ntx; ++i) {
38  depgraph.AddTransaction({int32_t(i) + 1, 1});
39  if (i > 0) depgraph.AddDependency(0, i);
40  }
41  return depgraph;
42 }
43 
44 // Construct a difficult graph. These need at least sqrt(2^(n-1)) iterations in the best
45 // known algorithms (purely empirically determined).
46 template<typename SetType>
47 DepGraph<SetType> MakeHardGraph(ClusterIndex ntx)
48 {
49  DepGraph<SetType> depgraph;
50  for (ClusterIndex i = 0; i < ntx; ++i) {
51  if (ntx & 1) {
52  // Odd cluster size.
53  //
54  // Mermaid diagram code for the resulting cluster for 11 transactions:
55  // ```mermaid
56  // graph BT
57  // T0["T0: 1/2"];T1["T1: 14/2"];T2["T2: 6/1"];T3["T3: 5/1"];T4["T4: 7/1"];
58  // T5["T5: 5/1"];T6["T6: 7/1"];T7["T7: 5/1"];T8["T8: 7/1"];T9["T9: 5/1"];
59  // T10["T10: 7/1"];
60  // T1-->T0;T1-->T2;T3-->T2;T4-->T3;T4-->T5;T6-->T5;T4-->T7;T8-->T7;T4-->T9;T10-->T9;
61  // ```
62  if (i == 0) {
63  depgraph.AddTransaction({1, 2});
64  } else if (i == 1) {
65  depgraph.AddTransaction({14, 2});
66  depgraph.AddDependency(0, 1);
67  } else if (i == 2) {
68  depgraph.AddTransaction({6, 1});
69  depgraph.AddDependency(2, 1);
70  } else if (i == 3) {
71  depgraph.AddTransaction({5, 1});
72  depgraph.AddDependency(2, 3);
73  } else if ((i & 1) == 0) {
74  depgraph.AddTransaction({7, 1});
75  depgraph.AddDependency(i - 1, i);
76  } else {
77  depgraph.AddTransaction({5, 1});
78  depgraph.AddDependency(i, 4);
79  }
80  } else {
81  // Even cluster size.
82  //
83  // Mermaid diagram code for the resulting cluster for 10 transactions:
84  // ```mermaid
85  // graph BT
86  // T0["T0: 1"];T1["T1: 3"];T2["T2: 1"];T3["T3: 4"];T4["T4: 0"];T5["T5: 4"];T6["T6: 0"];
87  // T7["T7: 4"];T8["T8: 0"];T9["T9: 4"];
88  // T1-->T0;T2-->T0;T3-->T2;T3-->T4;T5-->T4;T3-->T6;T7-->T6;T3-->T8;T9-->T8;
89  // ```
90  if (i == 0) {
91  depgraph.AddTransaction({1, 1});
92  } else if (i == 1) {
93  depgraph.AddTransaction({3, 1});
94  depgraph.AddDependency(0, 1);
95  } else if (i == 2) {
96  depgraph.AddTransaction({1, 1});
97  depgraph.AddDependency(0, 2);
98  } else if (i & 1) {
99  depgraph.AddTransaction({4, 1});
100  depgraph.AddDependency(i - 1, i);
101  } else {
102  depgraph.AddTransaction({0, 1});
103  depgraph.AddDependency(i, 3);
104  }
105  }
106  }
107  return depgraph;
108 }
109 
114 template<typename SetType>
115 void BenchLinearizePerIterWorstCase(ClusterIndex ntx, benchmark::Bench& bench)
116 {
117  const auto depgraph = MakeHardGraph<SetType>(ntx);
118  const auto iter_limit = std::min<uint64_t>(10000, uint64_t{1} << (ntx / 2 - 1));
119  uint64_t rng_seed = 0;
120  bench.batch(iter_limit).unit("iters").run([&] {
121  SearchCandidateFinder finder(depgraph, rng_seed++);
122  auto [candidate, iters_performed] = finder.FindCandidateSet(iter_limit, {});
123  assert(iters_performed == iter_limit);
124  });
125 }
126 
140 template<typename SetType>
141 void BenchLinearizeNoItersWorstCaseAnc(ClusterIndex ntx, benchmark::Bench& bench)
142 {
143  const auto depgraph = MakeLinearGraph<SetType>(ntx);
144  uint64_t rng_seed = 0;
145  std::vector<ClusterIndex> old_lin(ntx);
146  for (ClusterIndex i = 0; i < ntx; ++i) old_lin[i] = i;
147  bench.run([&] {
148  Linearize(depgraph, /*max_iterations=*/0, rng_seed++, old_lin);
149  });
150 }
151 
160 template<typename SetType>
161 void BenchLinearizeNoItersWorstCaseLIMO(ClusterIndex ntx, benchmark::Bench& bench)
162 {
163  const auto depgraph = MakeWideGraph<SetType>(ntx);
164  uint64_t rng_seed = 0;
165  std::vector<ClusterIndex> old_lin(ntx);
166  for (ClusterIndex i = 0; i < ntx; ++i) old_lin[i] = i;
167  bench.run([&] {
168  Linearize(depgraph, /*max_iterations=*/0, rng_seed++, old_lin);
169  });
170 }
171 
172 template<typename SetType>
173 void BenchPostLinearizeWorstCase(ClusterIndex ntx, benchmark::Bench& bench)
174 {
175  DepGraph<SetType> depgraph = MakeWideGraph<SetType>(ntx);
176  std::vector<ClusterIndex> lin(ntx);
177  bench.run([&] {
178  for (ClusterIndex i = 0; i < ntx; ++i) lin[i] = i;
179  PostLinearize(depgraph, lin);
180  });
181 }
182 
183 template<typename SetType>
184 void BenchMergeLinearizationsWorstCase(ClusterIndex ntx, benchmark::Bench& bench)
185 {
186  DepGraph<SetType> depgraph;
187  for (ClusterIndex i = 0; i < ntx; ++i) {
188  depgraph.AddTransaction({i, 1});
189  if (i) depgraph.AddDependency(0, i);
190  }
191  std::vector<ClusterIndex> lin1;
192  std::vector<ClusterIndex> lin2;
193  lin1.push_back(0);
194  lin2.push_back(0);
195  for (ClusterIndex i = 1; i < ntx; ++i) {
196  lin1.push_back(i);
197  lin2.push_back(ntx - i);
198  }
199  bench.run([&] {
200  MergeLinearizations(depgraph, lin1, lin2);
201  });
202 }
203 
204 } // namespace
205 
206 static void LinearizePerIter16TxWorstCase(benchmark::Bench& bench) { BenchLinearizePerIterWorstCase<BitSet<16>>(16, bench); }
207 static void LinearizePerIter32TxWorstCase(benchmark::Bench& bench) { BenchLinearizePerIterWorstCase<BitSet<32>>(32, bench); }
208 static void LinearizePerIter48TxWorstCase(benchmark::Bench& bench) { BenchLinearizePerIterWorstCase<BitSet<48>>(48, bench); }
209 static void LinearizePerIter64TxWorstCase(benchmark::Bench& bench) { BenchLinearizePerIterWorstCase<BitSet<64>>(64, bench); }
210 static void LinearizePerIter75TxWorstCase(benchmark::Bench& bench) { BenchLinearizePerIterWorstCase<BitSet<75>>(75, bench); }
211 static void LinearizePerIter99TxWorstCase(benchmark::Bench& bench) { BenchLinearizePerIterWorstCase<BitSet<99>>(99, bench); }
212 
213 static void LinearizeNoIters16TxWorstCaseAnc(benchmark::Bench& bench) { BenchLinearizeNoItersWorstCaseAnc<BitSet<16>>(16, bench); }
214 static void LinearizeNoIters32TxWorstCaseAnc(benchmark::Bench& bench) { BenchLinearizeNoItersWorstCaseAnc<BitSet<32>>(32, bench); }
215 static void LinearizeNoIters48TxWorstCaseAnc(benchmark::Bench& bench) { BenchLinearizeNoItersWorstCaseAnc<BitSet<48>>(48, bench); }
216 static void LinearizeNoIters64TxWorstCaseAnc(benchmark::Bench& bench) { BenchLinearizeNoItersWorstCaseAnc<BitSet<64>>(64, bench); }
217 static void LinearizeNoIters75TxWorstCaseAnc(benchmark::Bench& bench) { BenchLinearizeNoItersWorstCaseAnc<BitSet<75>>(75, bench); }
218 static void LinearizeNoIters99TxWorstCaseAnc(benchmark::Bench& bench) { BenchLinearizeNoItersWorstCaseAnc<BitSet<99>>(99, bench); }
219 
220 static void LinearizeNoIters16TxWorstCaseLIMO(benchmark::Bench& bench) { BenchLinearizeNoItersWorstCaseLIMO<BitSet<16>>(16, bench); }
221 static void LinearizeNoIters32TxWorstCaseLIMO(benchmark::Bench& bench) { BenchLinearizeNoItersWorstCaseLIMO<BitSet<32>>(32, bench); }
222 static void LinearizeNoIters48TxWorstCaseLIMO(benchmark::Bench& bench) { BenchLinearizeNoItersWorstCaseLIMO<BitSet<48>>(48, bench); }
223 static void LinearizeNoIters64TxWorstCaseLIMO(benchmark::Bench& bench) { BenchLinearizeNoItersWorstCaseLIMO<BitSet<64>>(64, bench); }
224 static void LinearizeNoIters75TxWorstCaseLIMO(benchmark::Bench& bench) { BenchLinearizeNoItersWorstCaseLIMO<BitSet<75>>(75, bench); }
225 static void LinearizeNoIters99TxWorstCaseLIMO(benchmark::Bench& bench) { BenchLinearizeNoItersWorstCaseLIMO<BitSet<99>>(99, bench); }
226 
227 static void PostLinearize16TxWorstCase(benchmark::Bench& bench) { BenchPostLinearizeWorstCase<BitSet<16>>(16, bench); }
228 static void PostLinearize32TxWorstCase(benchmark::Bench& bench) { BenchPostLinearizeWorstCase<BitSet<32>>(32, bench); }
229 static void PostLinearize48TxWorstCase(benchmark::Bench& bench) { BenchPostLinearizeWorstCase<BitSet<48>>(48, bench); }
230 static void PostLinearize64TxWorstCase(benchmark::Bench& bench) { BenchPostLinearizeWorstCase<BitSet<64>>(64, bench); }
231 static void PostLinearize75TxWorstCase(benchmark::Bench& bench) { BenchPostLinearizeWorstCase<BitSet<75>>(75, bench); }
232 static void PostLinearize99TxWorstCase(benchmark::Bench& bench) { BenchPostLinearizeWorstCase<BitSet<99>>(99, bench); }
233 
234 static void MergeLinearizations16TxWorstCase(benchmark::Bench& bench) { BenchMergeLinearizationsWorstCase<BitSet<16>>(16, bench); }
235 static void MergeLinearizations32TxWorstCase(benchmark::Bench& bench) { BenchMergeLinearizationsWorstCase<BitSet<32>>(32, bench); }
236 static void MergeLinearizations48TxWorstCase(benchmark::Bench& bench) { BenchMergeLinearizationsWorstCase<BitSet<48>>(48, bench); }
237 static void MergeLinearizations64TxWorstCase(benchmark::Bench& bench) { BenchMergeLinearizationsWorstCase<BitSet<64>>(64, bench); }
238 static void MergeLinearizations75TxWorstCase(benchmark::Bench& bench) { BenchMergeLinearizationsWorstCase<BitSet<75>>(75, bench); }
239 static void MergeLinearizations99TxWorstCase(benchmark::Bench& bench) { BenchMergeLinearizationsWorstCase<BitSet<99>>(99, bench); }
240 
247 
254 
261 
268 
static void LinearizePerIter32TxWorstCase(benchmark::Bench &bench)
BENCHMARK(LinearizePerIter16TxWorstCase, benchmark::PriorityLevel::HIGH)
static void LinearizeNoIters64TxWorstCaseLIMO(benchmark::Bench &bench)
ClusterIndex AddTransaction(const FeeFrac &feefrac) noexcept
Add a new unconnected transaction to this transaction graph (at the end), and return its ClusterIndex...
assert(!tx.IsCoinBase())
static void MergeLinearizations48TxWorstCase(benchmark::Bench &bench)
static void LinearizeNoIters99TxWorstCaseAnc(benchmark::Bench &bench)
uint32_t ClusterIndex
Data type to represent transaction indices in clusters.
static void PostLinearize16TxWorstCase(benchmark::Bench &bench)
static void LinearizeNoIters32TxWorstCaseLIMO(benchmark::Bench &bench)
static void LinearizePerIter64TxWorstCase(benchmark::Bench &bench)
static void LinearizePerIter75TxWorstCase(benchmark::Bench &bench)
static void PostLinearize75TxWorstCase(benchmark::Bench &bench)
static void MergeLinearizations99TxWorstCase(benchmark::Bench &bench)
static void LinearizeNoIters48TxWorstCaseAnc(benchmark::Bench &bench)
static void MergeLinearizations75TxWorstCase(benchmark::Bench &bench)
static void LinearizeNoIters75TxWorstCaseLIMO(benchmark::Bench &bench)
static void LinearizePerIter16TxWorstCase(benchmark::Bench &bench)
Bench & run(char const *benchmarkName, Op &&op)
Repeatedly calls op() based on the configuration, and performs measurements.
Definition: nanobench.h:1234
static void PostLinearize64TxWorstCase(benchmark::Bench &bench)
static void LinearizeNoIters48TxWorstCaseLIMO(benchmark::Bench &bench)
static void LinearizePerIter99TxWorstCase(benchmark::Bench &bench)
static void PostLinearize32TxWorstCase(benchmark::Bench &bench)
static void LinearizeNoIters16TxWorstCaseLIMO(benchmark::Bench &bench)
static void LinearizeNoIters75TxWorstCaseAnc(benchmark::Bench &bench)
static void MergeLinearizations16TxWorstCase(benchmark::Bench &bench)
static void MergeLinearizations32TxWorstCase(benchmark::Bench &bench)
static void PostLinearize48TxWorstCase(benchmark::Bench &bench)
void AddDependency(ClusterIndex parent, ClusterIndex child) noexcept
Modify this transaction graph, adding a dependency between a specified parent and child...
static void MergeLinearizations64TxWorstCase(benchmark::Bench &bench)
Data structure that holds a transaction graph&#39;s preprocessed data (fee, size, ancestors, descendants).
std::pair< std::vector< ClusterIndex >, bool > Linearize(const DepGraph< SetType > &depgraph, uint64_t max_iterations, uint64_t rng_seed, Span< const ClusterIndex > old_linearization={}) noexcept
Find or improve a linearization for a cluster.
static void LinearizeNoIters16TxWorstCaseAnc(benchmark::Bench &bench)
Main entry point to nanobench&#39;s benchmarking facility.
Definition: nanobench.h:627
std::vector< ClusterIndex > MergeLinearizations(const DepGraph< SetType > &depgraph, Span< const ClusterIndex > lin1, Span< const ClusterIndex > lin2)
Merge two linearizations for the same cluster into one that is as good as both.
void PostLinearize(const DepGraph< SetType > &depgraph, Span< ClusterIndex > linearization)
Improve a given linearization.
static void LinearizeNoIters32TxWorstCaseAnc(benchmark::Bench &bench)
static void PostLinearize99TxWorstCase(benchmark::Bench &bench)
Class encapsulating the state needed to perform search for good candidate sets.
static void LinearizePerIter48TxWorstCase(benchmark::Bench &bench)
static void LinearizeNoIters99TxWorstCaseLIMO(benchmark::Bench &bench)
static void LinearizeNoIters64TxWorstCaseAnc(benchmark::Bench &bench)