Skip to content

Commit 74dc388

Browse files
committed
Merge #8873: Add microbenchmarks to profile more code paths.
18dacf9 Add microbenchmarks to profile more code paths. (Russell Yanofsky)
2 parents 7f71a3c + 18dacf9 commit 74dc388

File tree

5 files changed

+372
-1
lines changed

5 files changed

+372
-1
lines changed

src/Makefile.bench.include

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,9 @@ bench_bench_bitcoin_SOURCES = \
1414
bench/Examples.cpp \
1515
bench/rollingbloom.cpp \
1616
bench/crypto_hash.cpp \
17+
bench/ccoins_caching.cpp \
18+
bench/mempool_eviction.cpp \
19+
bench/verify_script.cpp \
1720
bench/base58.cpp
1821

1922
bench_bench_bitcoin_CPPFLAGS = $(AM_CPPFLAGS) $(BITCOIN_INCLUDES) $(EVENT_CLFAGS) $(EVENT_PTHREADS_CFLAGS) -I$(builddir)/bench/
@@ -34,7 +37,8 @@ bench_bench_bitcoin_LDADD += $(LIBBITCOIN_ZMQ) $(ZMQ_LIBS)
3437
endif
3538

3639
if ENABLE_WALLET
37-
bench_bench_bitcoin_LDADD += $(LIBBITCOIN_WALLET)
40+
bench_bench_bitcoin_SOURCES += bench/coin_selection.cpp
41+
bench_bench_bitcoin_LDADD += $(LIBBITCOIN_WALLET) $(LIBBITCOIN_CRYPTO)
3842
endif
3943

4044
bench_bench_bitcoin_LDADD += $(BOOST_LIBS) $(BDB_LIBS) $(SSL_LIBS) $(CRYPTO_LIBS) $(MINIUPNPC_LIBS) $(EVENT_PTHREADS_LIBS) $(EVENT_LIBS)

src/bench/ccoins_caching.cpp

