aboutsummaryrefslogtreecommitdiff
path: root/src/bench
diff options
context:
space:
mode:
Diffstat (limited to 'src/bench')
-rw-r--r--src/bench/Examples.cpp4
-rw-r--r--src/bench/base58.cpp4
-rw-r--r--src/bench/bench.cpp57
-rw-r--r--src/bench/bench.h17
-rw-r--r--src/bench/bench_bitcoin.cpp4
-rw-r--r--src/bench/ccoins_caching.cpp87
-rw-r--r--src/bench/checkblock.cpp56
-rw-r--r--src/bench/checkqueue.cpp103
-rw-r--r--src/bench/coin_selection.cpp60
-rw-r--r--src/bench/crypto_hash.cpp35
-rw-r--r--src/bench/data/block413567.rawbin0 -> 999887 bytes
-rw-r--r--src/bench/lockedpool.cpp47
-rw-r--r--src/bench/mempool_eviction.cpp114
-rw-r--r--src/bench/perf.cpp53
-rw-r--r--src/bench/perf.h37
-rw-r--r--src/bench/prevector_destructor.cpp36
-rw-r--r--src/bench/verify_script.cpp102
17 files changed, 782 insertions, 34 deletions
diff --git a/src/bench/Examples.cpp b/src/bench/Examples.cpp
index b6b020a971..314947d48c 100644
--- a/src/bench/Examples.cpp
+++ b/src/bench/Examples.cpp
@@ -1,9 +1,9 @@
-// Copyright (c) 2015 The Bitcoin Core developers
+// Copyright (c) 2015-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 "main.h"
+#include "validation.h"
#include "utiltime.h"
// Sanity test: this should loop ten times, and
diff --git a/src/bench/base58.cpp b/src/bench/base58.cpp
index 1279c3e7df..3319c179bf 100644
--- a/src/bench/base58.cpp
+++ b/src/bench/base58.cpp
@@ -1,10 +1,10 @@
-// Copyright (c) 2016 the Bitcoin Core developers
+// 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 "main.h"
+#include "validation.h"
#include "base58.h"
#include <vector>
diff --git a/src/bench/bench.cpp b/src/bench/bench.cpp
index 227546a7a7..b0df3d2b04 100644
--- a/src/bench/bench.cpp
+++ b/src/bench/bench.cpp
@@ -1,16 +1,18 @@
-// Copyright (c) 2015 The Bitcoin Core developers
+// Copyright (c) 2015-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 "perf.h"
#include <iostream>
#include <iomanip>
#include <sys/time.h>
-using namespace benchmark;
-
-std::map<std::string, BenchFunction> BenchRunner::benchmarks;
+benchmark::BenchRunner::BenchmarkMap &benchmark::BenchRunner::benchmarks() {
+ static std::map<std::string, benchmark::BenchFunction> benchmarks_map;
+ return benchmarks_map;
+}
static double gettimedouble(void) {
struct timeval tv;
@@ -18,34 +20,36 @@ static double gettimedouble(void) {
return tv.tv_usec * 0.000001 + tv.tv_sec;
}
-BenchRunner::BenchRunner(std::string name, BenchFunction func)
+benchmark::BenchRunner::BenchRunner(std::string name, benchmark::BenchFunction func)
{
- benchmarks.insert(std::make_pair(name, func));
+ benchmarks().insert(std::make_pair(name, func));
}
void
-BenchRunner::RunAll(double elapsedTimeForOne)
+benchmark::BenchRunner::RunAll(double elapsedTimeForOne)
{
- std::cout << "#Benchmark" << "," << "count" << "," << "min" << "," << "max" << "," << "average" << "\n";
+ perf_init();
+ std::cout << "#Benchmark" << "," << "count" << "," << "min" << "," << "max" << "," << "average" << ","
+ << "min_cycles" << "," << "max_cycles" << "," << "average_cycles" << "\n";
- for (std::map<std::string,BenchFunction>::iterator it = benchmarks.begin();
- it != benchmarks.end(); ++it) {
-
- State state(it->first, elapsedTimeForOne);
- BenchFunction& func = it->second;
- func(state);
+ for (const auto &p: benchmarks()) {
+ State state(p.first, elapsedTimeForOne);
+ p.second(state);
}
+ perf_fini();
}
-bool State::KeepRunning()
+bool benchmark::State::KeepRunning()
{
if (count & countMask) {
++count;
return true;
}
double now;
+ uint64_t nowCycles;
if (count == 0) {
lastTime = beginTime = now = gettimedouble();
+ lastCycles = beginCycles = nowCycles = perf_cpucycles();
}
else {
now = gettimedouble();
@@ -53,6 +57,13 @@ bool State::KeepRunning()
double elapsedOne = elapsed * countMaskInv;
if (elapsedOne < minTime) minTime = elapsedOne;
if (elapsedOne > maxTime) maxTime = elapsedOne;
+
+ // We only use relative values, so don't have to handle 64-bit wrap-around specially
+ nowCycles = perf_cpucycles();
+ uint64_t elapsedOneCycles = (nowCycles - lastCycles) * countMaskInv;
+ if (elapsedOneCycles < minCycles) minCycles = elapsedOneCycles;
+ if (elapsedOneCycles > maxCycles) maxCycles = elapsedOneCycles;
+
if (elapsed*128 < maxElapsed) {
// If the execution was much too fast (1/128th of maxElapsed), increase the count mask by 8x and restart timing.
// The restart avoids including the overhead of this code in the measurement.
@@ -61,23 +72,33 @@ bool State::KeepRunning()
count = 0;
minTime = std::numeric_limits<double>::max();
maxTime = std::numeric_limits<double>::min();
+ minCycles = std::numeric_limits<uint64_t>::max();
+ maxCycles = std::numeric_limits<uint64_t>::min();
return true;
}
if (elapsed*16 < maxElapsed) {
- countMask = ((countMask<<1)|1) & ((1LL<<60)-1);
- countMaskInv = 1./(countMask+1);
+ uint64_t newCountMask = ((countMask<<1)|1) & ((1LL<<60)-1);
+ if ((count & newCountMask)==0) {
+ countMask = newCountMask;
+ countMaskInv = 1./(countMask+1);
+ }
}
}
lastTime = now;
+ lastCycles = nowCycles;
++count;
if (now - beginTime < maxElapsed) return true; // Keep going
--count;
+ assert(count != 0 && "count == 0 => (now == 0 && beginTime == 0) => return above");
+
// Output results
double average = (now-beginTime)/count;
- std::cout << std::fixed << std::setprecision(15) << name << "," << count << "," << minTime << "," << maxTime << "," << average << "\n";
+ int64_t averageCycles = (nowCycles-beginCycles)/count;
+ std::cout << std::fixed << std::setprecision(15) << name << "," << count << "," << minTime << "," << maxTime << "," << average << ","
+ << minCycles << "," << maxCycles << "," << averageCycles << "\n";
return false;
}
diff --git a/src/bench/bench.h b/src/bench/bench.h
index f13b145aaf..f12a41126c 100644
--- a/src/bench/bench.h
+++ b/src/bench/bench.h
@@ -1,4 +1,4 @@
-// Copyright (c) 2015 The Bitcoin Core developers
+// Copyright (c) 2015-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.
@@ -14,7 +14,7 @@
// Simple micro-benchmarking framework; API mostly matches a subset of the Google Benchmark
// framework (see https://github.com/google/benchmark)
-// Wny not use the Google Benchmark framework? Because adding Yet Another Dependency
+// Why not use the Google Benchmark framework? Because adding Yet Another Dependency
// (that uses cmake as its build system and has lots of features we don't need) isn't
// worth it.
@@ -41,12 +41,18 @@ namespace benchmark {
double maxElapsed;
double beginTime;
double lastTime, minTime, maxTime, countMaskInv;
- int64_t count;
- int64_t countMask;
+ uint64_t count;
+ uint64_t countMask;
+ uint64_t beginCycles;
+ uint64_t lastCycles;
+ uint64_t minCycles;
+ uint64_t maxCycles;
public:
State(std::string _name, double _maxElapsed) : name(_name), maxElapsed(_maxElapsed), count(0) {
minTime = std::numeric_limits<double>::max();
maxTime = std::numeric_limits<double>::min();
+ minCycles = std::numeric_limits<uint64_t>::max();
+ maxCycles = std::numeric_limits<uint64_t>::min();
countMask = 1;
countMaskInv = 1./(countMask + 1);
}
@@ -57,7 +63,8 @@ namespace benchmark {
class BenchRunner
{
- static std::map<std::string, BenchFunction> benchmarks;
+ typedef std::map<std::string, BenchFunction> BenchmarkMap;
+ static BenchmarkMap &benchmarks();
public:
BenchRunner(std::string name, BenchFunction func);
diff --git a/src/bench/bench_bitcoin.cpp b/src/bench/bench_bitcoin.cpp
index db1402216d..61a0b31aed 100644
--- a/src/bench/bench_bitcoin.cpp
+++ b/src/bench/bench_bitcoin.cpp
@@ -1,11 +1,11 @@
-// Copyright (c) 2015 The Bitcoin Core developers
+// Copyright (c) 2015-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"
-#include "main.h"
+#include "validation.h"
#include "util.h"
int
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/checkblock.cpp b/src/bench/checkblock.cpp
new file mode 100644
index 0000000000..195388839e
--- /dev/null
+++ b/src/bench/checkblock.cpp
@@ -0,0 +1,56 @@
+// 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 "chainparams.h"
+#include "validation.h"
+#include "streams.h"
+#include "consensus/validation.h"
+
+namespace block_bench {
+#include "bench/data/block413567.raw.h"
+}
+
+// These are the two major time-sinks which happen after we have fully received
+// a block off the wire, but before we can relay the block on to peers using
+// compact block relay.
+
+static void DeserializeBlockTest(benchmark::State& state)
+{
+ CDataStream stream((const char*)block_bench::block413567,
+ (const char*)&block_bench::block413567[sizeof(block_bench::block413567)],
+ SER_NETWORK, PROTOCOL_VERSION);
+ char a = '\0';
+ stream.write(&a, 1); // Prevent compaction
+
+ while (state.KeepRunning()) {
+ CBlock block;
+ stream >> block;
+ assert(stream.Rewind(sizeof(block_bench::block413567)));
+ }
+}
+
+static void DeserializeAndCheckBlockTest(benchmark::State& state)
+{
+ CDataStream stream((const char*)block_bench::block413567,
+ (const char*)&block_bench::block413567[sizeof(block_bench::block413567)],
+ SER_NETWORK, PROTOCOL_VERSION);
+ char a = '\0';
+ stream.write(&a, 1); // Prevent compaction
+
+ const auto chainParams = CreateChainParams(CBaseChainParams::MAIN);
+
+ while (state.KeepRunning()) {
+ CBlock block; // Note that CBlock caches its checked state, so we need to recreate it here
+ stream >> block;
+ assert(stream.Rewind(sizeof(block_bench::block413567)));
+
+ CValidationState validationState;
+ assert(CheckBlock(block, validationState, chainParams->GetConsensus()));
+ }
+}
+
+BENCHMARK(DeserializeBlockTest);
+BENCHMARK(DeserializeAndCheckBlockTest);
diff --git a/src/bench/checkqueue.cpp b/src/bench/checkqueue.cpp
new file mode 100644
index 0000000000..88a2a570f9
--- /dev/null
+++ b/src/bench/checkqueue.cpp
@@ -0,0 +1,103 @@
+// Copyright (c) 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 "util.h"
+#include "validation.h"
+#include "checkqueue.h"
+#include "prevector.h"
+#include <vector>
+#include <boost/thread/thread.hpp>
+#include "random.h"
+
+
+// This Benchmark tests the CheckQueue with the lightest
+// weight Checks, so it should make any lock contention
+// particularly visible
+static const int MIN_CORES = 2;
+static const size_t BATCHES = 101;
+static const size_t BATCH_SIZE = 30;
+static const int PREVECTOR_SIZE = 28;
+static const int QUEUE_BATCH_SIZE = 128;
+static void CCheckQueueSpeed(benchmark::State& state)
+{
+ struct FakeJobNoWork {
+ bool operator()()
+ {
+ return true;
+ }
+ void swap(FakeJobNoWork& x){};
+ };
+ CCheckQueue<FakeJobNoWork> queue {QUEUE_BATCH_SIZE};
+ boost::thread_group tg;
+ for (auto x = 0; x < std::max(MIN_CORES, GetNumCores()); ++x) {
+ tg.create_thread([&]{queue.Thread();});
+ }
+ while (state.KeepRunning()) {
+ CCheckQueueControl<FakeJobNoWork> control(&queue);
+
+ // We call Add a number of times to simulate the behavior of adding
+ // a block of transactions at once.
+
+ std::vector<std::vector<FakeJobNoWork>> vBatches(BATCHES);
+ for (auto& vChecks : vBatches) {
+ vChecks.resize(BATCH_SIZE);
+ }
+ for (auto& vChecks : vBatches) {
+ // We can't make vChecks in the inner loop because we want to measure
+ // the cost of getting the memory to each thread and we might get the same
+ // memory
+ control.Add(vChecks);
+ }
+ // control waits for completion by RAII, but
+ // it is done explicitly here for clarity
+ control.Wait();
+ }
+ tg.interrupt_all();
+ tg.join_all();
+}
+
+// This Benchmark tests the CheckQueue with a slightly realistic workload,
+// where checks all contain a prevector that is indirect 50% of the time
+// and there is a little bit of work done between calls to Add.
+static void CCheckQueueSpeedPrevectorJob(benchmark::State& state)
+{
+ struct PrevectorJob {
+ prevector<PREVECTOR_SIZE, uint8_t> p;
+ PrevectorJob(){
+ }
+ PrevectorJob(FastRandomContext& insecure_rand){
+ p.resize(insecure_rand.randrange(PREVECTOR_SIZE*2));
+ }
+ bool operator()()
+ {
+ return true;
+ }
+ void swap(PrevectorJob& x){p.swap(x.p);};
+ };
+ CCheckQueue<PrevectorJob> queue {QUEUE_BATCH_SIZE};
+ boost::thread_group tg;
+ for (auto x = 0; x < std::max(MIN_CORES, GetNumCores()); ++x) {
+ tg.create_thread([&]{queue.Thread();});
+ }
+ while (state.KeepRunning()) {
+ // Make insecure_rand here so that each iteration is identical.
+ FastRandomContext insecure_rand(true);
+ CCheckQueueControl<PrevectorJob> control(&queue);
+ std::vector<std::vector<PrevectorJob>> vBatches(BATCHES);
+ for (auto& vChecks : vBatches) {
+ vChecks.reserve(BATCH_SIZE);
+ for (size_t x = 0; x < BATCH_SIZE; ++x)
+ vChecks.emplace_back(insecure_rand);
+ control.Add(vChecks);
+ }
+ // control waits for completion by RAII, but
+ // it is done explicitly here for clarity
+ control.Wait();
+ }
+ tg.interrupt_all();
+ tg.join_all();
+}
+BENCHMARK(CCheckQueueSpeed);
+BENCHMARK(CCheckQueueSpeedPrevectorJob);
diff --git a/src/bench/coin_selection.cpp b/src/bench/coin_selection.cpp
new file mode 100644
index 0000000000..42891f345b
--- /dev/null
+++ b/src/bench/coin_selection.cpp
@@ -0,0 +1,60 @@
+// Copyright (c) 2012-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 "wallet/wallet.h"
+
+#include <boost/foreach.hpp>
+#include <set>
+
+static void addCoin(const CAmount& nValue, const CWallet& wallet, std::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, MakeTransactionRef(std::move(tx)));
+
+ int nAge = 6 * 24;
+ COutput output(wtx, nInput, nAge, true /* spendable */, true /* solvable */, true /* safe */);
+ 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;
+ std::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);
+
+ std::set<CInputCoin> setCoinsRet;
+ CAmount nValueRet;
+ bool success = wallet.SelectCoinsMinConf(1003 * COIN, 1, 6, 0, vCoins, setCoinsRet, nValueRet);
+ assert(success);
+ assert(nValueRet == 1003 * COIN);
+ assert(setCoinsRet.size() == 2);
+ }
+}
+
+BENCHMARK(CoinSelection);
diff --git a/src/bench/crypto_hash.cpp b/src/bench/crypto_hash.cpp
index 168006154f..2914a36c7b 100644
--- a/src/bench/crypto_hash.cpp
+++ b/src/bench/crypto_hash.cpp
@@ -7,6 +7,7 @@
#include "bench.h"
#include "bloom.h"
#include "hash.h"
+#include "random.h"
#include "uint256.h"
#include "utiltime.h"
#include "crypto/ripemd160.h"
@@ -22,7 +23,7 @@ static void RIPEMD160(benchmark::State& state)
uint8_t hash[CRIPEMD160::OUTPUT_SIZE];
std::vector<uint8_t> in(BUFFER_SIZE,0);
while (state.KeepRunning())
- CRIPEMD160().Write(begin_ptr(in), in.size()).Finalize(hash);
+ CRIPEMD160().Write(in.data(), in.size()).Finalize(hash);
}
static void SHA1(benchmark::State& state)
@@ -30,7 +31,7 @@ static void SHA1(benchmark::State& state)
uint8_t hash[CSHA1::OUTPUT_SIZE];
std::vector<uint8_t> in(BUFFER_SIZE,0);
while (state.KeepRunning())
- CSHA1().Write(begin_ptr(in), in.size()).Finalize(hash);
+ CSHA1().Write(in.data(), in.size()).Finalize(hash);
}
static void SHA256(benchmark::State& state)
@@ -38,7 +39,7 @@ static void SHA256(benchmark::State& state)
uint8_t hash[CSHA256::OUTPUT_SIZE];
std::vector<uint8_t> in(BUFFER_SIZE,0);
while (state.KeepRunning())
- CSHA256().Write(begin_ptr(in), in.size()).Finalize(hash);
+ CSHA256().Write(in.data(), in.size()).Finalize(hash);
}
static void SHA256_32b(benchmark::State& state)
@@ -46,7 +47,7 @@ static void SHA256_32b(benchmark::State& state)
std::vector<uint8_t> in(32,0);
while (state.KeepRunning()) {
for (int i = 0; i < 1000000; i++) {
- CSHA256().Write(begin_ptr(in), in.size()).Finalize(&in[0]);
+ CSHA256().Write(in.data(), in.size()).Finalize(&in[0]);
}
}
}
@@ -56,7 +57,7 @@ static void SHA512(benchmark::State& state)
uint8_t hash[CSHA512::OUTPUT_SIZE];
std::vector<uint8_t> in(BUFFER_SIZE,0);
while (state.KeepRunning())
- CSHA512().Write(begin_ptr(in), in.size()).Finalize(hash);
+ CSHA512().Write(in.data(), in.size()).Finalize(hash);
}
static void SipHash_32b(benchmark::State& state)
@@ -69,6 +70,28 @@ static void SipHash_32b(benchmark::State& state)
}
}
+static void FastRandom_32bit(benchmark::State& state)
+{
+ FastRandomContext rng(true);
+ uint32_t x = 0;
+ while (state.KeepRunning()) {
+ for (int i = 0; i < 1000000; i++) {
+ x += rng.rand32();
+ }
+ }
+}
+
+static void FastRandom_1bit(benchmark::State& state)
+{
+ FastRandomContext rng(true);
+ uint32_t x = 0;
+ while (state.KeepRunning()) {
+ for (int i = 0; i < 1000000; i++) {
+ x += rng.randbool();
+ }
+ }
+}
+
BENCHMARK(RIPEMD160);
BENCHMARK(SHA1);
BENCHMARK(SHA256);
@@ -76,3 +99,5 @@ BENCHMARK(SHA512);
BENCHMARK(SHA256_32b);
BENCHMARK(SipHash_32b);
+BENCHMARK(FastRandom_32bit);
+BENCHMARK(FastRandom_1bit);
diff --git a/src/bench/data/block413567.raw b/src/bench/data/block413567.raw
new file mode 100644
index 0000000000..67d2d5d382
--- /dev/null
+++ b/src/bench/data/block413567.raw
Binary files differ
diff --git a/src/bench/lockedpool.cpp b/src/bench/lockedpool.cpp
new file mode 100644
index 0000000000..43a1422795
--- /dev/null
+++ b/src/bench/lockedpool.cpp
@@ -0,0 +1,47 @@
+// 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 "support/lockedpool.h"
+
+#include <iostream>
+#include <vector>
+
+#define ASIZE 2048
+#define BITER 5000
+#define MSIZE 2048
+
+static void BenchLockedPool(benchmark::State& state)
+{
+ void *synth_base = reinterpret_cast<void*>(0x08000000);
+ const size_t synth_size = 1024*1024;
+ Arena b(synth_base, synth_size, 16);
+
+ std::vector<void*> addr;
+ for (int x=0; x<ASIZE; ++x)
+ addr.push_back(0);
+ uint32_t s = 0x12345678;
+ while (state.KeepRunning()) {
+ for (int x=0; x<BITER; ++x) {
+ int idx = s & (addr.size()-1);
+ if (s & 0x80000000) {
+ b.free(addr[idx]);
+ addr[idx] = 0;
+ } else if(!addr[idx]) {
+ addr[idx] = b.alloc((s >> 16) & (MSIZE-1));
+ }
+ bool lsb = s & 1;
+ s >>= 1;
+ if (lsb)
+ s ^= 0xf00f00f0; // LFSR period 0xf7ffffe0
+ }
+ }
+ for (void *ptr: addr)
+ b.free(ptr);
+ addr.clear();
+}
+
+BENCHMARK(BenchLockedPool);
+
diff --git a/src/bench/mempool_eviction.cpp b/src/bench/mempool_eviction.cpp
new file mode 100644
index 0000000000..073bbde016
--- /dev/null
+++ b/src/bench/mempool_eviction.cpp
@@ -0,0 +1,114 @@
+// Copyright (c) 2011-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 "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;
+ unsigned int nHeight = 1;
+ bool spendsCoinbase = false;
+ unsigned int sigOpCost = 4;
+ LockPoints lp;
+ pool.addUnchecked(tx.GetHash(), CTxMemPoolEntry(
+ MakeTransactionRef(tx), nFee, nTime, nHeight,
+ 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;
+
+ 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/perf.cpp b/src/bench/perf.cpp
new file mode 100644
index 0000000000..a549ec29ea
--- /dev/null
+++ b/src/bench/perf.cpp
@@ -0,0 +1,53 @@
+// 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 "perf.h"
+
+#if defined(__i386__) || defined(__x86_64__)
+
+/* These architectures support querying the cycle counter
+ * from user space, no need for any syscall overhead.
+ */
+void perf_init(void) { }
+void perf_fini(void) { }
+
+#elif defined(__linux__)
+
+#include <unistd.h>
+#include <sys/syscall.h>
+#include <linux/perf_event.h>
+
+static int fd = -1;
+static struct perf_event_attr attr;
+
+void perf_init(void)
+{
+ attr.type = PERF_TYPE_HARDWARE;
+ attr.config = PERF_COUNT_HW_CPU_CYCLES;
+ fd = syscall(__NR_perf_event_open, &attr, 0, -1, -1, 0);
+}
+
+void perf_fini(void)
+{
+ if (fd != -1) {
+ close(fd);
+ }
+}
+
+uint64_t perf_cpucycles(void)
+{
+ uint64_t result = 0;
+ if (fd == -1 || read(fd, &result, sizeof(result)) < (ssize_t)sizeof(result)) {
+ return 0;
+ }
+ return result;
+}
+
+#else /* Unhandled platform */
+
+void perf_init(void) { }
+void perf_fini(void) { }
+uint64_t perf_cpucycles(void) { return 0; }
+
+#endif
diff --git a/src/bench/perf.h b/src/bench/perf.h
new file mode 100644
index 0000000000..681bd0c8a2
--- /dev/null
+++ b/src/bench/perf.h
@@ -0,0 +1,37 @@
+// 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.
+
+/** Functions for measurement of CPU cycles */
+#ifndef H_PERF
+#define H_PERF
+
+#include <stdint.h>
+
+#if defined(__i386__)
+
+static inline uint64_t perf_cpucycles(void)
+{
+ uint64_t x;
+ __asm__ volatile (".byte 0x0f, 0x31" : "=A" (x));
+ return x;
+}
+
+#elif defined(__x86_64__)
+
+static inline uint64_t perf_cpucycles(void)
+{
+ uint32_t hi, lo;
+ __asm__ __volatile__ ("rdtsc" : "=a"(lo), "=d"(hi));
+ return ((uint64_t)lo)|(((uint64_t)hi)<<32);
+}
+#else
+
+uint64_t perf_cpucycles(void);
+
+#endif
+
+void perf_init(void);
+void perf_fini(void);
+
+#endif // H_PERF
diff --git a/src/bench/prevector_destructor.cpp b/src/bench/prevector_destructor.cpp
new file mode 100644
index 0000000000..55af3de4fe
--- /dev/null
+++ b/src/bench/prevector_destructor.cpp
@@ -0,0 +1,36 @@
+// Copyright (c) 2015-2017 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 "prevector.h"
+
+static void PrevectorDestructor(benchmark::State& state)
+{
+ while (state.KeepRunning()) {
+ for (auto x = 0; x < 1000; ++x) {
+ prevector<28, unsigned char> t0;
+ prevector<28, unsigned char> t1;
+ t0.resize(28);
+ t1.resize(29);
+ }
+ }
+}
+
+static void PrevectorClear(benchmark::State& state)
+{
+
+ while (state.KeepRunning()) {
+ for (auto x = 0; x < 1000; ++x) {
+ prevector<28, unsigned char> t0;
+ prevector<28, unsigned char> t1;
+ t0.resize(28);
+ t0.clear();
+ t1.resize(29);
+ t0.clear();
+ }
+ }
+}
+
+BENCHMARK(PrevectorDestructor);
+BENCHMARK(PrevectorClear);
diff --git a/src/bench/verify_script.cpp b/src/bench/verify_script.cpp
new file mode 100644
index 0000000000..23bbadc88d
--- /dev/null
+++ b/src/bench/verify_script.cpp
@@ -0,0 +1,102 @@
+// 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.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.vin[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.vin[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(
+ txCredit.vout[0].scriptPubKey.data(),
+ txCredit.vout[0].scriptPubKey.size(),
+ txCredit.vout[0].nValue,
+ (const unsigned char*)stream.data(), stream.size(), 0, flags, nullptr);
+ assert(csuccess == 1);
+#endif
+ }
+}
+
+BENCHMARK(VerifyScriptBench);