Initial Vexta Core v0.1.0 release
This commit is contained in:
commit
25c454329d
2481 changed files with 689289 additions and 0 deletions
1
src/bench/.gitignore
vendored
Normal file
1
src/bench/.gitignore
vendored
Normal file
|
|
@ -0,0 +1 @@
|
|||
bench_digibyte
|
||||
141
src/bench/addrman.cpp
Normal file
141
src/bench/addrman.cpp
Normal file
|
|
@ -0,0 +1,141 @@
|
|||
// Copyright (c) 2020-2020 The DigiByte Core developers
|
||||
// Distributed under the MIT software license, see the accompanying
|
||||
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
|
||||
|
||||
#include <addrman.h>
|
||||
#include <bench/bench.h>
|
||||
#include <random.h>
|
||||
#include <util/time.h>
|
||||
|
||||
#include <optional>
|
||||
#include <vector>
|
||||
|
||||
/* A "source" is a source address from which we have received a bunch of other addresses. */
|
||||
|
||||
static constexpr size_t NUM_SOURCES = 64;
|
||||
static constexpr size_t NUM_ADDRESSES_PER_SOURCE = 256;
|
||||
|
||||
static std::vector<CAddress> g_sources;
|
||||
static std::vector<std::vector<CAddress>> g_addresses;
|
||||
|
||||
static void CreateAddresses()
|
||||
{
|
||||
if (g_sources.size() > 0) { // already created
|
||||
return;
|
||||
}
|
||||
|
||||
FastRandomContext rng(uint256(std::vector<unsigned char>(32, 123)));
|
||||
|
||||
auto randAddr = [&rng]() {
|
||||
in6_addr addr;
|
||||
memcpy(&addr, rng.randbytes(sizeof(addr)).data(), sizeof(addr));
|
||||
|
||||
uint16_t port;
|
||||
memcpy(&port, rng.randbytes(sizeof(port)).data(), sizeof(port));
|
||||
if (port == 0) {
|
||||
port = 1;
|
||||
}
|
||||
|
||||
CAddress ret(CService(addr, port), NODE_NETWORK);
|
||||
|
||||
ret.nTime = GetAdjustedTime();
|
||||
|
||||
return ret;
|
||||
};
|
||||
|
||||
for (size_t source_i = 0; source_i < NUM_SOURCES; ++source_i) {
|
||||
g_sources.emplace_back(randAddr());
|
||||
g_addresses.emplace_back();
|
||||
for (size_t addr_i = 0; addr_i < NUM_ADDRESSES_PER_SOURCE; ++addr_i) {
|
||||
g_addresses[source_i].emplace_back(randAddr());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void AddAddressesToAddrMan(CAddrMan& addrman)
|
||||
{
|
||||
for (size_t source_i = 0; source_i < NUM_SOURCES; ++source_i) {
|
||||
addrman.Add(g_addresses[source_i], g_sources[source_i]);
|
||||
}
|
||||
}
|
||||
|
||||
static void FillAddrMan(CAddrMan& addrman)
|
||||
{
|
||||
CreateAddresses();
|
||||
|
||||
AddAddressesToAddrMan(addrman);
|
||||
}
|
||||
|
||||
/* Benchmarks */
|
||||
|
||||
static void AddrManAdd(benchmark::Bench& bench)
|
||||
{
|
||||
CreateAddresses();
|
||||
|
||||
CAddrMan addrman;
|
||||
|
||||
bench.run([&] {
|
||||
AddAddressesToAddrMan(addrman);
|
||||
addrman.Clear();
|
||||
});
|
||||
}
|
||||
|
||||
static void AddrManSelect(benchmark::Bench& bench)
|
||||
{
|
||||
CAddrMan addrman;
|
||||
|
||||
FillAddrMan(addrman);
|
||||
|
||||
bench.run([&] {
|
||||
const auto& address = addrman.Select();
|
||||
assert(address.GetPort() > 0);
|
||||
});
|
||||
}
|
||||
|
||||
static void AddrManGetAddr(benchmark::Bench& bench)
|
||||
{
|
||||
CAddrMan addrman;
|
||||
|
||||
FillAddrMan(addrman);
|
||||
|
||||
bench.run([&] {
|
||||
const auto& addresses = addrman.GetAddr(/* max_addresses */ 2500, /* max_pct */ 23, /* network */ std::nullopt);
|
||||
assert(addresses.size() > 0);
|
||||
});
|
||||
}
|
||||
|
||||
static void AddrManGood(benchmark::Bench& bench)
|
||||
{
|
||||
/* Create many CAddrMan objects - one to be modified at each loop iteration.
|
||||
* This is necessary because the CAddrMan::Good() method modifies the
|
||||
* object, affecting the timing of subsequent calls to the same method and
|
||||
* we want to do the same amount of work in every loop iteration. */
|
||||
|
||||
bench.epochs(5).epochIterations(1);
|
||||
|
||||
std::vector<CAddrMan> addrmans(bench.epochs() * bench.epochIterations());
|
||||
for (auto& addrman : addrmans) {
|
||||
FillAddrMan(addrman);
|
||||
}
|
||||
|
||||
auto markSomeAsGood = [](CAddrMan& addrman) {
|
||||
for (size_t source_i = 0; source_i < NUM_SOURCES; ++source_i) {
|
||||
for (size_t addr_i = 0; addr_i < NUM_ADDRESSES_PER_SOURCE; ++addr_i) {
|
||||
if (addr_i % 32 == 0) {
|
||||
addrman.Good(g_addresses[source_i][addr_i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
uint64_t i = 0;
|
||||
bench.run([&] {
|
||||
markSomeAsGood(addrmans.at(i));
|
||||
++i;
|
||||
});
|
||||
}
|
||||
|
||||
BENCHMARK(AddrManAdd);
|
||||
BENCHMARK(AddrManSelect);
|
||||
BENCHMARK(AddrManGetAddr);
|
||||
BENCHMARK(AddrManGood);
|
||||
56
src/bench/base58.cpp
Normal file
56
src/bench/base58.cpp
Normal file
|
|
@ -0,0 +1,56 @@
|
|||
// Copyright (c) 2016-2020 The Bitcoin Core developers
|
||||
// Copyright (c) 2016-2020 The DigiByte Core developers
|
||||
// Distributed under the MIT software license, see the accompanying
|
||||
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
|
||||
|
||||
#include <bench/bench.h>
|
||||
|
||||
#include <base58.h>
|
||||
|
||||
#include <array>
|
||||
#include <vector>
|
||||
|
||||
|
||||
static void Base58Encode(benchmark::Bench& bench)
|
||||
{
|
||||
static const std::array<unsigned char, 32> buff = {
|
||||
{
|
||||
17, 79, 8, 99, 150, 189, 208, 162, 22, 23, 203, 163, 36, 58, 147,
|
||||
227, 139, 2, 215, 100, 91, 38, 11, 141, 253, 40, 117, 21, 16, 90,
|
||||
200, 24
|
||||
}
|
||||
};
|
||||
bench.batch(buff.size()).unit("byte").run([&] {
|
||||
EncodeBase58(buff);
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
static void Base58CheckEncode(benchmark::Bench& bench)
|
||||
{
|
||||
static const std::array<unsigned char, 32> buff = {
|
||||
{
|
||||
17, 79, 8, 99, 150, 189, 208, 162, 22, 23, 203, 163, 36, 58, 147,
|
||||
227, 139, 2, 215, 100, 91, 38, 11, 141, 253, 40, 117, 21, 16, 90,
|
||||
200, 24
|
||||
}
|
||||
};
|
||||
bench.batch(buff.size()).unit("byte").run([&] {
|
||||
EncodeBase58Check(buff);
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
static void Base58Decode(benchmark::Bench& bench)
|
||||
{
|
||||
const char* addr = "17VZNX1SN5NtKa8UQFxwQbFeFc3iqRYhem";
|
||||
std::vector<unsigned char> vch;
|
||||
bench.batch(strlen(addr)).unit("byte").run([&] {
|
||||
(void) DecodeBase58(addr, vch, 64);
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
BENCHMARK(Base58Encode);
|
||||
BENCHMARK(Base58CheckEncode);
|
||||
BENCHMARK(Base58Decode);
|
||||
38
src/bench/bech32.cpp
Normal file
38
src/bench/bech32.cpp
Normal file
|
|
@ -0,0 +1,38 @@
|
|||
// Copyright (c) 2018-2020 The Bitcoin Core developers
|
||||
// Copyright (c) 2018-2020 The DigiByte Core developers
|
||||
// Distributed under the MIT software license, see the accompanying
|
||||
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
|
||||
|
||||
#include <bench/bench.h>
|
||||
#include <bench/nanobench.h>
|
||||
|
||||
#include <bech32.h>
|
||||
#include <util/strencodings.h>
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
|
||||
static void Bech32Encode(benchmark::Bench& bench)
|
||||
{
|
||||
std::vector<uint8_t> v = ParseHex("c97f5a67ec381b760aeaf67573bc164845ff39a3bb26a1cee401ac67243b48db");
|
||||
std::vector<unsigned char> tmp = {0};
|
||||
tmp.reserve(1 + 32 * 8 / 5);
|
||||
ConvertBits<8, 5, true>([&](unsigned char c) { tmp.push_back(c); }, v.begin(), v.end());
|
||||
bench.batch(v.size()).unit("byte").run([&] {
|
||||
bech32::Encode(bech32::Encoding::BECH32, "bc", tmp);
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
static void Bech32Decode(benchmark::Bench& bench)
|
||||
{
|
||||
std::string addr = "bc1qkallence7tjawwvy0dwt4twc62qjgaw8f4vlhyd006d99f09";
|
||||
bench.batch(addr.size()).unit("byte").run([&] {
|
||||
bech32::Decode(addr);
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
BENCHMARK(Bech32Encode);
|
||||
BENCHMARK(Bech32Decode);
|
||||
84
src/bench/bench.cpp
Normal file
84
src/bench/bench.cpp
Normal file
|
|
@ -0,0 +1,84 @@
|
|||
// Copyright (c) 2015-2020 The Bitcoin Core developers
|
||||
// Copyright (c) 2015-2020 The DigiByte Core developers
|
||||
// Distributed under the MIT software license, see the accompanying
|
||||
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
|
||||
|
||||
#include <bench/bench.h>
|
||||
|
||||
#include <chainparams.h>
|
||||
#include <test/util/setup_common.h>
|
||||
#include <validation.h>
|
||||
|
||||
#include <regex>
|
||||
|
||||
const std::function<void(const std::string&)> G_TEST_LOG_FUN{};
|
||||
|
||||
namespace {
|
||||
|
||||
void GenerateTemplateResults(const std::vector<ankerl::nanobench::Result>& benchmarkResults, const std::string& filename, const char* tpl)
|
||||
{
|
||||
if (benchmarkResults.empty() || filename.empty()) {
|
||||
// nothing to write, bail out
|
||||
return;
|
||||
}
|
||||
std::ofstream fout(filename);
|
||||
if (fout.is_open()) {
|
||||
ankerl::nanobench::render(tpl, benchmarkResults, fout);
|
||||
} else {
|
||||
std::cout << "Could write to file '" << filename << "'" << std::endl;
|
||||
}
|
||||
|
||||
std::cout << "Created '" << filename << "'" << std::endl;
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
benchmark::BenchRunner::BenchmarkMap& benchmark::BenchRunner::benchmarks()
|
||||
{
|
||||
static std::map<std::string, BenchFunction> benchmarks_map;
|
||||
return benchmarks_map;
|
||||
}
|
||||
|
||||
benchmark::BenchRunner::BenchRunner(std::string name, benchmark::BenchFunction func)
|
||||
{
|
||||
benchmarks().insert(std::make_pair(name, func));
|
||||
}
|
||||
|
||||
void benchmark::BenchRunner::RunAll(const Args& args)
|
||||
{
|
||||
std::regex reFilter(args.regex_filter);
|
||||
std::smatch baseMatch;
|
||||
|
||||
std::vector<ankerl::nanobench::Result> benchmarkResults;
|
||||
for (const auto& p : benchmarks()) {
|
||||
if (!std::regex_match(p.first, baseMatch, reFilter)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (args.is_list_only) {
|
||||
std::cout << p.first << std::endl;
|
||||
continue;
|
||||
}
|
||||
|
||||
Bench bench;
|
||||
bench.name(p.first);
|
||||
if (args.asymptote.empty()) {
|
||||
p.second(bench);
|
||||
} else {
|
||||
for (auto n : args.asymptote) {
|
||||
bench.complexityN(n);
|
||||
p.second(bench);
|
||||
}
|
||||
std::cout << bench.complexityBigO() << std::endl;
|
||||
}
|
||||
|
||||
if (!bench.results().empty()) {
|
||||
benchmarkResults.push_back(bench.results().back());
|
||||
}
|
||||
}
|
||||
|
||||
GenerateTemplateResults(benchmarkResults, args.output_csv, "# Benchmark, evals, iterations, total, min, max, median\n"
|
||||
"{{#result}}{{name}}, {{epochs}}, {{average(iterations)}}, {{sumProduct(iterations, elapsed)}}, {{minimum(elapsed)}}, {{maximum(elapsed)}}, {{median(elapsed)}}\n"
|
||||
"{{/result}}");
|
||||
GenerateTemplateResults(benchmarkResults, args.output_json, ankerl::nanobench::templates::json());
|
||||
}
|
||||
68
src/bench/bench.h
Normal file
68
src/bench/bench.h
Normal file
|
|
@ -0,0 +1,68 @@
|
|||
// Copyright (c) 2015-2020 The Bitcoin Core developers
|
||||
// Copyright (c) 2015-2020 The DigiByte Core developers
|
||||
// Distributed under the MIT software license, see the accompanying
|
||||
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
|
||||
|
||||
#ifndef DIGIBYTE_BENCH_BENCH_H
|
||||
#define DIGIBYTE_BENCH_BENCH_H
|
||||
|
||||
#include <util/macros.h>
|
||||
|
||||
#include <chrono>
|
||||
#include <functional>
|
||||
#include <map>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include <bench/nanobench.h>
|
||||
|
||||
/*
|
||||
* Usage:
|
||||
|
||||
static void NameOfYourBenchmarkFunction(benchmark::Bench& bench)
|
||||
{
|
||||
...do any setup needed...
|
||||
|
||||
bench.run([&] {
|
||||
...do stuff you want to time; refer to src/bench/nanobench.h
|
||||
for more information and the options that can be passed here...
|
||||
});
|
||||
|
||||
...do any cleanup needed...
|
||||
}
|
||||
|
||||
BENCHMARK(NameOfYourBenchmarkFunction);
|
||||
|
||||
*/
|
||||
|
||||
namespace benchmark {
|
||||
|
||||
using ankerl::nanobench::Bench;
|
||||
|
||||
typedef std::function<void(Bench&)> BenchFunction;
|
||||
|
||||
struct Args {
|
||||
std::string regex_filter;
|
||||
bool is_list_only;
|
||||
std::vector<double> asymptote;
|
||||
std::string output_csv;
|
||||
std::string output_json;
|
||||
};
|
||||
|
||||
class BenchRunner
|
||||
{
|
||||
typedef std::map<std::string, BenchFunction> BenchmarkMap;
|
||||
static BenchmarkMap& benchmarks();
|
||||
|
||||
public:
|
||||
BenchRunner(std::string name, BenchFunction func);
|
||||
|
||||
static void RunAll(const Args& args);
|
||||
};
|
||||
} // namespace benchmark
|
||||
|
||||
// BENCHMARK(foo) expands to: benchmark::BenchRunner bench_11foo("foo", foo);
|
||||
#define BENCHMARK(n) \
|
||||
benchmark::BenchRunner PASTE2(bench_, PASTE2(__LINE__, n))(STRINGIZE(n), n);
|
||||
|
||||
#endif // DIGIBYTE_BENCH_BENCH_H
|
||||
67
src/bench/bench_digibyte.cpp
Normal file
67
src/bench/bench_digibyte.cpp
Normal file
|
|
@ -0,0 +1,67 @@
|
|||
// Copyright (c) 2015-2020 The Bitcoin Core developers
|
||||
// Copyright (c) 2015-2021 The DigiByte Core developers
|
||||
// Distributed under the MIT software license, see the accompanying
|
||||
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
|
||||
|
||||
#include <bench/bench.h>
|
||||
|
||||
#include <crypto/sha256.h>
|
||||
#include <util/strencodings.h>
|
||||
#include <util/system.h>
|
||||
|
||||
#include <memory>
|
||||
|
||||
static const char* DEFAULT_BENCH_FILTER = ".*";
|
||||
|
||||
static void SetupBenchArgs(ArgsManager& argsman)
|
||||
{
|
||||
SetupHelpOptions(argsman);
|
||||
|
||||
argsman.AddArg("-list", "List benchmarks without executing them", ArgsManager::ALLOW_ANY, OptionsCategory::OPTIONS);
|
||||
argsman.AddArg("-filter=<regex>", strprintf("Regular expression filter to select benchmark by name (default: %s)", DEFAULT_BENCH_FILTER), ArgsManager::ALLOW_ANY, OptionsCategory::OPTIONS);
|
||||
argsman.AddArg("-asymptote=n1,n2,n3,...", strprintf("Test asymptotic growth of the runtime of an algorithm, if supported by the benchmark"), ArgsManager::ALLOW_ANY, OptionsCategory::OPTIONS);
|
||||
argsman.AddArg("-output_csv=<output.csv>", "Generate CSV file with the most important benchmark results.", ArgsManager::ALLOW_ANY, OptionsCategory::OPTIONS);
|
||||
argsman.AddArg("-output_json=<output.json>", "Generate JSON file with all benchmark results.", ArgsManager::ALLOW_ANY, OptionsCategory::OPTIONS);
|
||||
}
|
||||
|
||||
// parses a comma separated list like "10,20,30,50"
|
||||
static std::vector<double> parseAsymptote(const std::string& str) {
|
||||
std::stringstream ss(str);
|
||||
std::vector<double> numbers;
|
||||
double d;
|
||||
char c;
|
||||
while (ss >> d) {
|
||||
numbers.push_back(d);
|
||||
ss >> c;
|
||||
}
|
||||
return numbers;
|
||||
}
|
||||
|
||||
int main(int argc, char** argv)
|
||||
{
|
||||
ArgsManager argsman;
|
||||
SetupBenchArgs(argsman);
|
||||
SHA256AutoDetect();
|
||||
std::string error;
|
||||
if (!argsman.ParseParameters(argc, argv, error)) {
|
||||
tfm::format(std::cerr, "Error parsing command line arguments: %s\n", error);
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
if (HelpRequested(argsman)) {
|
||||
std::cout << argsman.GetHelpMessage();
|
||||
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
|
||||
benchmark::Args args;
|
||||
args.regex_filter = argsman.GetArg("-filter", DEFAULT_BENCH_FILTER);
|
||||
args.is_list_only = argsman.GetBoolArg("-list", false);
|
||||
args.asymptote = parseAsymptote(argsman.GetArg("-asymptote", ""));
|
||||
args.output_csv = argsman.GetArg("-output_csv", "");
|
||||
args.output_json = argsman.GetArg("-output_json", "");
|
||||
|
||||
benchmark::BenchRunner::RunAll(args);
|
||||
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
51
src/bench/block_assemble.cpp
Normal file
51
src/bench/block_assemble.cpp
Normal file
|
|
@ -0,0 +1,51 @@
|
|||
// Copyright (c) 2011-2020 The Bitcoin Core developers
|
||||
// Copyright (c) 2014-2020 The DigiByte Core developers
|
||||
// Distributed under the MIT software license, see the accompanying
|
||||
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
|
||||
|
||||
#include <bench/bench.h>
|
||||
#include <consensus/validation.h>
|
||||
#include <crypto/sha256.h>
|
||||
#include <test/util/mining.h>
|
||||
#include <test/util/script.h>
|
||||
#include <test/util/setup_common.h>
|
||||
#include <test/util/wallet.h>
|
||||
#include <txmempool.h>
|
||||
#include <validation.h>
|
||||
|
||||
|
||||
#include <vector>
|
||||
|
||||
static void AssembleBlock(benchmark::Bench& bench)
|
||||
{
|
||||
const auto test_setup = MakeNoLogFileContext<const TestingSetup>();
|
||||
|
||||
CScriptWitness witness;
|
||||
witness.stack.push_back(WITNESS_STACK_ELEM_OP_TRUE);
|
||||
|
||||
// Collect some loose transactions that spend the coinbases of our mined blocks
|
||||
constexpr size_t NUM_BLOCKS{130};
|
||||
std::array<CTransactionRef, NUM_BLOCKS - COINBASE_MATURITY_2 + 1> txs;
|
||||
for (size_t b{0}; b < NUM_BLOCKS; ++b) {
|
||||
CMutableTransaction tx;
|
||||
tx.vin.push_back(MineBlock(test_setup->m_node, P2WSH_OP_TRUE));
|
||||
tx.vin.back().scriptWitness = witness;
|
||||
tx.vout.emplace_back(1337, P2WSH_OP_TRUE);
|
||||
if (NUM_BLOCKS - b >= COINBASE_MATURITY)
|
||||
txs.at(b) = MakeTransactionRef(tx);
|
||||
}
|
||||
{
|
||||
LOCK(::cs_main); // Required for ::AcceptToMemoryPool.
|
||||
|
||||
for (const auto& txr : txs) {
|
||||
const MempoolAcceptResult res = ::AcceptToMemoryPool(test_setup->m_node.chainman->ActiveChainstate(), *test_setup->m_node.mempool, txr, false /* bypass_limits */);
|
||||
assert(res.m_result_type == MempoolAcceptResult::ResultType::VALID);
|
||||
}
|
||||
}
|
||||
|
||||
bench.run([&] {
|
||||
PrepareBlock(test_setup->m_node, P2WSH_OP_TRUE);
|
||||
});
|
||||
}
|
||||
|
||||
BENCHMARK(AssembleBlock);
|
||||
55
src/bench/ccoins_caching.cpp
Normal file
55
src/bench/ccoins_caching.cpp
Normal file
|
|
@ -0,0 +1,55 @@
|
|||
// Copyright (c) 2016-2020 The Bitcoin Core developers
|
||||
// Copyright (c) 2016-2020 The DigiByte Core developers
|
||||
// Distributed under the MIT software license, see the accompanying
|
||||
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
|
||||
|
||||
#include <bench/bench.h>
|
||||
#include <coins.h>
|
||||
#include <policy/policy.h>
|
||||
#include <script/signingprovider.h>
|
||||
#include <test/util/transaction_utils.h>
|
||||
|
||||
#include <vector>
|
||||
|
||||
// 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/digibyte/digibyte/issues/7883#issuecomment-224807484)
|
||||
static void CCoinsCaching(benchmark::Bench& bench)
|
||||
{
|
||||
const ECCVerifyHandle verify_handle;
|
||||
ECC_Start();
|
||||
|
||||
FillableSigningProvider keystore;
|
||||
CCoinsView coinsDummy;
|
||||
CCoinsViewCache coins(&coinsDummy);
|
||||
std::vector<CMutableTransaction> dummyTransactions =
|
||||
SetupDummyInputs(keystore, coins, {11 * COIN, 50 * COIN, 21 * COIN, 22 * COIN});
|
||||
|
||||
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 * COIN;
|
||||
t1.vout[0].scriptPubKey << OP_1;
|
||||
|
||||
// Benchmark.
|
||||
const CTransaction tx_1(t1);
|
||||
bench.run([&] {
|
||||
bool success = AreInputsStandard(tx_1, coins, false);
|
||||
assert(success);
|
||||
});
|
||||
ECC_Stop();
|
||||
}
|
||||
|
||||
BENCHMARK(CCoinsCaching);
|
||||
44
src/bench/chacha20.cpp
Normal file
44
src/bench/chacha20.cpp
Normal file
|
|
@ -0,0 +1,44 @@
|
|||
// Copyright (c) 2019-2020 The DigiByte Core developers
|
||||
// Distributed under the MIT software license, see the accompanying
|
||||
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
|
||||
|
||||
|
||||
#include <bench/bench.h>
|
||||
#include <crypto/chacha20.h>
|
||||
|
||||
/* Number of bytes to process per iteration */
|
||||
static const uint64_t BUFFER_SIZE_TINY = 64;
|
||||
static const uint64_t BUFFER_SIZE_SMALL = 256;
|
||||
static const uint64_t BUFFER_SIZE_LARGE = 1024*1024;
|
||||
|
||||
static void CHACHA20(benchmark::Bench& bench, size_t buffersize)
|
||||
{
|
||||
std::vector<uint8_t> key(32,0);
|
||||
ChaCha20 ctx(key.data(), key.size());
|
||||
ctx.SetIV(0);
|
||||
ctx.Seek(0);
|
||||
std::vector<uint8_t> in(buffersize,0);
|
||||
std::vector<uint8_t> out(buffersize,0);
|
||||
bench.batch(in.size()).unit("byte").run([&] {
|
||||
ctx.Crypt(in.data(), out.data(), in.size());
|
||||
});
|
||||
}
|
||||
|
||||
static void CHACHA20_64BYTES(benchmark::Bench& bench)
|
||||
{
|
||||
CHACHA20(bench, BUFFER_SIZE_TINY);
|
||||
}
|
||||
|
||||
static void CHACHA20_256BYTES(benchmark::Bench& bench)
|
||||
{
|
||||
CHACHA20(bench, BUFFER_SIZE_SMALL);
|
||||
}
|
||||
|
||||
static void CHACHA20_1MB(benchmark::Bench& bench)
|
||||
{
|
||||
CHACHA20(bench, BUFFER_SIZE_LARGE);
|
||||
}
|
||||
|
||||
BENCHMARK(CHACHA20_64BYTES);
|
||||
BENCHMARK(CHACHA20_256BYTES);
|
||||
BENCHMARK(CHACHA20_1MB);
|
||||
126
src/bench/chacha_poly_aead.cpp
Normal file
126
src/bench/chacha_poly_aead.cpp
Normal file
|
|
@ -0,0 +1,126 @@
|
|||
// Copyright (c) 2019-2020 The DigiByte Core developers
|
||||
// Distributed under the MIT software license, see the accompanying
|
||||
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
|
||||
|
||||
|
||||
#include <bench/bench.h>
|
||||
#include <crypto/chacha_poly_aead.h>
|
||||
#include <crypto/poly1305.h> // for the POLY1305_TAGLEN constant
|
||||
#include <hash.h>
|
||||
|
||||
#include <assert.h>
|
||||
#include <limits>
|
||||
|
||||
/* Number of bytes to process per iteration */
|
||||
static constexpr uint64_t BUFFER_SIZE_TINY = 64;
|
||||
static constexpr uint64_t BUFFER_SIZE_SMALL = 256;
|
||||
static constexpr uint64_t BUFFER_SIZE_LARGE = 1024 * 1024;
|
||||
|
||||
static const unsigned char k1[32] = {0};
|
||||
static const unsigned char k2[32] = {0};
|
||||
|
||||
static ChaCha20Poly1305AEAD aead(k1, 32, k2, 32);
|
||||
|
||||
static void CHACHA20_POLY1305_AEAD(benchmark::Bench& bench, size_t buffersize, bool include_decryption)
|
||||
{
|
||||
std::vector<unsigned char> in(buffersize + CHACHA20_POLY1305_AEAD_AAD_LEN + POLY1305_TAGLEN, 0);
|
||||
std::vector<unsigned char> out(buffersize + CHACHA20_POLY1305_AEAD_AAD_LEN + POLY1305_TAGLEN, 0);
|
||||
uint64_t seqnr_payload = 0;
|
||||
uint64_t seqnr_aad = 0;
|
||||
int aad_pos = 0;
|
||||
uint32_t len = 0;
|
||||
bench.batch(buffersize).unit("byte").run([&] {
|
||||
// encrypt or decrypt the buffer with a static key
|
||||
const bool crypt_ok_1 = aead.Crypt(seqnr_payload, seqnr_aad, aad_pos, out.data(), out.size(), in.data(), buffersize, true);
|
||||
assert(crypt_ok_1);
|
||||
|
||||
if (include_decryption) {
|
||||
// if we decrypt, include the GetLength
|
||||
const bool get_length_ok = aead.GetLength(&len, seqnr_aad, aad_pos, in.data());
|
||||
assert(get_length_ok);
|
||||
const bool crypt_ok_2 = aead.Crypt(seqnr_payload, seqnr_aad, aad_pos, out.data(), out.size(), in.data(), buffersize, true);
|
||||
assert(crypt_ok_2);
|
||||
}
|
||||
|
||||
// increase main sequence number
|
||||
seqnr_payload++;
|
||||
// increase aad position (position in AAD keystream)
|
||||
aad_pos += CHACHA20_POLY1305_AEAD_AAD_LEN;
|
||||
if (aad_pos + CHACHA20_POLY1305_AEAD_AAD_LEN > CHACHA20_ROUND_OUTPUT) {
|
||||
aad_pos = 0;
|
||||
seqnr_aad++;
|
||||
}
|
||||
if (seqnr_payload + 1 == std::numeric_limits<uint64_t>::max()) {
|
||||
// reuse of nonce+key is okay while benchmarking.
|
||||
seqnr_payload = 0;
|
||||
seqnr_aad = 0;
|
||||
aad_pos = 0;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
static void CHACHA20_POLY1305_AEAD_64BYTES_ONLY_ENCRYPT(benchmark::Bench& bench)
|
||||
{
|
||||
CHACHA20_POLY1305_AEAD(bench, BUFFER_SIZE_TINY, false);
|
||||
}
|
||||
|
||||
static void CHACHA20_POLY1305_AEAD_256BYTES_ONLY_ENCRYPT(benchmark::Bench& bench)
|
||||
{
|
||||
CHACHA20_POLY1305_AEAD(bench, BUFFER_SIZE_SMALL, false);
|
||||
}
|
||||
|
||||
static void CHACHA20_POLY1305_AEAD_1MB_ONLY_ENCRYPT(benchmark::Bench& bench)
|
||||
{
|
||||
CHACHA20_POLY1305_AEAD(bench, BUFFER_SIZE_LARGE, false);
|
||||
}
|
||||
|
||||
static void CHACHA20_POLY1305_AEAD_64BYTES_ENCRYPT_DECRYPT(benchmark::Bench& bench)
|
||||
{
|
||||
CHACHA20_POLY1305_AEAD(bench, BUFFER_SIZE_TINY, true);
|
||||
}
|
||||
|
||||
static void CHACHA20_POLY1305_AEAD_256BYTES_ENCRYPT_DECRYPT(benchmark::Bench& bench)
|
||||
{
|
||||
CHACHA20_POLY1305_AEAD(bench, BUFFER_SIZE_SMALL, true);
|
||||
}
|
||||
|
||||
static void CHACHA20_POLY1305_AEAD_1MB_ENCRYPT_DECRYPT(benchmark::Bench& bench)
|
||||
{
|
||||
CHACHA20_POLY1305_AEAD(bench, BUFFER_SIZE_LARGE, true);
|
||||
}
|
||||
|
||||
// Add Hash() (dbl-sha256) bench for comparison
|
||||
|
||||
static void HASH(benchmark::Bench& bench, size_t buffersize)
|
||||
{
|
||||
uint8_t hash[CHash256::OUTPUT_SIZE];
|
||||
std::vector<uint8_t> in(buffersize,0);
|
||||
bench.batch(in.size()).unit("byte").run([&] {
|
||||
CHash256().Write(in).Finalize(hash);
|
||||
});
|
||||
}
|
||||
|
||||
static void HASH_64BYTES(benchmark::Bench& bench)
|
||||
{
|
||||
HASH(bench, BUFFER_SIZE_TINY);
|
||||
}
|
||||
|
||||
static void HASH_256BYTES(benchmark::Bench& bench)
|
||||
{
|
||||
HASH(bench, BUFFER_SIZE_SMALL);
|
||||
}
|
||||
|
||||
static void HASH_1MB(benchmark::Bench& bench)
|
||||
{
|
||||
HASH(bench, BUFFER_SIZE_LARGE);
|
||||
}
|
||||
|
||||
BENCHMARK(CHACHA20_POLY1305_AEAD_64BYTES_ONLY_ENCRYPT);
|
||||
BENCHMARK(CHACHA20_POLY1305_AEAD_256BYTES_ONLY_ENCRYPT);
|
||||
BENCHMARK(CHACHA20_POLY1305_AEAD_1MB_ONLY_ENCRYPT);
|
||||
BENCHMARK(CHACHA20_POLY1305_AEAD_64BYTES_ENCRYPT_DECRYPT);
|
||||
BENCHMARK(CHACHA20_POLY1305_AEAD_256BYTES_ENCRYPT_DECRYPT);
|
||||
BENCHMARK(CHACHA20_POLY1305_AEAD_1MB_ENCRYPT_DECRYPT);
|
||||
BENCHMARK(HASH_64BYTES);
|
||||
BENCHMARK(HASH_256BYTES);
|
||||
BENCHMARK(HASH_1MB);
|
||||
54
src/bench/checkblock.cpp
Normal file
54
src/bench/checkblock.cpp
Normal file
|
|
@ -0,0 +1,54 @@
|
|||
// Copyright (c) 2016-2020 The Bitcoin Core developers
|
||||
// Copyright (c) 2016-2020 The DigiByte Core developers
|
||||
// Distributed under the MIT software license, see the accompanying
|
||||
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
|
||||
|
||||
#include <bench/bench.h>
|
||||
#include <bench/data.h>
|
||||
|
||||
#include <chainparams.h>
|
||||
#include <consensus/validation.h>
|
||||
#include <streams.h>
|
||||
#include <validation.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::Bench& bench)
|
||||
{
|
||||
CDataStream stream(benchmark::data::block413567, SER_NETWORK, PROTOCOL_VERSION);
|
||||
char a = '\0';
|
||||
stream.write(&a, 1); // Prevent compaction
|
||||
|
||||
bench.unit("block").run([&] {
|
||||
CBlock block;
|
||||
stream >> block;
|
||||
bool rewound = stream.Rewind(benchmark::data::block413567.size());
|
||||
assert(rewound);
|
||||
});
|
||||
}
|
||||
|
||||
static void DeserializeAndCheckBlockTest(benchmark::Bench& bench)
|
||||
{
|
||||
CDataStream stream(benchmark::data::block413567, SER_NETWORK, PROTOCOL_VERSION);
|
||||
char a = '\0';
|
||||
stream.write(&a, 1); // Prevent compaction
|
||||
|
||||
ArgsManager bench_args;
|
||||
const auto chainParams = CreateChainParams(bench_args, CBaseChainParams::MAIN);
|
||||
|
||||
bench.unit("block").run([&] {
|
||||
CBlock block; // Note that CBlock caches its checked state, so we need to recreate it here
|
||||
stream >> block;
|
||||
bool rewound = stream.Rewind(benchmark::data::block413567.size());
|
||||
assert(rewound);
|
||||
|
||||
BlockValidationState validationState;
|
||||
bool checked = CheckBlock(block, validationState, chainParams->GetConsensus());
|
||||
assert(checked);
|
||||
});
|
||||
}
|
||||
|
||||
BENCHMARK(DeserializeBlockTest);
|
||||
BENCHMARK(DeserializeAndCheckBlockTest);
|
||||
72
src/bench/checkqueue.cpp
Normal file
72
src/bench/checkqueue.cpp
Normal file
|
|
@ -0,0 +1,72 @@
|
|||
// Copyright (c) 2015-2020 The Bitcoin Core developers
|
||||
// Copyright (c) 2015-2020 The DigiByte Core developers
|
||||
// Distributed under the MIT software license, see the accompanying
|
||||
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
|
||||
|
||||
#include <bench/bench.h>
|
||||
#include <checkqueue.h>
|
||||
#include <key.h>
|
||||
#include <prevector.h>
|
||||
#include <pubkey.h>
|
||||
#include <random.h>
|
||||
#include <util/system.h>
|
||||
|
||||
#include <vector>
|
||||
|
||||
static const size_t BATCHES = 101;
|
||||
static const size_t BATCH_SIZE = 30;
|
||||
static const int PREVECTOR_SIZE = 28;
|
||||
static const unsigned int QUEUE_BATCH_SIZE = 128;
|
||||
|
||||
// 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::Bench& bench)
|
||||
{
|
||||
// We shouldn't ever be running with the checkqueue on a single core machine.
|
||||
if (GetNumCores() <= 1) return;
|
||||
|
||||
const ECCVerifyHandle verify_handle;
|
||||
ECC_Start();
|
||||
|
||||
struct PrevectorJob {
|
||||
prevector<PREVECTOR_SIZE, uint8_t> p;
|
||||
PrevectorJob(){
|
||||
}
|
||||
explicit 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};
|
||||
// The main thread should be counted to prevent thread oversubscription, and
|
||||
// to decrease the variance of benchmark results.
|
||||
queue.StartWorkerThreads(GetNumCores() - 1);
|
||||
|
||||
// create all the data once, then submit copies in the benchmark.
|
||||
FastRandomContext insecure_rand(true);
|
||||
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);
|
||||
}
|
||||
|
||||
bench.minEpochIterations(10).batch(BATCH_SIZE * BATCHES).unit("job").run([&] {
|
||||
// Make insecure_rand here so that each iteration is identical.
|
||||
CCheckQueueControl<PrevectorJob> control(&queue);
|
||||
for (auto vChecks : vBatches) {
|
||||
control.Add(vChecks);
|
||||
}
|
||||
// control waits for completion by RAII, but
|
||||
// it is done explicitly here for clarity
|
||||
control.Wait();
|
||||
});
|
||||
queue.StopWorkerThreads();
|
||||
ECC_Stop();
|
||||
}
|
||||
BENCHMARK(CCheckQueueSpeedPrevectorJob);
|
||||
117
src/bench/coin_selection.cpp
Normal file
117
src/bench/coin_selection.cpp
Normal file
|
|
@ -0,0 +1,117 @@
|
|||
// Copyright (c) 2012-2020 The Bitcoin Core developers
|
||||
// Copyright (c) 2014-2020 The DigiByte Core developers
|
||||
// Distributed under the MIT software license, see the accompanying
|
||||
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
|
||||
|
||||
#include <bench/bench.h>
|
||||
#include <interfaces/chain.h>
|
||||
#include <node/context.h>
|
||||
#include <wallet/coinselection.h>
|
||||
#include <wallet/wallet.h>
|
||||
|
||||
#include <set>
|
||||
|
||||
static void addCoin(const CAmount& nValue, const CWallet& wallet, std::vector<std::unique_ptr<CWalletTx>>& wtxs)
|
||||
{
|
||||
static int nextLockTime = 0;
|
||||
CMutableTransaction tx;
|
||||
tx.nLockTime = nextLockTime++; // so all transactions get different hashes
|
||||
tx.vout.resize(1);
|
||||
tx.vout[0].nValue = nValue;
|
||||
wtxs.push_back(std::make_unique<CWalletTx>(&wallet, MakeTransactionRef(std::move(tx))));
|
||||
}
|
||||
|
||||
// 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/digibyte/digibyte/issues/7883#issuecomment-224807484)
|
||||
static void CoinSelection(benchmark::Bench& bench)
|
||||
{
|
||||
NodeContext node;
|
||||
auto chain = interfaces::MakeChain(node);
|
||||
CWallet wallet(chain.get(), "", CreateDummyWalletDatabase());
|
||||
wallet.SetupLegacyScriptPubKeyMan();
|
||||
std::vector<std::unique_ptr<CWalletTx>> wtxs;
|
||||
LOCK(wallet.cs_wallet);
|
||||
|
||||
// Add coins.
|
||||
for (int i = 0; i < 1000; ++i) {
|
||||
addCoin(1000 * COIN, wallet, wtxs);
|
||||
}
|
||||
addCoin(3 * COIN, wallet, wtxs);
|
||||
|
||||
// Create coins
|
||||
std::vector<COutput> coins;
|
||||
for (const auto& wtx : wtxs) {
|
||||
coins.emplace_back(wtx.get(), 0 /* iIn */, 6 * 24 /* nDepthIn */, true /* spendable */, true /* solvable */, true /* safe */);
|
||||
}
|
||||
|
||||
const CoinEligibilityFilter filter_standard(1, 6, 0);
|
||||
const CoinSelectionParams coin_selection_params(/* change_output_size= */ 34,
|
||||
/* change_spend_size= */ 148, /* effective_feerate= */ CFeeRate(0),
|
||||
/* long_term_feerate= */ CFeeRate(0), /* discard_feerate= */ CFeeRate(0),
|
||||
/* tx_no_inputs_size= */ 0, /* avoid_partial= */ false);
|
||||
bench.run([&] {
|
||||
std::set<CInputCoin> setCoinsRet;
|
||||
CAmount nValueRet;
|
||||
bool success = wallet.AttemptSelection(1003 * COIN, filter_standard, coins, setCoinsRet, nValueRet, coin_selection_params);
|
||||
assert(success);
|
||||
assert(nValueRet == 1003 * COIN);
|
||||
assert(setCoinsRet.size() == 2);
|
||||
});
|
||||
}
|
||||
|
||||
typedef std::set<CInputCoin> CoinSet;
|
||||
static NodeContext testNode;
|
||||
static auto testChain = interfaces::MakeChain(testNode);
|
||||
static CWallet testWallet(testChain.get(), "", CreateDummyWalletDatabase());
|
||||
std::vector<std::unique_ptr<CWalletTx>> wtxn;
|
||||
|
||||
// Copied from src/wallet/test/coinselector_tests.cpp
|
||||
static void add_coin(const CAmount& nValue, int nInput, std::vector<OutputGroup>& set)
|
||||
{
|
||||
CMutableTransaction tx;
|
||||
tx.vout.resize(nInput + 1);
|
||||
tx.vout[nInput].nValue = nValue;
|
||||
std::unique_ptr<CWalletTx> wtx = std::make_unique<CWalletTx>(&testWallet, MakeTransactionRef(std::move(tx)));
|
||||
set.emplace_back();
|
||||
set.back().Insert(COutput(wtx.get(), nInput, 0, true, true, true).GetInputCoin(), 0, true, 0, 0, false);
|
||||
wtxn.emplace_back(std::move(wtx));
|
||||
}
|
||||
// Copied from src/wallet/test/coinselector_tests.cpp
|
||||
static CAmount make_hard_case(int utxos, std::vector<OutputGroup>& utxo_pool)
|
||||
{
|
||||
utxo_pool.clear();
|
||||
CAmount target = 0;
|
||||
for (int i = 0; i < utxos; ++i) {
|
||||
target += (CAmount)1 << (utxos+i);
|
||||
add_coin((CAmount)1 << (utxos+i), 2*i, utxo_pool);
|
||||
add_coin(((CAmount)1 << (utxos+i)) + ((CAmount)1 << (utxos-1-i)), 2*i + 1, utxo_pool);
|
||||
}
|
||||
return target;
|
||||
}
|
||||
|
||||
static void BnBExhaustion(benchmark::Bench& bench)
|
||||
{
|
||||
// Setup
|
||||
testWallet.SetupLegacyScriptPubKeyMan();
|
||||
std::vector<OutputGroup> utxo_pool;
|
||||
CoinSet selection;
|
||||
CAmount value_ret = 0;
|
||||
|
||||
bench.run([&] {
|
||||
// Benchmark
|
||||
CAmount target = make_hard_case(17, utxo_pool);
|
||||
SelectCoinsBnB(utxo_pool, target, 0, selection, value_ret); // Should exhaust
|
||||
|
||||
// Cleanup
|
||||
utxo_pool.clear();
|
||||
selection.clear();
|
||||
});
|
||||
}
|
||||
|
||||
BENCHMARK(CoinSelection);
|
||||
BENCHMARK(BnBExhaustion);
|
||||
173
src/bench/crypto_hash.cpp
Normal file
173
src/bench/crypto_hash.cpp
Normal file
|
|
@ -0,0 +1,173 @@
|
|||
// Copyright (c) 2016-2020 The Bitcoin Core developers
|
||||
// Copyright (c) 2016-2020 The DigiByte Core developers
|
||||
// Distributed under the MIT software license, see the accompanying
|
||||
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
|
||||
|
||||
|
||||
#include <bench/bench.h>
|
||||
#include <crypto/muhash.h>
|
||||
#include <crypto/ripemd160.h>
|
||||
#include <crypto/sha1.h>
|
||||
#include <crypto/sha256.h>
|
||||
#include <crypto/sha3.h>
|
||||
#include <crypto/sha512.h>
|
||||
#include <crypto/siphash.h>
|
||||
#include <hash.h>
|
||||
#include <random.h>
|
||||
#include <uint256.h>
|
||||
|
||||
/* Number of bytes to hash per iteration */
|
||||
static const uint64_t BUFFER_SIZE = 1000*1000;
|
||||
|
||||
static void RIPEMD160(benchmark::Bench& bench)
|
||||
{
|
||||
uint8_t hash[CRIPEMD160::OUTPUT_SIZE];
|
||||
std::vector<uint8_t> in(BUFFER_SIZE,0);
|
||||
bench.batch(in.size()).unit("byte").run([&] {
|
||||
CRIPEMD160().Write(in.data(), in.size()).Finalize(hash);
|
||||
});
|
||||
}
|
||||
|
||||
static void SHA1(benchmark::Bench& bench)
|
||||
{
|
||||
uint8_t hash[CSHA1::OUTPUT_SIZE];
|
||||
std::vector<uint8_t> in(BUFFER_SIZE,0);
|
||||
bench.batch(in.size()).unit("byte").run([&] {
|
||||
CSHA1().Write(in.data(), in.size()).Finalize(hash);
|
||||
});
|
||||
}
|
||||
|
||||
static void SHA256(benchmark::Bench& bench)
|
||||
{
|
||||
uint8_t hash[CSHA256::OUTPUT_SIZE];
|
||||
std::vector<uint8_t> in(BUFFER_SIZE,0);
|
||||
bench.batch(in.size()).unit("byte").run([&] {
|
||||
CSHA256().Write(in.data(), in.size()).Finalize(hash);
|
||||
});
|
||||
}
|
||||
|
||||
static void SHA3_256_1M(benchmark::Bench& bench)
|
||||
{
|
||||
uint8_t hash[SHA3_256::OUTPUT_SIZE];
|
||||
std::vector<uint8_t> in(BUFFER_SIZE,0);
|
||||
bench.batch(in.size()).unit("byte").run([&] {
|
||||
SHA3_256().Write(in).Finalize(hash);
|
||||
});
|
||||
}
|
||||
|
||||
static void SHA256_32b(benchmark::Bench& bench)
|
||||
{
|
||||
std::vector<uint8_t> in(32,0);
|
||||
bench.batch(in.size()).unit("byte").run([&] {
|
||||
CSHA256()
|
||||
.Write(in.data(), in.size())
|
||||
.Finalize(in.data());
|
||||
});
|
||||
}
|
||||
|
||||
static void SHA256D64_1024(benchmark::Bench& bench)
|
||||
{
|
||||
std::vector<uint8_t> in(64 * 1024, 0);
|
||||
bench.batch(in.size()).unit("byte").run([&] {
|
||||
SHA256D64(in.data(), in.data(), 1024);
|
||||
});
|
||||
}
|
||||
|
||||
static void SHA512(benchmark::Bench& bench)
|
||||
{
|
||||
uint8_t hash[CSHA512::OUTPUT_SIZE];
|
||||
std::vector<uint8_t> in(BUFFER_SIZE,0);
|
||||
bench.batch(in.size()).unit("byte").run([&] {
|
||||
CSHA512().Write(in.data(), in.size()).Finalize(hash);
|
||||
});
|
||||
}
|
||||
|
||||
static void SipHash_32b(benchmark::Bench& bench)
|
||||
{
|
||||
uint256 x;
|
||||
uint64_t k1 = 0;
|
||||
bench.run([&] {
|
||||
*((uint64_t*)x.begin()) = SipHashUint256(0, ++k1, x);
|
||||
});
|
||||
}
|
||||
|
||||
static void FastRandom_32bit(benchmark::Bench& bench)
|
||||
{
|
||||
FastRandomContext rng(true);
|
||||
bench.run([&] {
|
||||
rng.rand32();
|
||||
});
|
||||
}
|
||||
|
||||
static void FastRandom_1bit(benchmark::Bench& bench)
|
||||
{
|
||||
FastRandomContext rng(true);
|
||||
bench.run([&] {
|
||||
rng.randbool();
|
||||
});
|
||||
}
|
||||
|
||||
static void MuHash(benchmark::Bench& bench)
|
||||
{
|
||||
MuHash3072 acc;
|
||||
unsigned char key[32] = {0};
|
||||
int i = 0;
|
||||
bench.run([&] {
|
||||
key[0] = ++i;
|
||||
acc *= MuHash3072(key);
|
||||
});
|
||||
}
|
||||
|
||||
static void MuHashMul(benchmark::Bench& bench)
|
||||
{
|
||||
MuHash3072 acc;
|
||||
FastRandomContext rng(true);
|
||||
MuHash3072 muhash{rng.randbytes(32)};
|
||||
|
||||
bench.run([&] {
|
||||
acc *= muhash;
|
||||
});
|
||||
}
|
||||
|
||||
static void MuHashDiv(benchmark::Bench& bench)
|
||||
{
|
||||
MuHash3072 acc;
|
||||
FastRandomContext rng(true);
|
||||
MuHash3072 muhash{rng.randbytes(32)};
|
||||
|
||||
for (size_t i = 0; i < bench.epochIterations(); ++i) {
|
||||
acc *= muhash;
|
||||
}
|
||||
|
||||
bench.run([&] {
|
||||
acc /= muhash;
|
||||
});
|
||||
}
|
||||
|
||||
static void MuHashPrecompute(benchmark::Bench& bench)
|
||||
{
|
||||
MuHash3072 acc;
|
||||
FastRandomContext rng(true);
|
||||
std::vector<unsigned char> key{rng.randbytes(32)};
|
||||
|
||||
bench.run([&] {
|
||||
MuHash3072{key};
|
||||
});
|
||||
}
|
||||
|
||||
BENCHMARK(RIPEMD160);
|
||||
BENCHMARK(SHA1);
|
||||
BENCHMARK(SHA256);
|
||||
BENCHMARK(SHA512);
|
||||
BENCHMARK(SHA3_256_1M);
|
||||
|
||||
BENCHMARK(SHA256_32b);
|
||||
BENCHMARK(SipHash_32b);
|
||||
BENCHMARK(SHA256D64_1024);
|
||||
BENCHMARK(FastRandom_32bit);
|
||||
BENCHMARK(FastRandom_1bit);
|
||||
|
||||
BENCHMARK(MuHash);
|
||||
BENCHMARK(MuHashMul);
|
||||
BENCHMARK(MuHashDiv);
|
||||
BENCHMARK(MuHashPrecompute);
|
||||
14
src/bench/data.cpp
Normal file
14
src/bench/data.cpp
Normal file
|
|
@ -0,0 +1,14 @@
|
|||
// Copyright (c) 2019 The DigiByte Core developers
|
||||
// Distributed under the MIT software license, see the accompanying
|
||||
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
|
||||
|
||||
#include <bench/data.h>
|
||||
|
||||
namespace benchmark {
|
||||
namespace data {
|
||||
|
||||
#include <bench/data/block413567.raw.h>
|
||||
const std::vector<uint8_t> block413567{std::begin(block413567_raw), std::end(block413567_raw)};
|
||||
|
||||
} // namespace data
|
||||
} // namespace benchmark
|
||||
19
src/bench/data.h
Normal file
19
src/bench/data.h
Normal file
|
|
@ -0,0 +1,19 @@
|
|||
// Copyright (c) 2019 The DigiByte Core developers
|
||||
// Distributed under the MIT software license, see the accompanying
|
||||
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
|
||||
|
||||
#ifndef DIGIBYTE_BENCH_DATA_H
|
||||
#define DIGIBYTE_BENCH_DATA_H
|
||||
|
||||
#include <cstdint>
|
||||
#include <vector>
|
||||
|
||||
namespace benchmark {
|
||||
namespace data {
|
||||
|
||||
extern const std::vector<uint8_t> block413567;
|
||||
|
||||
} // namespace data
|
||||
} // namespace benchmark
|
||||
|
||||
#endif // DIGIBYTE_BENCH_DATA_H
|
||||
BIN
src/bench/data/block413567.raw
Normal file
BIN
src/bench/data/block413567.raw
Normal file
Binary file not shown.
65
src/bench/duplicate_inputs.cpp
Normal file
65
src/bench/duplicate_inputs.cpp
Normal file
|
|
@ -0,0 +1,65 @@
|
|||
// Copyright (c) 2011-2020 The DigiByte Core developers
|
||||
// Distributed under the MIT software license, see the accompanying
|
||||
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
|
||||
|
||||
#include <bench/bench.h>
|
||||
#include <chainparams.h>
|
||||
#include <consensus/merkle.h>
|
||||
#include <consensus/validation.h>
|
||||
#include <pow.h>
|
||||
#include <test/util/setup_common.h>
|
||||
#include <txmempool.h>
|
||||
#include <validation.h>
|
||||
|
||||
|
||||
static void DuplicateInputs(benchmark::Bench& bench)
|
||||
{
|
||||
const auto testing_setup = MakeNoLogFileContext<const TestingSetup>();
|
||||
|
||||
const CScript SCRIPT_PUB{CScript(OP_TRUE)};
|
||||
|
||||
const CChainParams& chainparams = Params();
|
||||
|
||||
CBlock block{};
|
||||
CMutableTransaction coinbaseTx{};
|
||||
CMutableTransaction naughtyTx{};
|
||||
|
||||
LOCK(cs_main);
|
||||
CBlockIndex* pindexPrev = testing_setup->m_node.chainman->ActiveChain().Tip();
|
||||
assert(pindexPrev != nullptr);
|
||||
block.nBits = GetNextWorkRequired(pindexPrev, &block, chainparams.GetConsensus());
|
||||
block.nNonce = 0;
|
||||
auto nHeight = pindexPrev->nHeight + 1;
|
||||
|
||||
// Make a coinbase TX
|
||||
coinbaseTx.vin.resize(1);
|
||||
coinbaseTx.vin[0].prevout.SetNull();
|
||||
coinbaseTx.vout.resize(1);
|
||||
coinbaseTx.vout[0].scriptPubKey = SCRIPT_PUB;
|
||||
coinbaseTx.vout[0].nValue = GetBlockSubsidy(nHeight, chainparams.GetConsensus());
|
||||
coinbaseTx.vin[0].scriptSig = CScript() << nHeight << OP_0;
|
||||
|
||||
|
||||
naughtyTx.vout.resize(1);
|
||||
naughtyTx.vout[0].nValue = 0;
|
||||
naughtyTx.vout[0].scriptPubKey = SCRIPT_PUB;
|
||||
|
||||
uint64_t n_inputs = (((MAX_BLOCK_SERIALIZED_SIZE / WITNESS_SCALE_FACTOR) - (CTransaction(coinbaseTx).GetTotalSize() + CTransaction(naughtyTx).GetTotalSize())) / 41) - 100;
|
||||
for (uint64_t x = 0; x < (n_inputs - 1); ++x) {
|
||||
naughtyTx.vin.emplace_back(GetRandHash(), 0, CScript(), 0);
|
||||
}
|
||||
naughtyTx.vin.emplace_back(naughtyTx.vin.back());
|
||||
|
||||
block.vtx.push_back(MakeTransactionRef(std::move(coinbaseTx)));
|
||||
block.vtx.push_back(MakeTransactionRef(std::move(naughtyTx)));
|
||||
|
||||
block.hashMerkleRoot = BlockMerkleRoot(block);
|
||||
|
||||
bench.run([&] {
|
||||
BlockValidationState cvstate{};
|
||||
assert(!CheckBlock(block, cvstate, chainparams.GetConsensus(), false, false));
|
||||
assert(cvstate.GetRejectReason() == "bad-txns-inputs-duplicate");
|
||||
});
|
||||
}
|
||||
|
||||
BENCHMARK(DuplicateInputs);
|
||||
22
src/bench/examples.cpp
Normal file
22
src/bench/examples.cpp
Normal file
|
|
@ -0,0 +1,22 @@
|
|||
// Copyright (c) 2015-2020 The Bitcoin Core developers
|
||||
// Copyright (c) 2015-2020 The DigiByte Core developers
|
||||
// Distributed under the MIT software license, see the accompanying
|
||||
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
|
||||
|
||||
#include <bench/bench.h>
|
||||
|
||||
// Extremely fast-running benchmark:
|
||||
#include <math.h>
|
||||
|
||||
volatile double sum = 0.0; // volatile, global so not optimized away
|
||||
|
||||
static void Trig(benchmark::Bench& bench)
|
||||
{
|
||||
double d = 0.01;
|
||||
bench.run([&] {
|
||||
sum += sin(d);
|
||||
d += 0.000001;
|
||||
});
|
||||
}
|
||||
|
||||
BENCHMARK(Trig);
|
||||
43
src/bench/gcs_filter.cpp
Normal file
43
src/bench/gcs_filter.cpp
Normal file
|
|
@ -0,0 +1,43 @@
|
|||
// Copyright (c) 2018-2020 The DigiByte Core developers
|
||||
// Distributed under the MIT software license, see the accompanying
|
||||
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
|
||||
|
||||
#include <bench/bench.h>
|
||||
#include <blockfilter.h>
|
||||
|
||||
static void ConstructGCSFilter(benchmark::Bench& bench)
|
||||
{
|
||||
GCSFilter::ElementSet elements;
|
||||
for (int i = 0; i < 10000; ++i) {
|
||||
GCSFilter::Element element(32);
|
||||
element[0] = static_cast<unsigned char>(i);
|
||||
element[1] = static_cast<unsigned char>(i >> 8);
|
||||
elements.insert(std::move(element));
|
||||
}
|
||||
|
||||
uint64_t siphash_k0 = 0;
|
||||
bench.batch(elements.size()).unit("elem").run([&] {
|
||||
GCSFilter filter({siphash_k0, 0, 20, 1 << 20}, elements);
|
||||
|
||||
siphash_k0++;
|
||||
});
|
||||
}
|
||||
|
||||
static void MatchGCSFilter(benchmark::Bench& bench)
|
||||
{
|
||||
GCSFilter::ElementSet elements;
|
||||
for (int i = 0; i < 10000; ++i) {
|
||||
GCSFilter::Element element(32);
|
||||
element[0] = static_cast<unsigned char>(i);
|
||||
element[1] = static_cast<unsigned char>(i >> 8);
|
||||
elements.insert(std::move(element));
|
||||
}
|
||||
GCSFilter filter({0, 0, 20, 1 << 20}, elements);
|
||||
|
||||
bench.unit("elem").run([&] {
|
||||
filter.Match(GCSFilter::Element());
|
||||
});
|
||||
}
|
||||
|
||||
BENCHMARK(ConstructGCSFilter);
|
||||
BENCHMARK(MatchGCSFilter);
|
||||
47
src/bench/hashpadding.cpp
Normal file
47
src/bench/hashpadding.cpp
Normal file
|
|
@ -0,0 +1,47 @@
|
|||
// Copyright (c) 2015-2020 The DigiByte Core developers
|
||||
// Distributed under the MIT software license, see the accompanying
|
||||
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
|
||||
|
||||
#include <bench/bench.h>
|
||||
#include <hash.h>
|
||||
#include <random.h>
|
||||
#include <uint256.h>
|
||||
|
||||
|
||||
static void PrePadded(benchmark::Bench& bench)
|
||||
{
|
||||
|
||||
CSHA256 hasher;
|
||||
|
||||
// Setup the salted hasher
|
||||
uint256 nonce = GetRandHash();
|
||||
hasher.Write(nonce.begin(), 32);
|
||||
hasher.Write(nonce.begin(), 32);
|
||||
uint256 data = GetRandHash();
|
||||
bench.run([&] {
|
||||
unsigned char out[32];
|
||||
CSHA256 h = hasher;
|
||||
h.Write(data.begin(), 32);
|
||||
h.Finalize(out);
|
||||
});
|
||||
}
|
||||
|
||||
BENCHMARK(PrePadded);
|
||||
|
||||
static void RegularPadded(benchmark::Bench& bench)
|
||||
{
|
||||
CSHA256 hasher;
|
||||
|
||||
// Setup the salted hasher
|
||||
uint256 nonce = GetRandHash();
|
||||
uint256 data = GetRandHash();
|
||||
bench.run([&] {
|
||||
unsigned char out[32];
|
||||
CSHA256 h = hasher;
|
||||
h.Write(nonce.begin(), 32);
|
||||
h.Write(data.begin(), 32);
|
||||
h.Finalize(out);
|
||||
});
|
||||
}
|
||||
|
||||
BENCHMARK(RegularPadded);
|
||||
43
src/bench/lockedpool.cpp
Normal file
43
src/bench/lockedpool.cpp
Normal file
|
|
@ -0,0 +1,43 @@
|
|||
// Copyright (c) 2016-2020 The Bitcoin Core developers
|
||||
// Copyright (c) 2016-2020 The DigiByte Core developers
|
||||
// Distributed under the MIT software license, see the accompanying
|
||||
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
|
||||
|
||||
#include <bench/bench.h>
|
||||
|
||||
#include <support/lockedpool.h>
|
||||
|
||||
#include <vector>
|
||||
|
||||
#define ASIZE 2048
|
||||
#define MSIZE 2048
|
||||
|
||||
static void BenchLockedPool(benchmark::Bench& bench)
|
||||
{
|
||||
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(nullptr);
|
||||
uint32_t s = 0x12345678;
|
||||
bench.run([&] {
|
||||
int idx = s & (addr.size() - 1);
|
||||
if (s & 0x80000000) {
|
||||
b.free(addr[idx]);
|
||||
addr[idx] = nullptr;
|
||||
} 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);
|
||||
136
src/bench/mempool_eviction.cpp
Normal file
136
src/bench/mempool_eviction.cpp
Normal file
|
|
@ -0,0 +1,136 @@
|
|||
// Copyright (c) 2011-2020 The Bitcoin Core developers
|
||||
// Copyright (c) 2014-2020 The DigiByte Core developers
|
||||
// Distributed under the MIT software license, see the accompanying
|
||||
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
|
||||
|
||||
#include <bench/bench.h>
|
||||
#include <policy/policy.h>
|
||||
#include <test/util/setup_common.h>
|
||||
#include <txmempool.h>
|
||||
|
||||
|
||||
static void AddTx(const CTransactionRef& tx, const CAmount& nFee, CTxMemPool& pool) EXCLUSIVE_LOCKS_REQUIRED(cs_main, pool.cs)
|
||||
{
|
||||
int64_t nTime = 0;
|
||||
unsigned int nHeight = 1;
|
||||
bool spendsCoinbase = false;
|
||||
unsigned int sigOpCost = 4;
|
||||
LockPoints lp;
|
||||
pool.addUnchecked(CTxMemPoolEntry(
|
||||
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::Bench& bench)
|
||||
{
|
||||
const auto testing_setup = MakeNoLogFileContext<const TestingSetup>();
|
||||
|
||||
CMutableTransaction tx1 = CMutableTransaction();
|
||||
tx1.vin.resize(1);
|
||||
tx1.vin[0].scriptSig = CScript() << OP_1;
|
||||
tx1.vin[0].scriptWitness.stack.push_back({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.vin[0].scriptWitness.stack.push_back({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.vin[0].scriptWitness.stack.push_back({3});
|
||||
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[0].scriptWitness.stack.push_back({4});
|
||||
tx4.vin[1].prevout.SetNull();
|
||||
tx4.vin[1].scriptSig = CScript() << OP_4;
|
||||
tx4.vin[1].scriptWitness.stack.push_back({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[0].scriptWitness.stack.push_back({4});
|
||||
tx5.vin[1].prevout.SetNull();
|
||||
tx5.vin[1].scriptSig = CScript() << OP_5;
|
||||
tx5.vin[1].scriptWitness.stack.push_back({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[0].scriptWitness.stack.push_back({4});
|
||||
tx6.vin[1].prevout.SetNull();
|
||||
tx6.vin[1].scriptSig = CScript() << OP_6;
|
||||
tx6.vin[1].scriptWitness.stack.push_back({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[0].scriptWitness.stack.push_back({5});
|
||||
tx7.vin[1].prevout = COutPoint(tx6.GetHash(), 0);
|
||||
tx7.vin[1].scriptSig = CScript() << OP_6;
|
||||
tx7.vin[1].scriptWitness.stack.push_back({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;
|
||||
LOCK2(cs_main, pool.cs);
|
||||
// Create transaction references outside the "hot loop"
|
||||
const CTransactionRef tx1_r{MakeTransactionRef(tx1)};
|
||||
const CTransactionRef tx2_r{MakeTransactionRef(tx2)};
|
||||
const CTransactionRef tx3_r{MakeTransactionRef(tx3)};
|
||||
const CTransactionRef tx4_r{MakeTransactionRef(tx4)};
|
||||
const CTransactionRef tx5_r{MakeTransactionRef(tx5)};
|
||||
const CTransactionRef tx6_r{MakeTransactionRef(tx6)};
|
||||
const CTransactionRef tx7_r{MakeTransactionRef(tx7)};
|
||||
|
||||
bench.run([&]() NO_THREAD_SAFETY_ANALYSIS {
|
||||
AddTx(tx1_r, 10000LL, pool);
|
||||
AddTx(tx2_r, 5000LL, pool);
|
||||
AddTx(tx3_r, 20000LL, pool);
|
||||
AddTx(tx4_r, 7000LL, pool);
|
||||
AddTx(tx5_r, 1000LL, pool);
|
||||
AddTx(tx6_r, 1100LL, pool);
|
||||
AddTx(tx7_r, 9000LL, pool);
|
||||
pool.TrimToSize(pool.DynamicMemoryUsage() * 3 / 4);
|
||||
pool.TrimToSize(GetVirtualTransactionSize(*tx1_r));
|
||||
});
|
||||
}
|
||||
|
||||
BENCHMARK(MempoolEviction);
|
||||
94
src/bench/mempool_stress.cpp
Normal file
94
src/bench/mempool_stress.cpp
Normal file
|
|
@ -0,0 +1,94 @@
|
|||
// Copyright (c) 2011-2020 The DigiByte Core developers
|
||||
// Distributed under the MIT software license, see the accompanying
|
||||
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
|
||||
|
||||
#include <bench/bench.h>
|
||||
#include <policy/policy.h>
|
||||
#include <test/util/setup_common.h>
|
||||
#include <txmempool.h>
|
||||
|
||||
#include <vector>
|
||||
|
||||
static void AddTx(const CTransactionRef& tx, CTxMemPool& pool) EXCLUSIVE_LOCKS_REQUIRED(cs_main, pool.cs)
|
||||
{
|
||||
int64_t nTime = 0;
|
||||
unsigned int nHeight = 1;
|
||||
bool spendsCoinbase = false;
|
||||
unsigned int sigOpCost = 4;
|
||||
LockPoints lp;
|
||||
pool.addUnchecked(CTxMemPoolEntry(tx, 1000, nTime, nHeight, spendsCoinbase, sigOpCost, lp));
|
||||
}
|
||||
|
||||
struct Available {
|
||||
CTransactionRef ref;
|
||||
size_t vin_left{0};
|
||||
size_t tx_count;
|
||||
Available(CTransactionRef& ref, size_t tx_count) : ref(ref), tx_count(tx_count){}
|
||||
};
|
||||
|
||||
static void ComplexMemPool(benchmark::Bench& bench)
|
||||
{
|
||||
int childTxs = 800;
|
||||
if (bench.complexityN() > 1) {
|
||||
childTxs = static_cast<int>(bench.complexityN());
|
||||
}
|
||||
|
||||
FastRandomContext det_rand{true};
|
||||
std::vector<Available> available_coins;
|
||||
std::vector<CTransactionRef> ordered_coins;
|
||||
// Create some base transactions
|
||||
size_t tx_counter = 1;
|
||||
for (auto x = 0; x < 100; ++x) {
|
||||
CMutableTransaction tx = CMutableTransaction();
|
||||
tx.vin.resize(1);
|
||||
tx.vin[0].scriptSig = CScript() << CScriptNum(tx_counter);
|
||||
tx.vin[0].scriptWitness.stack.push_back(CScriptNum(x).getvch());
|
||||
tx.vout.resize(det_rand.randrange(10)+2);
|
||||
for (auto& out : tx.vout) {
|
||||
out.scriptPubKey = CScript() << CScriptNum(tx_counter) << OP_EQUAL;
|
||||
out.nValue = 10 * COIN;
|
||||
}
|
||||
ordered_coins.emplace_back(MakeTransactionRef(tx));
|
||||
available_coins.emplace_back(ordered_coins.back(), tx_counter++);
|
||||
}
|
||||
for (auto x = 0; x < childTxs && !available_coins.empty(); ++x) {
|
||||
CMutableTransaction tx = CMutableTransaction();
|
||||
size_t n_ancestors = det_rand.randrange(10)+1;
|
||||
for (size_t ancestor = 0; ancestor < n_ancestors && !available_coins.empty(); ++ancestor){
|
||||
size_t idx = det_rand.randrange(available_coins.size());
|
||||
Available coin = available_coins[idx];
|
||||
uint256 hash = coin.ref->GetHash();
|
||||
// biased towards taking just one ancestor, but maybe more
|
||||
size_t n_to_take = det_rand.randrange(2) == 0 ? 1 : 1+det_rand.randrange(coin.ref->vout.size() - coin.vin_left);
|
||||
for (size_t i = 0; i < n_to_take; ++i) {
|
||||
tx.vin.emplace_back();
|
||||
tx.vin.back().prevout = COutPoint(hash, coin.vin_left++);
|
||||
tx.vin.back().scriptSig = CScript() << coin.tx_count;
|
||||
tx.vin.back().scriptWitness.stack.push_back(CScriptNum(coin.tx_count).getvch());
|
||||
}
|
||||
if (coin.vin_left == coin.ref->vin.size()) {
|
||||
coin = available_coins.back();
|
||||
available_coins.pop_back();
|
||||
}
|
||||
tx.vout.resize(det_rand.randrange(10)+2);
|
||||
for (auto& out : tx.vout) {
|
||||
out.scriptPubKey = CScript() << CScriptNum(tx_counter) << OP_EQUAL;
|
||||
out.nValue = 10 * COIN;
|
||||
}
|
||||
}
|
||||
ordered_coins.emplace_back(MakeTransactionRef(tx));
|
||||
available_coins.emplace_back(ordered_coins.back(), tx_counter++);
|
||||
}
|
||||
const auto testing_setup = MakeNoLogFileContext<const TestingSetup>(CBaseChainParams::MAIN);
|
||||
CTxMemPool pool;
|
||||
LOCK2(cs_main, pool.cs);
|
||||
bench.run([&]() NO_THREAD_SAFETY_ANALYSIS {
|
||||
for (auto& tx : ordered_coins) {
|
||||
AddTx(tx, pool);
|
||||
}
|
||||
pool.TrimToSize(pool.DynamicMemoryUsage() * 3 / 4);
|
||||
pool.TrimToSize(GetVirtualTransactionSize(*ordered_coins.front()));
|
||||
});
|
||||
}
|
||||
|
||||
BENCHMARK(ComplexMemPool);
|
||||
27
src/bench/merkle_root.cpp
Normal file
27
src/bench/merkle_root.cpp
Normal file
|
|
@ -0,0 +1,27 @@
|
|||
// Copyright (c) 2016-2020 The Bitcoin Core developers
|
||||
// Copyright (c) 2016-2020 The DigiByte Core developers
|
||||
// Distributed under the MIT software license, see the accompanying
|
||||
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
|
||||
|
||||
#include <bench/bench.h>
|
||||
|
||||
#include <consensus/merkle.h>
|
||||
#include <random.h>
|
||||
#include <uint256.h>
|
||||
|
||||
static void MerkleRoot(benchmark::Bench& bench)
|
||||
{
|
||||
FastRandomContext rng(true);
|
||||
std::vector<uint256> leaves;
|
||||
leaves.resize(9001);
|
||||
for (auto& item : leaves) {
|
||||
item = rng.rand256();
|
||||
}
|
||||
bench.batch(leaves.size()).unit("leaf").run([&] {
|
||||
bool mutation = false;
|
||||
uint256 hash = ComputeMerkleRoot(std::vector<uint256>(leaves), &mutation);
|
||||
leaves[mutation] = hash;
|
||||
});
|
||||
}
|
||||
|
||||
BENCHMARK(MerkleRoot);
|
||||
6
src/bench/nanobench.cpp
Normal file
6
src/bench/nanobench.cpp
Normal file
|
|
@ -0,0 +1,6 @@
|
|||
// Copyright (c) 2019-2020 The DigiByte Core developers
|
||||
// Distributed under the MIT software license, see the accompanying
|
||||
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
|
||||
|
||||
#define ANKERL_NANOBENCH_IMPLEMENT
|
||||
#include <bench/nanobench.h>
|
||||
3360
src/bench/nanobench.h
Normal file
3360
src/bench/nanobench.h
Normal file
File diff suppressed because it is too large
Load diff
157
src/bench/peer_eviction.cpp
Normal file
157
src/bench/peer_eviction.cpp
Normal file
|
|
@ -0,0 +1,157 @@
|
|||
// Copyright (c) 2021 The DigiByte Core developers
|
||||
// Distributed under the MIT software license, see the accompanying
|
||||
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
|
||||
|
||||
#include <bench/bench.h>
|
||||
#include <net.h>
|
||||
#include <netaddress.h>
|
||||
#include <random.h>
|
||||
#include <test/util/net.h>
|
||||
#include <test/util/setup_common.h>
|
||||
|
||||
#include <algorithm>
|
||||
#include <functional>
|
||||
#include <vector>
|
||||
|
||||
static void EvictionProtectionCommon(
|
||||
benchmark::Bench& bench,
|
||||
int num_candidates,
|
||||
std::function<void(NodeEvictionCandidate&)> candidate_setup_fn)
|
||||
{
|
||||
using Candidates = std::vector<NodeEvictionCandidate>;
|
||||
FastRandomContext random_context{true};
|
||||
bench.warmup(100).epochIterations(1100);
|
||||
|
||||
Candidates candidates{GetRandomNodeEvictionCandidates(num_candidates, random_context)};
|
||||
for (auto& c : candidates) {
|
||||
candidate_setup_fn(c);
|
||||
}
|
||||
|
||||
std::vector<Candidates> copies{
|
||||
static_cast<size_t>(bench.epochs() * bench.epochIterations()), candidates};
|
||||
size_t i{0};
|
||||
bench.run([&] {
|
||||
ProtectEvictionCandidatesByRatio(copies.at(i));
|
||||
++i;
|
||||
});
|
||||
}
|
||||
|
||||
/* Benchmarks */
|
||||
|
||||
static void EvictionProtection0Networks250Candidates(benchmark::Bench& bench)
|
||||
{
|
||||
EvictionProtectionCommon(
|
||||
bench,
|
||||
250 /* num_candidates */,
|
||||
[](NodeEvictionCandidate& c) {
|
||||
c.nTimeConnected = c.id;
|
||||
c.m_network = NET_IPV4;
|
||||
});
|
||||
}
|
||||
|
||||
static void EvictionProtection1Networks250Candidates(benchmark::Bench& bench)
|
||||
{
|
||||
EvictionProtectionCommon(
|
||||
bench,
|
||||
250 /* num_candidates */,
|
||||
[](NodeEvictionCandidate& c) {
|
||||
c.nTimeConnected = c.id;
|
||||
c.m_is_local = false;
|
||||
if (c.id >= 130 && c.id < 240) { // 110 Tor
|
||||
c.m_network = NET_ONION;
|
||||
} else {
|
||||
c.m_network = NET_IPV4;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
static void EvictionProtection2Networks250Candidates(benchmark::Bench& bench)
|
||||
{
|
||||
EvictionProtectionCommon(
|
||||
bench,
|
||||
250 /* num_candidates */,
|
||||
[](NodeEvictionCandidate& c) {
|
||||
c.nTimeConnected = c.id;
|
||||
c.m_is_local = false;
|
||||
if (c.id >= 90 && c.id < 160) { // 70 Tor
|
||||
c.m_network = NET_ONION;
|
||||
} else if (c.id >= 170 && c.id < 250) { // 80 I2P
|
||||
c.m_network = NET_I2P;
|
||||
} else {
|
||||
c.m_network = NET_IPV4;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
static void EvictionProtection3Networks050Candidates(benchmark::Bench& bench)
|
||||
{
|
||||
EvictionProtectionCommon(
|
||||
bench,
|
||||
50 /* num_candidates */,
|
||||
[](NodeEvictionCandidate& c) {
|
||||
c.nTimeConnected = c.id;
|
||||
c.m_is_local = (c.id == 28 || c.id == 47); // 2 localhost
|
||||
if (c.id >= 30 && c.id < 47) { // 17 I2P
|
||||
c.m_network = NET_I2P;
|
||||
} else if (c.id >= 24 && c.id < 28) { // 4 Tor
|
||||
c.m_network = NET_ONION;
|
||||
} else {
|
||||
c.m_network = NET_IPV4;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
static void EvictionProtection3Networks100Candidates(benchmark::Bench& bench)
|
||||
{
|
||||
EvictionProtectionCommon(
|
||||
bench,
|
||||
100 /* num_candidates */,
|
||||
[](NodeEvictionCandidate& c) {
|
||||
c.nTimeConnected = c.id;
|
||||
c.m_is_local = (c.id >= 55 && c.id < 60); // 5 localhost
|
||||
if (c.id >= 70 && c.id < 80) { // 10 I2P
|
||||
c.m_network = NET_I2P;
|
||||
} else if (c.id >= 80 && c.id < 96) { // 16 Tor
|
||||
c.m_network = NET_ONION;
|
||||
} else {
|
||||
c.m_network = NET_IPV4;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
static void EvictionProtection3Networks250Candidates(benchmark::Bench& bench)
|
||||
{
|
||||
EvictionProtectionCommon(
|
||||
bench,
|
||||
250 /* num_candidates */,
|
||||
[](NodeEvictionCandidate& c) {
|
||||
c.nTimeConnected = c.id;
|
||||
c.m_is_local = (c.id >= 140 && c.id < 160); // 20 localhost
|
||||
if (c.id >= 170 && c.id < 180) { // 10 I2P
|
||||
c.m_network = NET_I2P;
|
||||
} else if (c.id >= 190 && c.id < 240) { // 50 Tor
|
||||
c.m_network = NET_ONION;
|
||||
} else {
|
||||
c.m_network = NET_IPV4;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// Candidate numbers used for the benchmarks:
|
||||
// - 50 candidates simulates a possible use of -maxconnections
|
||||
// - 100 candidates approximates an average node with default settings
|
||||
// - 250 candidates is the number of peers reported by operators of busy nodes
|
||||
|
||||
// No disadvantaged networks, with 250 eviction candidates.
|
||||
BENCHMARK(EvictionProtection0Networks250Candidates);
|
||||
|
||||
// 1 disadvantaged network (Tor) with 250 eviction candidates.
|
||||
BENCHMARK(EvictionProtection1Networks250Candidates);
|
||||
|
||||
// 2 disadvantaged networks (I2P, Tor) with 250 eviction candidates.
|
||||
BENCHMARK(EvictionProtection2Networks250Candidates);
|
||||
|
||||
// 3 disadvantaged networks (I2P/localhost/Tor) with 50/100/250 eviction candidates.
|
||||
BENCHMARK(EvictionProtection3Networks050Candidates);
|
||||
BENCHMARK(EvictionProtection3Networks100Candidates);
|
||||
BENCHMARK(EvictionProtection3Networks250Candidates);
|
||||
53
src/bench/perf.cpp
Normal file
53
src/bench/perf.cpp
Normal file
|
|
@ -0,0 +1,53 @@
|
|||
// Copyright (c) 2016-2017 The DigiByte Core developers
|
||||
// Distributed under the MIT software license, see the accompanying
|
||||
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
|
||||
|
||||
#include <bench/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
|
||||
37
src/bench/perf.h
Normal file
37
src/bench/perf.h
Normal file
|
|
@ -0,0 +1,37 @@
|
|||
// Copyright (c) 2016 The DigiByte 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
|
||||
41
src/bench/poly1305.cpp
Normal file
41
src/bench/poly1305.cpp
Normal file
|
|
@ -0,0 +1,41 @@
|
|||
// Copyright (c) 2019-2020 The DigiByte Core developers
|
||||
// Distributed under the MIT software license, see the accompanying
|
||||
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
|
||||
|
||||
|
||||
#include <bench/bench.h>
|
||||
#include <crypto/poly1305.h>
|
||||
|
||||
/* Number of bytes to process per iteration */
|
||||
static constexpr uint64_t BUFFER_SIZE_TINY = 64;
|
||||
static constexpr uint64_t BUFFER_SIZE_SMALL = 256;
|
||||
static constexpr uint64_t BUFFER_SIZE_LARGE = 1024*1024;
|
||||
|
||||
static void POLY1305(benchmark::Bench& bench, size_t buffersize)
|
||||
{
|
||||
std::vector<unsigned char> tag(POLY1305_TAGLEN, 0);
|
||||
std::vector<unsigned char> key(POLY1305_KEYLEN, 0);
|
||||
std::vector<unsigned char> in(buffersize, 0);
|
||||
bench.batch(in.size()).unit("byte").run([&] {
|
||||
poly1305_auth(tag.data(), in.data(), in.size(), key.data());
|
||||
});
|
||||
}
|
||||
|
||||
static void POLY1305_64BYTES(benchmark::Bench& bench)
|
||||
{
|
||||
POLY1305(bench, BUFFER_SIZE_TINY);
|
||||
}
|
||||
|
||||
static void POLY1305_256BYTES(benchmark::Bench& bench)
|
||||
{
|
||||
POLY1305(bench, BUFFER_SIZE_SMALL);
|
||||
}
|
||||
|
||||
static void POLY1305_1MB(benchmark::Bench& bench)
|
||||
{
|
||||
POLY1305(bench, BUFFER_SIZE_LARGE);
|
||||
}
|
||||
|
||||
BENCHMARK(POLY1305_64BYTES);
|
||||
BENCHMARK(POLY1305_256BYTES);
|
||||
BENCHMARK(POLY1305_1MB);
|
||||
99
src/bench/prevector.cpp
Normal file
99
src/bench/prevector.cpp
Normal file
|
|
@ -0,0 +1,99 @@
|
|||
// Copyright (c) 2015-2020 The Bitcoin Core developers
|
||||
// Copyright (c) 2015-2020 The DigiByte Core developers
|
||||
// Distributed under the MIT software license, see the accompanying
|
||||
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
|
||||
|
||||
#include <prevector.h>
|
||||
#include <serialize.h>
|
||||
#include <streams.h>
|
||||
#include <type_traits>
|
||||
|
||||
#include <bench/bench.h>
|
||||
|
||||
struct nontrivial_t {
|
||||
int x;
|
||||
nontrivial_t() :x(-1) {}
|
||||
SERIALIZE_METHODS(nontrivial_t, obj) { READWRITE(obj.x); }
|
||||
};
|
||||
static_assert(!std::is_trivially_default_constructible<nontrivial_t>::value,
|
||||
"expected nontrivial_t to not be trivially constructible");
|
||||
|
||||
typedef unsigned char trivial_t;
|
||||
static_assert(std::is_trivially_default_constructible<trivial_t>::value,
|
||||
"expected trivial_t to be trivially constructible");
|
||||
|
||||
template <typename T>
|
||||
static void PrevectorDestructor(benchmark::Bench& bench)
|
||||
{
|
||||
bench.batch(2).run([&] {
|
||||
prevector<28, T> t0;
|
||||
prevector<28, T> t1;
|
||||
t0.resize(28);
|
||||
t1.resize(29);
|
||||
});
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
static void PrevectorClear(benchmark::Bench& bench)
|
||||
{
|
||||
prevector<28, T> t0;
|
||||
prevector<28, T> t1;
|
||||
bench.batch(2).run([&] {
|
||||
t0.resize(28);
|
||||
t0.clear();
|
||||
t1.resize(29);
|
||||
t1.clear();
|
||||
});
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
static void PrevectorResize(benchmark::Bench& bench)
|
||||
{
|
||||
prevector<28, T> t0;
|
||||
prevector<28, T> t1;
|
||||
bench.batch(4).run([&] {
|
||||
t0.resize(28);
|
||||
t0.resize(0);
|
||||
t1.resize(29);
|
||||
t1.resize(0);
|
||||
});
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
static void PrevectorDeserialize(benchmark::Bench& bench)
|
||||
{
|
||||
CDataStream s0(SER_NETWORK, 0);
|
||||
prevector<28, T> t0;
|
||||
t0.resize(28);
|
||||
for (auto x = 0; x < 900; ++x) {
|
||||
s0 << t0;
|
||||
}
|
||||
t0.resize(100);
|
||||
for (auto x = 0; x < 101; ++x) {
|
||||
s0 << t0;
|
||||
}
|
||||
bench.batch(1000).run([&] {
|
||||
prevector<28, T> t1;
|
||||
for (auto x = 0; x < 1000; ++x) {
|
||||
s0 >> t1;
|
||||
}
|
||||
s0.Rewind();
|
||||
});
|
||||
}
|
||||
|
||||
#define PREVECTOR_TEST(name) \
|
||||
static void Prevector##name##Nontrivial(benchmark::Bench& bench) \
|
||||
{ \
|
||||
Prevector##name<nontrivial_t>(bench); \
|
||||
} \
|
||||
BENCHMARK(Prevector##name##Nontrivial); \
|
||||
static void Prevector##name##Trivial(benchmark::Bench& bench) \
|
||||
{ \
|
||||
Prevector##name<trivial_t>(bench); \
|
||||
} \
|
||||
BENCHMARK(Prevector##name##Trivial);
|
||||
|
||||
PREVECTOR_TEST(Clear)
|
||||
PREVECTOR_TEST(Destructor)
|
||||
PREVECTOR_TEST(Resize)
|
||||
PREVECTOR_TEST(Deserialize)
|
||||
40
src/bench/rollingbloom.cpp
Normal file
40
src/bench/rollingbloom.cpp
Normal file
|
|
@ -0,0 +1,40 @@
|
|||
// Copyright (c) 2016-2020 The Bitcoin Core developers
|
||||
// Copyright (c) 2016-2020 The DigiByte Core developers
|
||||
// Distributed under the MIT software license, see the accompanying
|
||||
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
|
||||
|
||||
|
||||
#include <bench/bench.h>
|
||||
#include <bloom.h>
|
||||
|
||||
static void RollingBloom(benchmark::Bench& bench)
|
||||
{
|
||||
CRollingBloomFilter filter(120000, 0.000001);
|
||||
std::vector<unsigned char> data(32);
|
||||
uint32_t count = 0;
|
||||
bench.run([&] {
|
||||
count++;
|
||||
data[0] = count;
|
||||
data[1] = count >> 8;
|
||||
data[2] = count >> 16;
|
||||
data[3] = count >> 24;
|
||||
filter.insert(data);
|
||||
|
||||
data[0] = count >> 24;
|
||||
data[1] = count >> 16;
|
||||
data[2] = count >> 8;
|
||||
data[3] = count;
|
||||
filter.contains(data);
|
||||
});
|
||||
}
|
||||
|
||||
static void RollingBloomReset(benchmark::Bench& bench)
|
||||
{
|
||||
CRollingBloomFilter filter(120000, 0.000001);
|
||||
bench.run([&] {
|
||||
filter.reset();
|
||||
});
|
||||
}
|
||||
|
||||
BENCHMARK(RollingBloom);
|
||||
BENCHMARK(RollingBloomReset);
|
||||
60
src/bench/rpc_blockchain.cpp
Normal file
60
src/bench/rpc_blockchain.cpp
Normal file
|
|
@ -0,0 +1,60 @@
|
|||
// Copyright (c) 2016-2020 The DigiByte Core developers
|
||||
// Distributed under the MIT software license, see the accompanying
|
||||
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
|
||||
|
||||
#include <bench/bench.h>
|
||||
#include <bench/data.h>
|
||||
|
||||
#include <rpc/blockchain.h>
|
||||
#include <streams.h>
|
||||
#include <test/util/setup_common.h>
|
||||
#include <validation.h>
|
||||
|
||||
#include <univalue.h>
|
||||
|
||||
namespace {
|
||||
|
||||
struct TestBlockAndIndex {
|
||||
const std::unique_ptr<const TestingSetup> testing_setup{MakeNoLogFileContext<const TestingSetup>(CBaseChainParams::MAIN)};
|
||||
CBlock block{};
|
||||
uint256 blockHash{};
|
||||
CBlockIndex blockindex{};
|
||||
|
||||
TestBlockAndIndex()
|
||||
{
|
||||
CDataStream stream(benchmark::data::block413567, SER_NETWORK, PROTOCOL_VERSION);
|
||||
char a = '\0';
|
||||
stream.write(&a, 1); // Prevent compaction
|
||||
|
||||
stream >> block;
|
||||
|
||||
blockHash = block.GetHash();
|
||||
blockindex.phashBlock = &blockHash;
|
||||
blockindex.nBits = 403014710;
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace
|
||||
|
||||
static void BlockToJsonVerbose(benchmark::Bench& bench)
|
||||
{
|
||||
TestBlockAndIndex data;
|
||||
bench.run([&] {
|
||||
auto univalue = blockToJSON(data.block, &data.blockindex, &data.blockindex, /*verbose*/ true);
|
||||
ankerl::nanobench::doNotOptimizeAway(univalue);
|
||||
});
|
||||
}
|
||||
|
||||
BENCHMARK(BlockToJsonVerbose);
|
||||
|
||||
static void BlockToJsonVerboseWrite(benchmark::Bench& bench)
|
||||
{
|
||||
TestBlockAndIndex data;
|
||||
auto univalue = blockToJSON(data.block, &data.blockindex, &data.blockindex, /*verbose*/ true);
|
||||
bench.run([&] {
|
||||
auto str = univalue.write();
|
||||
ankerl::nanobench::doNotOptimizeAway(str);
|
||||
});
|
||||
}
|
||||
|
||||
BENCHMARK(BlockToJsonVerboseWrite);
|
||||
40
src/bench/rpc_mempool.cpp
Normal file
40
src/bench/rpc_mempool.cpp
Normal file
|
|
@ -0,0 +1,40 @@
|
|||
// Copyright (c) 2011-2020 The DigiByte Core developers
|
||||
// Distributed under the MIT software license, see the accompanying
|
||||
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
|
||||
|
||||
#include <bench/bench.h>
|
||||
#include <rpc/blockchain.h>
|
||||
#include <txmempool.h>
|
||||
|
||||
#include <univalue.h>
|
||||
|
||||
|
||||
static void AddTx(const CTransactionRef& tx, const CAmount& fee, CTxMemPool& pool) EXCLUSIVE_LOCKS_REQUIRED(cs_main, pool.cs)
|
||||
{
|
||||
LockPoints lp;
|
||||
pool.addUnchecked(CTxMemPoolEntry(tx, fee, /* time */ 0, /* height */ 1, /* spendsCoinbase */ false, /* sigOpCost */ 4, lp));
|
||||
}
|
||||
|
||||
static void RpcMempool(benchmark::Bench& bench)
|
||||
{
|
||||
CTxMemPool pool;
|
||||
LOCK2(cs_main, pool.cs);
|
||||
|
||||
for (int i = 0; i < 1000; ++i) {
|
||||
CMutableTransaction tx = CMutableTransaction();
|
||||
tx.vin.resize(1);
|
||||
tx.vin[0].scriptSig = CScript() << OP_1;
|
||||
tx.vin[0].scriptWitness.stack.push_back({1});
|
||||
tx.vout.resize(1);
|
||||
tx.vout[0].scriptPubKey = CScript() << OP_1 << OP_EQUAL;
|
||||
tx.vout[0].nValue = i;
|
||||
const CTransactionRef tx_r{MakeTransactionRef(tx)};
|
||||
AddTx(tx_r, /* fee */ i, pool);
|
||||
}
|
||||
|
||||
bench.run([&] {
|
||||
(void)MempoolToJSON(pool, /*verbose*/ true);
|
||||
});
|
||||
}
|
||||
|
||||
BENCHMARK(RpcMempool);
|
||||
42
src/bench/util_time.cpp
Normal file
42
src/bench/util_time.cpp
Normal file
|
|
@ -0,0 +1,42 @@
|
|||
// Copyright (c) 2019-2020 The DigiByte Core developers
|
||||
// Distributed under the MIT software license, see the accompanying
|
||||
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
|
||||
|
||||
#include <bench/bench.h>
|
||||
|
||||
#include <util/time.h>
|
||||
|
||||
static void BenchTimeDeprecated(benchmark::Bench& bench)
|
||||
{
|
||||
bench.run([&] {
|
||||
(void)GetTime();
|
||||
});
|
||||
}
|
||||
|
||||
static void BenchTimeMock(benchmark::Bench& bench)
|
||||
{
|
||||
SetMockTime(111);
|
||||
bench.run([&] {
|
||||
(void)GetTime<std::chrono::seconds>();
|
||||
});
|
||||
SetMockTime(0);
|
||||
}
|
||||
|
||||
static void BenchTimeMillis(benchmark::Bench& bench)
|
||||
{
|
||||
bench.run([&] {
|
||||
(void)GetTime<std::chrono::milliseconds>();
|
||||
});
|
||||
}
|
||||
|
||||
static void BenchTimeMillisSys(benchmark::Bench& bench)
|
||||
{
|
||||
bench.run([&] {
|
||||
(void)GetTimeMillis();
|
||||
});
|
||||
}
|
||||
|
||||
BENCHMARK(BenchTimeDeprecated);
|
||||
BENCHMARK(BenchTimeMillis);
|
||||
BENCHMARK(BenchTimeMillisSys);
|
||||
BENCHMARK(BenchTimeMock);
|
||||
101
src/bench/verify_script.cpp
Normal file
101
src/bench/verify_script.cpp
Normal file
|
|
@ -0,0 +1,101 @@
|
|||
// Copyright (c) 2016-2020 The Bitcoin Core developers
|
||||
// Copyright (c) 2016-2020 The DigiByte Core developers
|
||||
// Distributed under the MIT software license, see the accompanying
|
||||
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
|
||||
|
||||
#include <bench/bench.h>
|
||||
#include <key.h>
|
||||
#if defined(HAVE_CONSENSUS_LIB)
|
||||
#include <script/vextaconsensus.h>
|
||||
#endif
|
||||
#include <script/script.h>
|
||||
#include <script/standard.h>
|
||||
#include <streams.h>
|
||||
#include <test/util/transaction_utils.h>
|
||||
|
||||
#include <array>
|
||||
|
||||
// Microbenchmark for verification of a basic P2WPKH script. Can be easily
|
||||
// modified to measure performance of other types of scripts.
|
||||
static void VerifyScriptBench(benchmark::Bench& bench)
|
||||
{
|
||||
const ECCVerifyHandle verify_handle;
|
||||
ECC_Start();
|
||||
|
||||
const int flags = SCRIPT_VERIFY_WITNESS | SCRIPT_VERIFY_P2SH;
|
||||
const int witnessversion = 0;
|
||||
|
||||
// Key pair.
|
||||
CKey key;
|
||||
static const std::array<unsigned char, 32> vchKey = {
|
||||
{
|
||||
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.begin(), vchKey.end(), false);
|
||||
CPubKey pubkey = key.GetPubKey();
|
||||
uint160 pubkeyHash;
|
||||
CHash160().Write(pubkey).Finalize(pubkeyHash);
|
||||
|
||||
// Script.
|
||||
CScript scriptPubKey = CScript() << witnessversion << ToByteVector(pubkeyHash);
|
||||
CScript scriptSig;
|
||||
CScript witScriptPubkey = CScript() << OP_DUP << OP_HASH160 << ToByteVector(pubkeyHash) << OP_EQUALVERIFY << OP_CHECKSIG;
|
||||
const CMutableTransaction& txCredit = BuildCreditingTransaction(scriptPubKey, 1);
|
||||
CMutableTransaction txSpend = BuildSpendingTransaction(scriptSig, CScriptWitness(), CTransaction(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());
|
||||
witness.stack.back().push_back(static_cast<unsigned char>(SIGHASH_ALL));
|
||||
witness.stack.push_back(ToByteVector(pubkey));
|
||||
|
||||
// Benchmark.
|
||||
bench.run([&] {
|
||||
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, MissingDataBehavior::ASSERT_FAIL),
|
||||
&err);
|
||||
assert(err == SCRIPT_ERR_OK);
|
||||
assert(success);
|
||||
|
||||
#if defined(HAVE_CONSENSUS_LIB)
|
||||
CDataStream stream(SER_NETWORK, PROTOCOL_VERSION);
|
||||
stream << txSpend;
|
||||
int csuccess = vextaconsensus_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
|
||||
});
|
||||
ECC_Stop();
|
||||
}
|
||||
|
||||
static void VerifyNestedIfScript(benchmark::Bench& bench)
|
||||
{
|
||||
std::vector<std::vector<unsigned char>> stack;
|
||||
CScript script;
|
||||
for (int i = 0; i < 100; ++i) {
|
||||
script << OP_1 << OP_IF;
|
||||
}
|
||||
for (int i = 0; i < 1000; ++i) {
|
||||
script << OP_1;
|
||||
}
|
||||
for (int i = 0; i < 100; ++i) {
|
||||
script << OP_ENDIF;
|
||||
}
|
||||
bench.run([&] {
|
||||
auto stack_copy = stack;
|
||||
ScriptError error;
|
||||
bool ret = EvalScript(stack_copy, script, 0, BaseSignatureChecker(), SigVersion::BASE, &error);
|
||||
assert(ret);
|
||||
});
|
||||
}
|
||||
|
||||
BENCHMARK(VerifyScriptBench);
|
||||
BENCHMARK(VerifyNestedIfScript);
|
||||
56
src/bench/wallet_balance.cpp
Normal file
56
src/bench/wallet_balance.cpp
Normal file
|
|
@ -0,0 +1,56 @@
|
|||
// Copyright (c) 2012-2020 The DigiByte Core developers
|
||||
// Distributed under the MIT software license, see the accompanying
|
||||
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
|
||||
|
||||
#include <bench/bench.h>
|
||||
#include <interfaces/chain.h>
|
||||
#include <node/context.h>
|
||||
#include <test/util/mining.h>
|
||||
#include <test/util/setup_common.h>
|
||||
#include <test/util/wallet.h>
|
||||
#include <validationinterface.h>
|
||||
#include <wallet/wallet.h>
|
||||
|
||||
#include <optional>
|
||||
|
||||
static void WalletBalance(benchmark::Bench& bench, const bool set_dirty, const bool add_watchonly, const bool add_mine)
|
||||
{
|
||||
const auto test_setup = MakeNoLogFileContext<const TestingSetup>();
|
||||
|
||||
const auto& ADDRESS_WATCHONLY = ADDRESS_dgbrt_UNSPENDABLE;
|
||||
|
||||
CWallet wallet{test_setup->m_node.chain.get(), "", CreateMockWalletDatabase()};
|
||||
{
|
||||
wallet.SetupLegacyScriptPubKeyMan();
|
||||
if (wallet.LoadWallet() != DBErrors::LOAD_OK) assert(false);
|
||||
}
|
||||
auto handler = test_setup->m_node.chain->handleNotifications({&wallet, [](CWallet*) {}});
|
||||
|
||||
const std::optional<std::string> address_mine{add_mine ? std::optional<std::string>{getnewaddress(wallet)} : std::nullopt};
|
||||
if (add_watchonly) importaddress(wallet, ADDRESS_WATCHONLY);
|
||||
|
||||
for (int i = 0; i < 60; ++i) {
|
||||
generatetoaddress(test_setup->m_node, address_mine.value_or(ADDRESS_WATCHONLY));
|
||||
generatetoaddress(test_setup->m_node, ADDRESS_WATCHONLY);
|
||||
}
|
||||
SyncWithValidationInterfaceQueue();
|
||||
|
||||
auto bal = wallet.GetBalance(); // Cache
|
||||
|
||||
bench.run([&] {
|
||||
if (set_dirty) wallet.MarkDirty();
|
||||
bal = wallet.GetBalance();
|
||||
if (add_mine) assert(bal.m_mine_trusted > 0);
|
||||
if (add_watchonly) assert(bal.m_watchonly_trusted > 0);
|
||||
});
|
||||
}
|
||||
|
||||
static void WalletBalanceDirty(benchmark::Bench& bench) { WalletBalance(bench, /* set_dirty */ true, /* add_watchonly */ true, /* add_mine */ true); }
|
||||
static void WalletBalanceClean(benchmark::Bench& bench) { WalletBalance(bench, /* set_dirty */ false, /* add_watchonly */ true, /* add_mine */ true); }
|
||||
static void WalletBalanceMine(benchmark::Bench& bench) { WalletBalance(bench, /* set_dirty */ false, /* add_watchonly */ false, /* add_mine */ true); }
|
||||
static void WalletBalanceWatch(benchmark::Bench& bench) { WalletBalance(bench, /* set_dirty */ false, /* add_watchonly */ true, /* add_mine */ false); }
|
||||
|
||||
BENCHMARK(WalletBalanceDirty);
|
||||
BENCHMARK(WalletBalanceClean);
|
||||
BENCHMARK(WalletBalanceMine);
|
||||
BENCHMARK(WalletBalanceWatch);
|
||||
Loading…
Reference in a new issue