Lines changed: 87 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,87 @@
1+
// Copyright (c) 2016 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.h"
6+
#include "coins.h"
7+
#include "policy/policy.h"
8+
#include "wallet/crypter.h"
9+
10+
#include <vector>
11+
12+
// FIXME: Dedup with SetupDummyInputs in test/transaction_tests.cpp.
13+
//
14+
// Helper: create two dummy transactions, each with
15+
// two outputs. The first has 11 and 50 CENT outputs
16+
// paid to a TX_PUBKEY, the second 21 and 22 CENT outputs
17+
// paid to a TX_PUBKEYHASH.
18+
//
19+
static std::vector<CMutableTransaction>
20+
SetupDummyInputs(CBasicKeyStore& keystoreRet, CCoinsViewCache& coinsRet)
21+
{
22+
std::vector<CMutableTransaction> dummyTransactions;
23+
dummyTransactions.resize(2);
24+
25+
// Add some keys to the keystore:
26+
CKey key[4];
27+
for (int i = 0; i < 4; i++) {
28+
key[i].MakeNewKey(i % 2);
29+
keystoreRet.AddKey(key[i]);
30+
}
31+
32+
// Create some dummy input transactions
33+
dummyTransactions[0].vout.resize(2);
34+
dummyTransactions[0].vout[0].nValue = 11 * CENT;
35+
dummyTransactions[0].vout[0].scriptPubKey << ToByteVector(key[0].GetPubKey()) << OP_CHECKSIG;
36+
dummyTransactions[0].vout[1].nValue = 50 * CENT;
37+
dummyTransactions[0].vout[1].scriptPubKey << ToByteVector(key[1].GetPubKey()) << OP_CHECKSIG;
38+
coinsRet.ModifyCoins(dummyTransactions[0].GetHash())->FromTx(dummyTransactions[0], 0);
39+
40+
dummyTransactions[1].vout.resize(2);
41+
dummyTransactions[1].vout[0].nValue = 21 * CENT;
42+
dummyTransactions[1].vout[0].scriptPubKey = GetScriptForDestination(key[2].GetPubKey().GetID());
43+
dummyTransactions[1].vout[1].nValue = 22 * CENT;
44+
dummyTransactions[1].vout[1].scriptPubKey = GetScriptForDestination(key[3].GetPubKey().GetID());
45+
coinsRet.ModifyCoins(dummyTransactions[1].GetHash())->FromTx(dummyTransactions[1], 0);
46+
47+
return dummyTransactions;
48+
}
49+
50+
// Microbenchmark for simple accesses to a CCoinsViewCache database. Note from
51+
// laanwj, "replicating the actual usage patterns of the client is hard though,
52+
// many times micro-benchmarks of the database showed completely different
53+
// characteristics than e.g. reindex timings. But that's not a requirement of
54+
// every benchmark."
55+
// (https://github.com/bitcoin/bitcoin/issues/7883#issuecomment-224807484)
56+
static void CCoinsCaching(benchmark::State& state)
57+
{
58+
CBasicKeyStore keystore;
59+
CCoinsView coinsDummy;
60+
CCoinsViewCache coins(&coinsDummy);
61+
std::vector<CMutableTransaction> dummyTransactions = SetupDummyInputs(keystore, coins);
62+
63+
CMutableTransaction t1;
64+
t1.vin.resize(3);
65+
t1.vin[0].prevout.hash = dummyTransactions[0].GetHash();
66+
t1.vin[0].prevout.n = 1;
67+
t1.vin[0].scriptSig << std::vector<unsigned char>(65, 0);
68+
t1.vin[1].prevout.hash = dummyTransactions[1].GetHash();
69+
t1.vin[1].prevout.n = 0;
70+
t1.vin[1].scriptSig << std::vector<unsigned char>(65, 0) << std::vector<unsigned char>(33, 4);
71+
t1.vin[2].prevout.hash = dummyTransactions[1].GetHash();
72+
t1.vin[2].prevout.n = 1;
73+
t1.vin[2].scriptSig << std::vector<unsigned char>(65, 0) << std::vector<unsigned char>(33, 4);
74+
t1.vout.resize(2);
75+
t1.vout[0].nValue = 90 * CENT;
76+
t1.vout[0].scriptPubKey << OP_1;
77+
78+
// Benchmark.
79+
while (state.KeepRunning()) {
80+
bool success = AreInputsStandard(t1, coins);
81+
assert(success);
82+
CAmount value = coins.GetValueIn(t1);
83+
assert(value == (50 + 21 + 22) * CENT);
84+
}
85+
}
86+
87+
BENCHMARK(CCoinsCaching);

src/bench/coin_selection.cpp

Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
// Copyright (c) 2012-2015 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.h"
6+
#include "wallet/wallet.h"
7+
8+
#include <boost/foreach.hpp>
9+
#include <set>
10+
11+
using namespace std;
12+
13+
static void addCoin(const CAmount& nValue, const CWallet& wallet, vector<COutput>& vCoins)
14+
{
15+
int nInput = 0;
16+
17+
static int nextLockTime = 0;
18+
CMutableTransaction tx;
19+
tx.nLockTime = nextLockTime++; // so all transactions get different hashes
20+
tx.vout.resize(nInput + 1);
21+
tx.vout[nInput].nValue = nValue;
22+
CWalletTx* wtx = new CWalletTx(&wallet, tx);
23+
24+
int nAge = 6 * 24;
25+
COutput output(wtx, nInput, nAge, true, true);
26+
vCoins.push_back(output);
27+
}
28+
29+
// Simple benchmark for wallet coin selection. Note that it maybe be necessary
30+
// to build up more complicated scenarios in order to get meaningful
31+
// measurements of performance. From laanwj, "Wallet coin selection is probably
32+
// the hardest, as you need a wider selection of scenarios, just testing the
33+
// same one over and over isn't too useful. Generating random isn't useful
34+
// either for measurements."
35+
// (https://github.com/bitcoin/bitcoin/issues/7883#issuecomment-224807484)
36+
static void CoinSelection(benchmark::State& state)
37+
{
38+
const CWallet wallet;
39+
vector<COutput> vCoins;
40+
LOCK(wallet.cs_wallet);
41+
42+
while (state.KeepRunning()) {
43+
// Empty wallet.
44+
BOOST_FOREACH (COutput output, vCoins)
45+
delete output.tx;
46+
vCoins.clear();
47+
48+
// Add coins.
49+
for (int i = 0; i < 1000; i++)
50+
addCoin(1000 * COIN, wallet, vCoins);
51+
addCoin(3 * COIN, wallet, vCoins);
52+
53+
set<pair<const CWalletTx*, unsigned int> > setCoinsRet;
54+
CAmount nValueRet;
55+
bool success = wallet.SelectCoinsMinConf(1003 * COIN, 1, 6, vCoins, setCoinsRet, nValueRet);
56+
assert(success);
57+
assert(nValueRet == 1003 * COIN);
58+
assert(setCoinsRet.size() == 2);
59+
}
60+
}
61+
62+
BENCHMARK(CoinSelection);

