Skip to content

Commit a5224be

Browse files
author
MarcoFalke
committed
Merge #17292: Add new mempool benchmarks for a complex pool
b0c774b Add new mempool benchmarks for a complex pool (Jeremy Rubin) Pull request description: This PR is related to #17268. It adds a mempool stress test which makes a really big complicated tx graph, and then, similar to mempool_eviction test, trims the size. The test setup is to make 100 original transactions with Rand(10)+2 outputs each. Then, 800 times: we create a new transaction with Rand(10) + 1 parents that are randomly sampled from all existing transactions (with unspent outputs). From each such parent, we then select Rand(remaining outputs) +1 50% of the time, or 1 outputs 50% of the time. Then, we trim the size to 3/4. Then we trim it to just a single transaction. This creates, hopefully, a big bundle of transactions with lots of complex structure, that should really put a strain on the mempool graph algorithms. This ends up testing both the descendant and ancestor tracking. I don't love that the test is "unstable". That is, in order to compare this test to another, you really can't modify any of the internal state because it will have a different order of invocations of the deterministic randomness. However, it certainly suffices for comparing branches. Top commit has no ACKs. Tree-SHA512: cabe96b849b9885878e20eec558915e921d49e6ed1e4b011b22ca191b4c99aa28930a8b963784c9adf78cc8b034a655513f7a0da865e280a1214ae15ebb1d574
2 parents 5021ef8 + b0c774b commit a5224be

File tree

2 files changed

+94
-0
lines changed

2 files changed

+94
-0
lines changed

src/Makefile.bench.include

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@ bench_bench_bitcoin_SOURCES = \
3030
bench/gcs_filter.cpp \
3131
bench/merkle_root.cpp \
3232
bench/mempool_eviction.cpp \
33+
bench/mempool_stress.cpp \
3334
bench/rpc_blockchain.cpp \
3435
bench/rpc_mempool.cpp \
3536
bench/util_time.cpp \

src/bench/mempool_stress.cpp

Lines changed: 93 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,93 @@
1+
// Copyright (c) 2011-2019 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 <policy/policy.h>
7+
#include <txmempool.h>
8+
9+
#include <vector>
10+
11+
static void AddTx(const CTransactionRef& tx, CTxMemPool& pool) EXCLUSIVE_LOCKS_REQUIRED(cs_main, pool.cs)
12+
{
13+
int64_t nTime = 0;
14+
unsigned int nHeight = 1;
15+
bool spendsCoinbase = false;
16+
unsigned int sigOpCost = 4;
17+
LockPoints lp;
18+
pool.addUnchecked(CTxMemPoolEntry(tx, 1000, nTime, nHeight, spendsCoinbase, sigOpCost, lp));
19+
}
20+
21+
struct Available {
22+
CTransactionRef ref;
23+
size_t vin_left{0};
24+
size_t tx_count;
25+
Available(CTransactionRef& ref, size_t tx_count) : ref(ref), tx_count(tx_count){}
26+
Available& operator=(Available other) {
27+
ref = other.ref;
28+
vin_left = other.vin_left;
29+
tx_count = other.tx_count;
30+
return *this;
31+
}
32+
};
33+
34+
static void ComplexMemPool(benchmark::State& state)
35+
{
36+
FastRandomContext det_rand{true};
37+
std::vector<Available> available_coins;
38+
std::vector<CTransactionRef> ordered_coins;
39+
// Create some base transactions
40+
size_t tx_counter = 1;
41+
for (auto x = 0; x < 100; ++x) {
42+
CMutableTransaction tx = CMutableTransaction();
43+
tx.vin.resize(1);
44+
tx.vin[0].scriptSig = CScript() << CScriptNum(tx_counter);
45+
tx.vin[0].scriptWitness.stack.push_back(CScriptNum(x).getvch());
46+
tx.vout.resize(det_rand.randrange(10)+2);
47+
for (auto& out : tx.vout) {
48+
out.scriptPubKey = CScript() << CScriptNum(tx_counter) << OP_EQUAL;
49+
out.nValue = 10 * COIN;
50+
}
51+
ordered_coins.emplace_back(MakeTransactionRef(tx));
52+
available_coins.emplace_back(ordered_coins.back(), tx_counter++);
53+
}
54+
for (auto x = 0; x < 800 && !available_coins.empty(); ++x) {
55+
CMutableTransaction tx = CMutableTransaction();
56+
size_t n_ancestors = det_rand.randrange(10)+1;
57+
for (size_t ancestor = 0; ancestor < n_ancestors && !available_coins.empty(); ++ancestor){
58+
size_t idx = det_rand.randrange(available_coins.size());
59+
Available coin = available_coins[idx];
60+
uint256 hash = coin.ref->GetHash();
61+
// biased towards taking just one ancestor, but maybe more
62+
size_t n_to_take = det_rand.randrange(2) == 0 ? 1 : 1+det_rand.randrange(coin.ref->vout.size() - coin.vin_left);
63+
for (size_t i = 0; i < n_to_take; ++i) {
64+
tx.vin.emplace_back();
65+
tx.vin.back().prevout = COutPoint(hash, coin.vin_left++);
66+
tx.vin.back().scriptSig = CScript() << coin.tx_count;
67+
tx.vin.back().scriptWitness.stack.push_back(CScriptNum(coin.tx_count).getvch());
68+
}
69+
if (coin.vin_left == coin.ref->vin.size()) {
70+
coin = available_coins.back();
71+
available_coins.pop_back();
72+
}
73+
tx.vout.resize(det_rand.randrange(10)+2);
74+
for (auto& out : tx.vout) {
75+
out.scriptPubKey = CScript() << CScriptNum(tx_counter) << OP_EQUAL;
76+
out.nValue = 10 * COIN;
77+
}
78+
}
79+
ordered_coins.emplace_back(MakeTransactionRef(tx));
80+
available_coins.emplace_back(ordered_coins.back(), tx_counter++);
81+
}
82+
CTxMemPool pool;
83+
LOCK2(cs_main, pool.cs);
84+
while (state.KeepRunning()) {
85+
for (auto& tx : ordered_coins) {
86+
AddTx(tx, pool);
87+
}
88+
pool.TrimToSize(pool.DynamicMemoryUsage() * 3 / 4);
89+
pool.TrimToSize(GetVirtualTransactionSize(*ordered_coins.front()));
90+
}
91+
}
92+
93+
BENCHMARK(ComplexMemPool, 1);

0 commit comments

Comments
 (0)