Merge #8873: Add microbenchmarks to profile more code paths.
18dacf9
Add microbenchmarks to profile more code paths. (Russell Yanofsky)
This commit is contained in:
commit
74dc388ab5
5 changed files with 372 additions and 1 deletions
|
@ -14,6 +14,9 @@ bench_bench_bitcoin_SOURCES = \
|
|||
bench/Examples.cpp \
|
||||
bench/rollingbloom.cpp \
|
||||
bench/crypto_hash.cpp \
|
||||
bench/ccoins_caching.cpp \
|
||||
bench/mempool_eviction.cpp \
|
||||
bench/verify_script.cpp \
|
||||
bench/base58.cpp
|
||||
|
||||
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)
|
|||
endif
|
||||
|
||||
if ENABLE_WALLET
|
||||
bench_bench_bitcoin_LDADD += $(LIBBITCOIN_WALLET)
|
||||
bench_bench_bitcoin_SOURCES += bench/coin_selection.cpp
|
||||
bench_bench_bitcoin_LDADD += $(LIBBITCOIN_WALLET) $(LIBBITCOIN_CRYPTO)
|
||||
endif
|
||||
|
||||
bench_bench_bitcoin_LDADD += $(BOOST_LIBS) $(BDB_LIBS) $(SSL_LIBS) $(CRYPTO_LIBS) $(MINIUPNPC_LIBS) $(EVENT_PTHREADS_LIBS) $(EVENT_LIBS)
|
||||
|
|
87
src/bench/ccoins_caching.cpp
Normal file
87
src/bench/ccoins_caching.cpp
Normal file
|
@ -0,0 +1,87 @@
|
|||
// Copyright (c) 2016 The Bitcoin Core developers
|
||||
// Distributed under the MIT software license, see the accompanying
|
||||
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
|
||||
|
||||
#include "bench.h"
|
||||
#include "coins.h"
|
||||
#include "policy/policy.h"
|
||||
#include "wallet/crypter.h"
|
||||
|
||||
#include <vector>
|
||||
|
||||
// FIXME: Dedup with SetupDummyInputs in test/transaction_tests.cpp.
|
||||
//
|
||||
// Helper: create two dummy transactions, each with
|
||||
// two outputs. The first has 11 and 50 CENT outputs
|
||||
// paid to a TX_PUBKEY, the second 21 and 22 CENT outputs
|
||||
// paid to a TX_PUBKEYHASH.
|
||||
//
|
||||
static std::vector<CMutableTransaction>
|
||||
SetupDummyInputs(CBasicKeyStore& keystoreRet, CCoinsViewCache& coinsRet)
|
||||
{
|
||||
std::vector<CMutableTransaction> dummyTransactions;
|
||||
dummyTransactions.resize(2);
|
||||
|
||||
// Add some keys to the keystore:
|
||||
CKey key[4];
|
||||
for (int i = 0; i < 4; i++) {
|
||||
key[i].MakeNewKey(i % 2);
|
||||
keystoreRet.AddKey(key[i]);
|
||||
}
|
||||
|
||||
// Create some dummy input transactions
|
||||
dummyTransactions[0].vout.resize(2);
|
||||
dummyTransactions[0].vout[0].nValue = 11 * CENT;
|
||||
dummyTransactions[0].vout[0].scriptPubKey << ToByteVector(key[0].GetPubKey()) << OP_CHECKSIG;
|
||||
dummyTransactions[0].vout[1].nValue = 50 * CENT;
|
||||
dummyTransactions[0].vout[1].scriptPubKey << ToByteVector(key[1].GetPubKey()) << OP_CHECKSIG;
|
||||
coinsRet.ModifyCoins(dummyTransactions[0].GetHash())->FromTx(dummyTransactions[0], 0);
|
||||
|
||||
dummyTransactions[1].vout.resize(2);
|
||||
dummyTransactions[1].vout[0].nValue = 21 * CENT;
|
||||
dummyTransactions[1].vout[0].scriptPubKey = GetScriptForDestination(key[2].GetPubKey().GetID());
|
||||
dummyTransactions[1].vout[1].nValue = 22 * CENT;
|
||||
dummyTransactions[1].vout[1].scriptPubKey = GetScriptForDestination(key[3].GetPubKey().GetID());
|
||||
coinsRet.ModifyCoins(dummyTransactions[1].GetHash())->FromTx(dummyTransactions[1], 0);
|
||||
|
||||
return dummyTransactions;
|
||||
}
|
||||
|
||||
// Microbenchmark for simple accesses to a CCoinsViewCache database. Note from
|
||||
// laanwj, "replicating the actual usage patterns of the client is hard though,
|
||||
// many times micro-benchmarks of the database showed completely different
|
||||
// characteristics than e.g. reindex timings. But that's not a requirement of
|
||||
// every benchmark."
|
||||
// (https://github.com/bitcoin/bitcoin/issues/7883#issuecomment-224807484)
|
||||
static void CCoinsCaching(benchmark::State& state)
|
||||
{
|
||||
CBasicKeyStore keystore;
|
||||
CCoinsView coinsDummy;
|
||||
CCoinsViewCache coins(&coinsDummy);
|
||||
std::vector<CMutableTransaction> dummyTransactions = SetupDummyInputs(keystore, coins);
|
||||
|
||||
CMutableTransaction t1;
|
||||
t1.vin.resize(3);
|
||||
t1.vin[0].prevout.hash = dummyTransactions[0].GetHash();
|
||||
t1.vin[0].prevout.n = 1;
|
||||
t1.vin[0].scriptSig << std::vector<unsigned char>(65, 0);
|
||||
t1.vin[1].prevout.hash = dummyTransactions[1].GetHash();
|
||||
t1.vin[1].prevout.n = 0;
|
||||
t1.vin[1].scriptSig << std::vector<unsigned char>(65, 0) << std::vector<unsigned char>(33, 4);
|
||||
t1.vin[2].prevout.hash = dummyTransactions[1].GetHash();
|
||||
t1.vin[2].prevout.n = 1;
|
||||
t1.vin[2].scriptSig << std::vector<unsigned char>(65, 0) << std::vector<unsigned char>(33, 4);
|
||||
t1.vout.resize(2);
|
||||
t1.vout[0].nValue = 90 * CENT;
|
||||
t1.vout[0].scriptPubKey << OP_1;
|
||||
|
||||
// Benchmark.
|
||||
while (state.KeepRunning()) {
|
||||
bool success = AreInputsStandard(t1, coins);
|
||||
assert(success);
|
||||
CAmount value = coins.GetValueIn(t1);
|
||||
assert(value == (50 + 21 + 22) * CENT);
|
||||
}
|
||||
}
|
||||
|
||||
BENCHMARK(CCoinsCaching);
|
62
src/bench/coin_selection.cpp
Normal file
62
src/bench/coin_selection.cpp
Normal file
|
@ -0,0 +1,62 @@
|
|||
// Copyright (c) 2012-2015 The Bitcoin Core developers
|
||||
// Distributed under the MIT software license, see the accompanying
|
||||
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
|
||||
|
||||
#include "bench.h"
|
||||
#include "wallet/wallet.h"
|
||||
|
||||
#include <boost/foreach.hpp>
|
||||
#include <set>
|
||||
|
||||
using namespace std;
|
||||
|
||||
static void addCoin(const CAmount& nValue, const CWallet& wallet, vector<COutput>& vCoins)
|
||||
{
|
||||
int nInput = 0;
|
||||
|
||||
static int nextLockTime = 0;
|
||||
CMutableTransaction tx;
|
||||
tx.nLockTime = nextLockTime++; // so all transactions get different hashes
|
||||
tx.vout.resize(nInput + 1);
|
||||
tx.vout[nInput].nValue = nValue;
|
||||
CWalletTx* wtx = new CWalletTx(&wallet, tx);
|
||||
|
||||
int nAge = 6 * 24;
|
||||
COutput output(wtx, nInput, nAge, true, true);
|
||||
vCoins.push_back(output);
|
||||
}
|
||||
|
||||
// Simple benchmark for wallet coin selection. Note that it maybe be necessary
|
||||
// to build up more complicated scenarios in order to get meaningful
|
||||
// measurements of performance. From laanwj, "Wallet coin selection is probably
|
||||
// the hardest, as you need a wider selection of scenarios, just testing the
|
||||
// same one over and over isn't too useful. Generating random isn't useful
|
||||
// either for measurements."
|
||||
// (https://github.com/bitcoin/bitcoin/issues/7883#issuecomment-224807484)
|
||||
static void CoinSelection(benchmark::State& state)
|
||||
{
|
||||
const CWallet wallet;
|
||||
vector<COutput> vCoins;
|
||||
LOCK(wallet.cs_wallet);
|
||||
|
||||
while (state.KeepRunning()) {
|
||||
// Empty wallet.
|
||||
BOOST_FOREACH (COutput output, vCoins)
|
||||
delete output.tx;
|
||||
vCoins.clear();
|
||||
|
||||
// Add coins.
|
||||
for (int i = 0; i < 1000; i++)
|
||||
addCoin(1000 * COIN, wallet, vCoins);
|
||||
addCoin(3 * COIN, wallet, vCoins);
|
||||
|
||||
set<pair<const CWalletTx*, unsigned int> > setCoinsRet;
|
||||
CAmount nValueRet;
|
||||
bool success = wallet.SelectCoinsMinConf(1003 * COIN, 1, 6, vCoins, setCoinsRet, nValueRet);
|
||||
assert(success);
|
||||
assert(nValueRet == 1003 * COIN);
|
||||
assert(setCoinsRet.size() == 2);
|
||||
}
|
||||
}
|
||||
|
||||
BENCHMARK(CoinSelection);
|
115
src/bench/mempool_eviction.cpp
Normal file
115
src/bench/mempool_eviction.cpp
Normal file
|
@ -0,0 +1,115 @@
|
|||
// Copyright (c) 2011-2015 The Bitcoin Core developers
|
||||
// Distributed under the MIT software license, see the accompanying
|
||||
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
|
||||
|
||||
#include "bench.h"
|
||||
#include "policy/policy.h"
|
||||
#include "txmempool.h"
|
||||
|
||||
#include <list>
|
||||
#include <vector>
|
||||
|
||||
static void AddTx(const CTransaction& tx, const CAmount& nFee, CTxMemPool& pool)
|
||||
{
|
||||
int64_t nTime = 0;
|
||||
double dPriority = 10.0;
|
||||
unsigned int nHeight = 1;
|
||||
bool spendsCoinbase = false;
|
||||
unsigned int sigOpCost = 4;
|
||||
LockPoints lp;
|
||||
pool.addUnchecked(tx.GetHash(), CTxMemPoolEntry(
|
||||
tx, nFee, nTime, dPriority, nHeight, pool.HasNoInputsOf(tx),
|
||||
tx.GetValueOut(), spendsCoinbase, sigOpCost, lp));
|
||||
}
|
||||
|
||||
// Right now this is only testing eviction performance in an extremely small
|
||||
// mempool. Code needs to be written to generate a much wider variety of
|
||||
// unique transactions for a more meaningful performance measurement.
|
||||
static void MempoolEviction(benchmark::State& state)
|
||||
{
|
||||
CMutableTransaction tx1 = CMutableTransaction();
|
||||
tx1.vin.resize(1);
|
||||
tx1.vin[0].scriptSig = CScript() << OP_1;
|
||||
tx1.vout.resize(1);
|
||||
tx1.vout[0].scriptPubKey = CScript() << OP_1 << OP_EQUAL;
|
||||
tx1.vout[0].nValue = 10 * COIN;
|
||||
|
||||
CMutableTransaction tx2 = CMutableTransaction();
|
||||
tx2.vin.resize(1);
|
||||
tx2.vin[0].scriptSig = CScript() << OP_2;
|
||||
tx2.vout.resize(1);
|
||||
tx2.vout[0].scriptPubKey = CScript() << OP_2 << OP_EQUAL;
|
||||
tx2.vout[0].nValue = 10 * COIN;
|
||||
|
||||
CMutableTransaction tx3 = CMutableTransaction();
|
||||
tx3.vin.resize(1);
|
||||
tx3.vin[0].prevout = COutPoint(tx2.GetHash(), 0);
|
||||
tx3.vin[0].scriptSig = CScript() << OP_2;
|
||||
tx3.vout.resize(1);
|
||||
tx3.vout[0].scriptPubKey = CScript() << OP_3 << OP_EQUAL;
|
||||
tx3.vout[0].nValue = 10 * COIN;
|
||||
|
||||
CMutableTransaction tx4 = CMutableTransaction();
|
||||
tx4.vin.resize(2);
|
||||
tx4.vin[0].prevout.SetNull();
|
||||
tx4.vin[0].scriptSig = CScript() << OP_4;
|
||||
tx4.vin[1].prevout.SetNull();
|
||||
tx4.vin[1].scriptSig = CScript() << OP_4;
|
||||
tx4.vout.resize(2);
|
||||
tx4.vout[0].scriptPubKey = CScript() << OP_4 << OP_EQUAL;
|
||||
tx4.vout[0].nValue = 10 * COIN;
|
||||
tx4.vout[1].scriptPubKey = CScript() << OP_4 << OP_EQUAL;
|
||||
tx4.vout[1].nValue = 10 * COIN;
|
||||
|
||||
CMutableTransaction tx5 = CMutableTransaction();
|
||||
tx5.vin.resize(2);
|
||||
tx5.vin[0].prevout = COutPoint(tx4.GetHash(), 0);
|
||||
tx5.vin[0].scriptSig = CScript() << OP_4;
|
||||
tx5.vin[1].prevout.SetNull();
|
||||
tx5.vin[1].scriptSig = CScript() << OP_5;
|
||||
tx5.vout.resize(2);
|
||||
tx5.vout[0].scriptPubKey = CScript() << OP_5 << OP_EQUAL;
|
||||
tx5.vout[0].nValue = 10 * COIN;
|
||||
tx5.vout[1].scriptPubKey = CScript() << OP_5 << OP_EQUAL;
|
||||
tx5.vout[1].nValue = 10 * COIN;
|
||||
|
||||
CMutableTransaction tx6 = CMutableTransaction();
|
||||
tx6.vin.resize(2);
|
||||
tx6.vin[0].prevout = COutPoint(tx4.GetHash(), 1);
|
||||
tx6.vin[0].scriptSig = CScript() << OP_4;
|
||||
tx6.vin[1].prevout.SetNull();
|
||||
tx6.vin[1].scriptSig = CScript() << OP_6;
|
||||
tx6.vout.resize(2);
|
||||
tx6.vout[0].scriptPubKey = CScript() << OP_6 << OP_EQUAL;
|
||||
tx6.vout[0].nValue = 10 * COIN;
|
||||
tx6.vout[1].scriptPubKey = CScript() << OP_6 << OP_EQUAL;
|
||||
tx6.vout[1].nValue = 10 * COIN;
|
||||
|
||||
CMutableTransaction tx7 = CMutableTransaction();
|
||||
tx7.vin.resize(2);
|
||||
tx7.vin[0].prevout = COutPoint(tx5.GetHash(), 0);
|
||||
tx7.vin[0].scriptSig = CScript() << OP_5;
|
||||
tx7.vin[1].prevout = COutPoint(tx6.GetHash(), 0);
|
||||
tx7.vin[1].scriptSig = CScript() << OP_6;
|
||||
tx7.vout.resize(2);
|
||||
tx7.vout[0].scriptPubKey = CScript() << OP_7 << OP_EQUAL;
|
||||
tx7.vout[0].nValue = 10 * COIN;
|
||||
tx7.vout[1].scriptPubKey = CScript() << OP_7 << OP_EQUAL;
|
||||
tx7.vout[1].nValue = 10 * COIN;
|
||||
|
||||
CTxMemPool pool(CFeeRate(1000));
|
||||
|
||||
while (state.KeepRunning()) {
|
||||
AddTx(tx1, 10000LL, pool);
|
||||
AddTx(tx2, 5000LL, pool);
|
||||
AddTx(tx3, 20000LL, pool);
|
||||
AddTx(tx4, 7000LL, pool);
|
||||
AddTx(tx5, 1000LL, pool);
|
||||
AddTx(tx6, 1100LL, pool);
|
||||
AddTx(tx7, 9000LL, pool);
|
||||
pool.TrimToSize(pool.DynamicMemoryUsage() * 3 / 4);
|
||||
pool.TrimToSize(GetVirtualTransactionSize(tx1));
|
||||
}
|
||||
}
|
||||
|
||||
BENCHMARK(MempoolEviction);
|
103
src/bench/verify_script.cpp
Normal file
103
src/bench/verify_script.cpp
Normal file
|
@ -0,0 +1,103 @@
|
|||
// Copyright (c) 2016 The Bitcoin Core developers
|
||||
// Distributed under the MIT software license, see the accompanying
|
||||
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
|
||||
|
||||
#include "bench.h"
|
||||
#include "key.h"
|
||||
#if defined(HAVE_CONSENSUS_LIB)
|
||||
#include "script/bitcoinconsensus.h"
|
||||
#endif
|
||||
#include "script/script.h"
|
||||
#include "script/sign.h"
|
||||
#include "streams.h"
|
||||
|
||||
// FIXME: Dedup with BuildCreditingTransaction in test/script_tests.cpp.
|
||||
static CMutableTransaction BuildCreditingTransaction(const CScript& scriptPubKey)
|
||||
{
|
||||
CMutableTransaction txCredit;
|
||||
txCredit.nVersion = 1;
|
||||
txCredit.nLockTime = 0;
|
||||
txCredit.vin.resize(1);
|
||||
txCredit.vout.resize(1);
|
||||
txCredit.vin[0].prevout.SetNull();
|
||||
txCredit.vin[0].scriptSig = CScript() << CScriptNum(0) << CScriptNum(0);
|
||||
txCredit.vin[0].nSequence = CTxIn::SEQUENCE_FINAL;
|
||||
txCredit.vout[0].scriptPubKey = scriptPubKey;
|
||||
txCredit.vout[0].nValue = 1;
|
||||
|
||||
return txCredit;
|
||||
}
|
||||
|
||||
// FIXME: Dedup with BuildSpendingTransaction in test/script_tests.cpp.
|
||||
static CMutableTransaction BuildSpendingTransaction(const CScript& scriptSig, const CMutableTransaction& txCredit)
|
||||
{
|
||||
CMutableTransaction txSpend;
|
||||
txSpend.nVersion = 1;
|
||||
txSpend.nLockTime = 0;
|
||||
txSpend.vin.resize(1);
|
||||
txSpend.vout.resize(1);
|
||||
txSpend.wit.vtxinwit.resize(1);
|
||||
txSpend.vin[0].prevout.hash = txCredit.GetHash();
|
||||
txSpend.vin[0].prevout.n = 0;
|
||||
txSpend.vin[0].scriptSig = scriptSig;
|
||||
txSpend.vin[0].nSequence = CTxIn::SEQUENCE_FINAL;
|
||||
txSpend.vout[0].scriptPubKey = CScript();
|
||||
txSpend.vout[0].nValue = txCredit.vout[0].nValue;
|
||||
|
||||
return txSpend;
|
||||
}
|
||||
|
||||
// Microbenchmark for verification of a basic P2WPKH script. Can be easily
|
||||
// modified to measure performance of other types of scripts.
|
||||
static void VerifyScriptBench(benchmark::State& state)
|
||||
{
|
||||
const int flags = SCRIPT_VERIFY_WITNESS | SCRIPT_VERIFY_P2SH;
|
||||
const int witnessversion = 0;
|
||||
|
||||
// Keypair.
|
||||
CKey key;
|
||||
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};
|
||||
key.Set(vchKey, vchKey + 32, false);
|
||||
CPubKey pubkey = key.GetPubKey();
|
||||
uint160 pubkeyHash;
|
||||
CHash160().Write(pubkey.begin(), pubkey.size()).Finalize(pubkeyHash.begin());
|
||||
|
||||
// Script.
|
||||
CScript scriptPubKey = CScript() << witnessversion << ToByteVector(pubkeyHash);
|
||||
CScript scriptSig;
|
||||
CScript witScriptPubkey = CScript() << OP_DUP << OP_HASH160 << ToByteVector(pubkeyHash) << OP_EQUALVERIFY << OP_CHECKSIG;
|
||||
CTransaction txCredit = BuildCreditingTransaction(scriptPubKey);
|
||||
CMutableTransaction txSpend = BuildSpendingTransaction(scriptSig, txCredit);
|
||||
CScriptWitness& witness = txSpend.wit.vtxinwit[0].scriptWitness;
|
||||
witness.stack.emplace_back();
|
||||
key.Sign(SignatureHash(witScriptPubkey, txSpend, 0, SIGHASH_ALL, txCredit.vout[0].nValue, SIGVERSION_WITNESS_V0), witness.stack.back(), 0);
|
||||
witness.stack.back().push_back(static_cast<unsigned char>(SIGHASH_ALL));
|
||||
witness.stack.push_back(ToByteVector(pubkey));
|
||||
|
||||
// Benchmark.
|
||||
while (state.KeepRunning()) {
|
||||
ScriptError err;
|
||||
bool success = VerifyScript(
|
||||
txSpend.vin[0].scriptSig,
|
||||
txCredit.vout[0].scriptPubKey,
|
||||
&txSpend.wit.vtxinwit[0].scriptWitness,
|
||||
flags,
|
||||
MutableTransactionSignatureChecker(&txSpend, 0, txCredit.vout[0].nValue),
|
||||
&err);
|
||||
assert(err == SCRIPT_ERR_OK);
|
||||
assert(success);
|
||||
|
||||
#if defined(HAVE_CONSENSUS_LIB)
|
||||
CDataStream stream(SER_NETWORK, PROTOCOL_VERSION);
|
||||
stream << txSpend;
|
||||
int csuccess = bitcoinconsensus_verify_script_with_amount(
|
||||
begin_ptr(txCredit.vout[0].scriptPubKey),
|
||||
txCredit.vout[0].scriptPubKey.size(),
|
||||
txCredit.vout[0].nValue,
|
||||
(const unsigned char*)&stream[0], stream.size(), 0, flags, nullptr);
|
||||
assert(csuccess == 1);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
BENCHMARK(VerifyScriptBench);
|
Loading…
Reference in a new issue