src/bench/mempool_eviction.cpp

Lines changed: 115 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,115 @@
1+
// Copyright (c) 2011-2015 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.h"
6+
#include "policy/policy.h"
7+
#include "txmempool.h"
8+
9+
#include <list>
10+
#include <vector>
11+
12+
static void AddTx(const CTransaction& tx, const CAmount& nFee, CTxMemPool& pool)
13+
{
14+
int64_t nTime = 0;
15+
double dPriority = 10.0;
16+
unsigned int nHeight = 1;
17+
bool spendsCoinbase = false;
18+
unsigned int sigOpCost = 4;
19+
LockPoints lp;
20+
pool.addUnchecked(tx.GetHash(), CTxMemPoolEntry(
21+
tx, nFee, nTime, dPriority, nHeight, pool.HasNoInputsOf(tx),
22+
tx.GetValueOut(), spendsCoinbase, sigOpCost, lp));
23+
}
24+
25+
// Right now this is only testing eviction performance in an extremely small
26+
// mempool. Code needs to be written to generate a much wider variety of
27+
// unique transactions for a more meaningful performance measurement.
28+
static void MempoolEviction(benchmark::State& state)
29+
{
30+
CMutableTransaction tx1 = CMutableTransaction();
31+
tx1.vin.resize(1);
32+
tx1.vin[0].scriptSig = CScript() << OP_1;
33+
tx1.vout.resize(1);
34+
tx1.vout[0].scriptPubKey = CScript() << OP_1 << OP_EQUAL;
35+
tx1.vout[0].nValue = 10 * COIN;
36+
37+
CMutableTransaction tx2 = CMutableTransaction();
38+
tx2.vin.resize(1);
39+
tx2.vin[0].scriptSig = CScript() << OP_2;
40+
tx2.vout.resize(1);
41+
tx2.vout[0].scriptPubKey = CScript() << OP_2 << OP_EQUAL;
42+
tx2.vout[0].nValue = 10 * COIN;
43+
44+
CMutableTransaction tx3 = CMutableTransaction();
45+
tx3.vin.resize(1);
46+
tx3.vin[0].prevout = COutPoint(tx2.GetHash(), 0);
47+
tx3.vin[0].scriptSig = CScript() << OP_2;
48+
tx3.vout.resize(1);
49+
tx3.vout[0].scriptPubKey = CScript() << OP_3 << OP_EQUAL;
50+
tx3.vout[0].nValue = 10 * COIN;
51+
52+
CMutableTransaction tx4 = CMutableTransaction();
53+
tx4.vin.resize(2);
54+
tx4.vin[0].prevout.SetNull();
55+
tx4.vin[0].scriptSig = CScript() << OP_4;
56+
tx4.vin[1].prevout.SetNull();
57+
tx4.vin[1].scriptSig = CScript() << OP_4;
58+
tx4.vout.resize(2);
59+
tx4.vout[0].scriptPubKey = CScript() << OP_4 << OP_EQUAL;
60+
tx4.vout[0].nValue = 10 * COIN;
61+
tx4.vout[1].scriptPubKey = CScript() << OP_4 << OP_EQUAL;
62+
tx4.vout[1].nValue = 10 * COIN;
63+
64+
CMutableTransaction tx5 = CMutableTransaction();
65+
tx5.vin.resize(2);
66+
tx5.vin[0].prevout = COutPoint(tx4.GetHash(), 0);
67+
tx5.vin[0].scriptSig = CScript() << OP_4;
68+
tx5.vin[1].prevout.SetNull();
69+
tx5.vin[1].scriptSig = CScript() << OP_5;
70+
tx5.vout.resize(2);
71+
tx5.vout[0].scriptPubKey = CScript() << OP_5 << OP_EQUAL;
72+
tx5.vout[0].nValue = 10 * COIN;
73+
tx5.vout[1].scriptPubKey = CScript() << OP_5 << OP_EQUAL;
74+
tx5.vout[1].nValue = 10 * COIN;
75+
76+
CMutableTransaction tx6 = CMutableTransaction();
77+
tx6.vin.resize(2);
78+
tx6.vin[0].prevout = COutPoint(tx4.GetHash(), 1);
79+
tx6.vin[0].scriptSig = CScript() << OP_4;
80+
tx6.vin[1].prevout.SetNull();
81+
tx6.vin[1].scriptSig = CScript() << OP_6;
82+
tx6.vout.resize(2);
83+
tx6.vout[0].scriptPubKey = CScript() << OP_6 << OP_EQUAL;
84+
tx6.vout[0].nValue = 10 * COIN;
85+
tx6.vout[1].scriptPubKey = CScript() << OP_6 << OP_EQUAL;
86+
tx6.vout[1].nValue = 10 * COIN;
87+
88+
CMutableTransaction tx7 = CMutableTransaction();
89+
tx7.vin.resize(2);
90+
tx7.vin[0].prevout = COutPoint(tx5.GetHash(), 0);
91+
tx7.vin[0].scriptSig = CScript() << OP_5;
92+
tx7.vin[1].prevout = COutPoint(tx6.GetHash(), 0);
93+
tx7.vin[1].scriptSig = CScript() << OP_6;
94+
tx7.vout.resize(2);
95+
tx7.vout[0].scriptPubKey = CScript() << OP_7 << OP_EQUAL;
96+
tx7.vout[0].nValue = 10 * COIN;
97+
tx7.vout[1].scriptPubKey = CScript() << OP_7 << OP_EQUAL;
98+
tx7.vout[1].nValue = 10 * COIN;
99+
100+
CTxMemPool pool(CFeeRate(1000));
101+
102+
while (state.KeepRunning()) {
103+
AddTx(tx1, 10000LL, pool);
104+
AddTx(tx2, 5000LL, pool);
105+
AddTx(tx3, 20000LL, pool);
106+
AddTx(tx4, 7000LL, pool);
107+
AddTx(tx5, 1000LL, pool);
108+
AddTx(tx6, 1100LL, pool);
109+
AddTx(tx7, 9000LL, pool);
110+
pool.TrimToSize(pool.DynamicMemoryUsage() * 3 / 4);
111+
pool.TrimToSize(GetVirtualTransactionSize(tx1));
112+
}
113+
}
114+
115+
BENCHMARK(MempoolEviction);

