aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorWladimir J. van der Laan <laanwj@gmail.com>2016-10-18 22:03:28 +0200
committerWladimir J. van der Laan <laanwj@gmail.com>2016-10-18 22:03:52 +0200
commit74dc388ab599304494a082dc99e2d57f962cb0b7 (patch)
treed193e836fa963694302d50b57bce011a64a88120 /src
parent7f71a3c591945769ad33e5734105219062311d1e (diff)
parent18dacf9bd25154e184b097ee4e8f786d9be25637 (diff)
Merge #8873: Add microbenchmarks to profile more code paths.
18dacf9 Add microbenchmarks to profile more code paths. (Russell Yanofsky)
Diffstat (limited to 'src')
-rw-r--r--src/Makefile.bench.include6
-rw-r--r--src/bench/ccoins_caching.cpp87
-rw-r--r--src/bench/coin_selection.cpp62
-rw-r--r--src/bench/mempool_eviction.cpp115
-rw-r--r--src/bench/verify_script.cpp103
5 files changed, 372 insertions, 1 deletions
diff --git a/src/Makefile.bench.include b/src/Makefile.bench.include
index 8c024a8c4a..c83432e91a 100644
--- a/src/Makefile.bench.include
+++ b/src/Makefile.bench.include
@@ -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)
diff --git a/src/bench/ccoins_caching.cpp b/src/bench/ccoins_caching.cpp
new file mode 100644
index 0000000000..1e8e3d462f
--- /dev/null
+++ b/src/bench/ccoins_caching.cpp
@@ -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);
diff --git a/src/bench/coin_selection.cpp b/src/bench/coin_selection.cpp
new file mode 100644
index 0000000000..7091ee3e11
--- /dev/null
+++ b/src/bench/coin_selection.cpp
@@ -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);
diff --git a/src/bench/mempool_eviction.cpp b/src/bench/mempool_eviction.cpp
new file mode 100644
index 0000000000..0ae69c75fc
--- /dev/null
+++ b/src/bench/mempool_eviction.cpp
@@ -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);
diff --git a/src/bench/verify_script.cpp b/src/bench/verify_script.cpp
new file mode 100644
index 0000000000..dc3940cdbd
--- /dev/null
+++ b/src/bench/verify_script.cpp
@@ -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);