src/bench/verify_script.cpp

Lines changed: 103 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,103 @@
1+
// Copyright (c) 2016 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.h"
6+
#include "key.h"
7+
#if defined(HAVE_CONSENSUS_LIB)
8+
#include "script/bitcoinconsensus.h"
9+
#endif
10+
#include "script/script.h"
11+
#include "script/sign.h"
12+
#include "streams.h"
13+
14+
// FIXME: Dedup with BuildCreditingTransaction in test/script_tests.cpp.
15+
static CMutableTransaction BuildCreditingTransaction(const CScript& scriptPubKey)
16+
{
17+
CMutableTransaction txCredit;
18+
txCredit.nVersion = 1;
19+
txCredit.nLockTime = 0;
20+
txCredit.vin.resize(1);
21+
txCredit.vout.resize(1);
22+
txCredit.vin[0].prevout.SetNull();
23+
txCredit.vin[0].scriptSig = CScript() << CScriptNum(0) << CScriptNum(0);
24+
txCredit.vin[0].nSequence = CTxIn::SEQUENCE_FINAL;
25+
txCredit.vout[0].scriptPubKey = scriptPubKey;
26+
txCredit.vout[0].nValue = 1;
27+
28+
return txCredit;
29+
}
30+
31+
// FIXME: Dedup with BuildSpendingTransaction in test/script_tests.cpp.
32+
static CMutableTransaction BuildSpendingTransaction(const CScript& scriptSig, const CMutableTransaction& txCredit)
33+
{
34+
CMutableTransaction txSpend;
35+
txSpend.nVersion = 1;
36+
txSpend.nLockTime = 0;
37+
txSpend.vin.resize(1);
38+
txSpend.vout.resize(1);
39+
txSpend.wit.vtxinwit.resize(1);
40+
txSpend.vin[0].prevout.hash = txCredit.GetHash();
41+
txSpend.vin[0].prevout.n = 0;
42+
txSpend.vin[0].scriptSig = scriptSig;
43+
txSpend.vin[0].nSequence = CTxIn::SEQUENCE_FINAL;
44+
txSpend.vout[0].scriptPubKey = CScript();
45+
txSpend.vout[0].nValue = txCredit.vout[0].nValue;
46+
47+
return txSpend;
48+
}
49+
50+
// Microbenchmark for verification of a basic P2WPKH script. Can be easily
51+
// modified to measure performance of other types of scripts.
52+
static void VerifyScriptBench(benchmark::State& state)
53+
{
54+
const int flags = SCRIPT_VERIFY_WITNESS | SCRIPT_VERIFY_P2SH;
55+
const int witnessversion = 0;
56+
57+
// Keypair.
58+
CKey key;
59+
const unsigned char vchKey[32] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1};
60+
key.Set(vchKey, vchKey + 32, false);
61+
CPubKey pubkey = key.GetPubKey();
62+
uint160 pubkeyHash;
63+
CHash160().Write(pubkey.begin(), pubkey.size()).Finalize(pubkeyHash.begin());
64+
65+
// Script.
66+
CScript scriptPubKey = CScript() << witnessversion << ToByteVector(pubkeyHash);
67+
CScript scriptSig;
68+
CScript witScriptPubkey = CScript() << OP_DUP << OP_HASH160 << ToByteVector(pubkeyHash) << OP_EQUALVERIFY << OP_CHECKSIG;
69+
CTransaction txCredit = BuildCreditingTransaction(scriptPubKey);
70+
CMutableTransaction txSpend = BuildSpendingTransaction(scriptSig, txCredit);
71+
CScriptWitness& witness = txSpend.wit.vtxinwit[0].scriptWitness;
72+
witness.stack.emplace_back();
73+
key.Sign(SignatureHash(witScriptPubkey, txSpend, 0, SIGHASH_ALL, txCredit.vout[0].nValue, SIGVERSION_WITNESS_V0), witness.stack.back(), 0);
74+
witness.stack.back().push_back(static_cast<unsigned char>(SIGHASH_ALL));
75+
witness.stack.push_back(ToByteVector(pubkey));
76+
77+
// Benchmark.
78+
while (state.KeepRunning()) {
79+
ScriptError err;
80+
bool success = VerifyScript(
81+
txSpend.vin[0].scriptSig,
82+
txCredit.vout[0].scriptPubKey,
83+
&txSpend.wit.vtxinwit[0].scriptWitness,
84+
flags,
85+
MutableTransactionSignatureChecker(&txSpend, 0, txCredit.vout[0].nValue),
86+
&err);
87+
assert(err == SCRIPT_ERR_OK);
88+
assert(success);
89+
90+
#if defined(HAVE_CONSENSUS_LIB)
91+
CDataStream stream(SER_NETWORK, PROTOCOL_VERSION);
92+
stream << txSpend;
93+
int csuccess = bitcoinconsensus_verify_script_with_amount(
94+
begin_ptr(txCredit.vout[0].scriptPubKey),
95+
txCredit.vout[0].scriptPubKey.size(),
96+
txCredit.vout[0].nValue,
97+
(const unsigned char*)&stream[0], stream.size(), 0, flags, nullptr);
98+
assert(csuccess == 1);
99+
#endif
100+
}
101+
}
102+
103+
BENCHMARK(VerifyScriptBench);

0 commit comments

Comments
 (0)