diff options
Diffstat (limited to 'src/bench')
-rw-r--r-- | src/bench/addrman.cpp | 11 | ||||
-rw-r--r-- | src/bench/bench.cpp | 7 | ||||
-rw-r--r-- | src/bench/bench.h | 1 | ||||
-rw-r--r-- | src/bench/bench_bitcoin.cpp | 16 | ||||
-rw-r--r-- | src/bench/checkqueue.cpp | 8 | ||||
-rw-r--r-- | src/bench/coin_selection.cpp | 4 | ||||
-rw-r--r-- | src/bench/mempool_eviction.cpp | 2 | ||||
-rw-r--r-- | src/bench/mempool_stress.cpp | 13 | ||||
-rw-r--r-- | src/bench/prevector.cpp | 4 | ||||
-rw-r--r-- | src/bench/rpc_blockchain.cpp | 4 | ||||
-rw-r--r-- | src/bench/rpc_mempool.cpp | 5 | ||||
-rw-r--r-- | src/bench/strencodings.cpp | 18 | ||||
-rw-r--r-- | src/bench/wallet_loading.cpp | 133 |
13 files changed, 196 insertions, 30 deletions
diff --git a/src/bench/addrman.cpp b/src/bench/addrman.cpp index 34bc4380dd..76300f4db8 100644 --- a/src/bench/addrman.cpp +++ b/src/bench/addrman.cpp @@ -4,6 +4,7 @@ #include <addrman.h> #include <bench/bench.h> +#include <netgroup.h> #include <random.h> #include <util/check.h> #include <util/time.h> @@ -16,7 +17,7 @@ static constexpr size_t NUM_SOURCES = 64; static constexpr size_t NUM_ADDRESSES_PER_SOURCE = 256; -static const std::vector<bool> EMPTY_ASMAP; +static NetGroupManager EMPTY_NETGROUPMAN{std::vector<bool>()}; static constexpr uint32_t ADDRMAN_CONSISTENCY_CHECK_RATIO{0}; static std::vector<CAddress> g_sources; @@ -77,14 +78,14 @@ static void AddrManAdd(benchmark::Bench& bench) CreateAddresses(); bench.run([&] { - AddrMan addrman{EMPTY_ASMAP, /*deterministic=*/false, ADDRMAN_CONSISTENCY_CHECK_RATIO}; + AddrMan addrman{EMPTY_NETGROUPMAN, /*deterministic=*/false, ADDRMAN_CONSISTENCY_CHECK_RATIO}; AddAddressesToAddrMan(addrman); }); } static void AddrManSelect(benchmark::Bench& bench) { - AddrMan addrman{EMPTY_ASMAP, /*deterministic=*/false, ADDRMAN_CONSISTENCY_CHECK_RATIO}; + AddrMan addrman{EMPTY_NETGROUPMAN, /*deterministic=*/false, ADDRMAN_CONSISTENCY_CHECK_RATIO}; FillAddrMan(addrman); @@ -96,7 +97,7 @@ static void AddrManSelect(benchmark::Bench& bench) static void AddrManGetAddr(benchmark::Bench& bench) { - AddrMan addrman{EMPTY_ASMAP, /*deterministic=*/false, ADDRMAN_CONSISTENCY_CHECK_RATIO}; + AddrMan addrman{EMPTY_NETGROUPMAN, /*deterministic=*/false, ADDRMAN_CONSISTENCY_CHECK_RATIO}; FillAddrMan(addrman); @@ -125,7 +126,7 @@ static void AddrManAddThenGood(benchmark::Bench& bench) // // This has some overhead (exactly the result of AddrManAdd benchmark), but that overhead is constant so improvements in // AddrMan::Good() will still be noticeable. - AddrMan addrman{EMPTY_ASMAP, /*deterministic=*/false, ADDRMAN_CONSISTENCY_CHECK_RATIO}; + AddrMan addrman{EMPTY_NETGROUPMAN, /*deterministic=*/false, ADDRMAN_CONSISTENCY_CHECK_RATIO}; AddAddressesToAddrMan(addrman); markSomeAsGood(addrman); diff --git a/src/bench/bench.cpp b/src/bench/bench.cpp index 033d319750..26975bb59d 100644 --- a/src/bench/bench.cpp +++ b/src/bench/bench.cpp @@ -57,6 +57,10 @@ void benchmark::BenchRunner::RunAll(const Args& args) std::regex reFilter(args.regex_filter); std::smatch baseMatch; + if (args.sanity_check) { + std::cout << "Running with --sanity-check option, benchmark results will be useless." << std::endl; + } + std::vector<ankerl::nanobench::Result> benchmarkResults; for (const auto& p : benchmarks()) { if (!std::regex_match(p.first, baseMatch, reFilter)) { @@ -69,6 +73,9 @@ void benchmark::BenchRunner::RunAll(const Args& args) } Bench bench; + if (args.sanity_check) { + bench.epochs(1).epochIterations(1); + } bench.name(p.first); if (args.min_time > 0ms) { // convert to nanos before dividing to reduce rounding errors diff --git a/src/bench/bench.h b/src/bench/bench.h index 6634138beb..17535e4e81 100644 --- a/src/bench/bench.h +++ b/src/bench/bench.h @@ -43,6 +43,7 @@ typedef std::function<void(Bench&)> BenchFunction; struct Args { bool is_list_only; + bool sanity_check; std::chrono::milliseconds min_time; std::vector<double> asymptote; fs::path output_csv; diff --git a/src/bench/bench_bitcoin.cpp b/src/bench/bench_bitcoin.cpp index d6f9c0f8b5..1bb4d34db9 100644 --- a/src/bench/bench_bitcoin.cpp +++ b/src/bench/bench_bitcoin.cpp @@ -26,9 +26,10 @@ static void SetupBenchArgs(ArgsManager& argsman) argsman.AddArg("-asymptote=<n1,n2,n3,...>", "Test asymptotic growth of the runtime of an algorithm, if supported by the benchmark", 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("-list", "List benchmarks without executing them", ArgsManager::ALLOW_ANY, OptionsCategory::OPTIONS); - argsman.AddArg("-min_time=<milliseconds>", strprintf("Minimum runtime per benchmark, in milliseconds (default: %d)", DEFAULT_MIN_TIME_MS), ArgsManager::ALLOW_ANY | ArgsManager::DISALLOW_NEGATION, 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); + argsman.AddArg("-min-time=<milliseconds>", strprintf("Minimum runtime per benchmark, in milliseconds (default: %d)", DEFAULT_MIN_TIME_MS), ArgsManager::ALLOW_ANY | ArgsManager::DISALLOW_NEGATION, 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); + argsman.AddArg("-sanity-check", "Run benchmarks for only one iteration", ArgsManager::ALLOW_ANY, OptionsCategory::OPTIONS); } // parses a comma separated list like "10,20,30,50" @@ -73,7 +74,7 @@ int main(int argc, char** argv) " sure each run has exactly the same preconditions.\n" "\n" " * If results are still not reliable, increase runtime with e.g.\n" - " -min_time=5000 to let a benchmark run for at least 5 seconds.\n" + " -min-time=5000 to let a benchmark run for at least 5 seconds.\n" "\n" " * bench_bitcoin uses nanobench [3] for which there is extensive\n" " documentation available online.\n" @@ -108,10 +109,11 @@ int main(int argc, char** argv) benchmark::Args args; args.asymptote = parseAsymptote(argsman.GetArg("-asymptote", "")); args.is_list_only = argsman.GetBoolArg("-list", false); - args.min_time = std::chrono::milliseconds(argsman.GetIntArg("-min_time", DEFAULT_MIN_TIME_MS)); - args.output_csv = argsman.GetPathArg("-output_csv"); - args.output_json = argsman.GetPathArg("-output_json"); + args.min_time = std::chrono::milliseconds(argsman.GetIntArg("-min-time", DEFAULT_MIN_TIME_MS)); + args.output_csv = argsman.GetPathArg("-output-csv"); + args.output_json = argsman.GetPathArg("-output-json"); args.regex_filter = argsman.GetArg("-filter", DEFAULT_BENCH_FILTER); + args.sanity_check = argsman.GetBoolArg("-sanity-check", false); benchmark::BenchRunner::RunAll(args); diff --git a/src/bench/checkqueue.cpp b/src/bench/checkqueue.cpp index d7b8c1badc..602081fb9b 100644 --- a/src/bench/checkqueue.cpp +++ b/src/bench/checkqueue.cpp @@ -30,8 +30,7 @@ static void CCheckQueueSpeedPrevectorJob(benchmark::Bench& bench) struct PrevectorJob { prevector<PREVECTOR_SIZE, uint8_t> p; - PrevectorJob(){ - } + PrevectorJob() = default; explicit PrevectorJob(FastRandomContext& insecure_rand){ p.resize(insecure_rand.randrange(PREVECTOR_SIZE*2)); } @@ -39,7 +38,10 @@ static void CCheckQueueSpeedPrevectorJob(benchmark::Bench& bench) { return true; } - void swap(PrevectorJob& x){p.swap(x.p);}; + void swap(PrevectorJob& x) noexcept + { + p.swap(x.p); + }; }; CCheckQueue<PrevectorJob> queue {QUEUE_BATCH_SIZE}; // The main thread should be counted to prevent thread oversubscription, and diff --git a/src/bench/coin_selection.cpp b/src/bench/coin_selection.cpp index de8ab9807c..b2958bcc9f 100644 --- a/src/bench/coin_selection.cpp +++ b/src/bench/coin_selection.cpp @@ -58,7 +58,7 @@ static void CoinSelection(benchmark::Bench& bench) // Create coins std::vector<COutput> coins; for (const auto& wtx : wtxs) { - coins.emplace_back(COutPoint(wtx->GetHash(), 0), wtx->tx->vout.at(0), /*depth=*/6 * 24, GetTxSpendSize(wallet, *wtx, 0), /*spendable=*/true, /*solvable=*/true, /*safe=*/true, wtx->GetTxTime(), /*from_me=*/true); + coins.emplace_back(COutPoint(wtx->GetHash(), 0), wtx->tx->vout.at(0), /*depth=*/6 * 24, GetTxSpendSize(wallet, *wtx, 0), /*spendable=*/true, /*solvable=*/true, /*safe=*/true, wtx->GetTxTime(), /*from_me=*/true, /*fees=*/ 0); } const CoinEligibilityFilter filter_standard(1, 6, 0); @@ -88,7 +88,7 @@ static void add_coin(const CAmount& nValue, int nInput, std::vector<OutputGroup> CMutableTransaction tx; tx.vout.resize(nInput + 1); tx.vout[nInput].nValue = nValue; - COutput output(COutPoint(tx.GetHash(), nInput), tx.vout.at(nInput), /*depth=*/ 0, /*input_bytes=*/ -1, /*spendable=*/ true, /*solvable=*/ true, /*safe=*/ true, /*time=*/ 0, /*from_me=*/ true); + COutput output(COutPoint(tx.GetHash(), nInput), tx.vout.at(nInput), /*depth=*/ 0, /*input_bytes=*/ -1, /*spendable=*/ true, /*solvable=*/ true, /*safe=*/ true, /*time=*/ 0, /*from_me=*/ true, /*fees=*/ 0); set.emplace_back(); set.back().Insert(output, /*ancestors=*/ 0, /*descendants=*/ 0, /*positive_only=*/ false); } diff --git a/src/bench/mempool_eviction.cpp b/src/bench/mempool_eviction.cpp index e80b9e1ac2..60d991fab9 100644 --- a/src/bench/mempool_eviction.cpp +++ b/src/bench/mempool_eviction.cpp @@ -108,7 +108,7 @@ static void MempoolEviction(benchmark::Bench& bench) tx7.vout[1].scriptPubKey = CScript() << OP_7 << OP_EQUAL; tx7.vout[1].nValue = 10 * COIN; - CTxMemPool pool; + CTxMemPool& pool = *Assert(testing_setup->m_node.mempool); LOCK2(cs_main, pool.cs); // Create transaction references outside the "hot loop" const CTransactionRef tx1_r{MakeTransactionRef(tx1)}; diff --git a/src/bench/mempool_stress.cpp b/src/bench/mempool_stress.cpp index a58658c4f1..725a6f8f5b 100644 --- a/src/bench/mempool_stress.cpp +++ b/src/bench/mempool_stress.cpp @@ -88,7 +88,7 @@ static void ComplexMemPool(benchmark::Bench& bench) } std::vector<CTransactionRef> ordered_coins = CreateOrderedCoins(det_rand, childTxs, /*min_ancestors=*/1); const auto testing_setup = MakeNoLogFileContext<const TestingSetup>(CBaseChainParams::MAIN); - CTxMemPool pool; + CTxMemPool& pool = *testing_setup.get()->m_node.mempool; LOCK2(cs_main, pool.cs); bench.run([&]() NO_THREAD_SAFETY_ANALYSIS { for (auto& tx : ordered_coins) { @@ -102,16 +102,15 @@ static void ComplexMemPool(benchmark::Bench& bench) static void MempoolCheck(benchmark::Bench& bench) { FastRandomContext det_rand{true}; - const int childTxs = bench.complexityN() > 1 ? static_cast<int>(bench.complexityN()) : 2000; - const std::vector<CTransactionRef> ordered_coins = CreateOrderedCoins(det_rand, childTxs, /*min_ancestors=*/5); - const auto testing_setup = MakeNoLogFileContext<const TestingSetup>(CBaseChainParams::MAIN, {"-checkmempool=1"}); - CTxMemPool pool; + auto testing_setup = MakeNoLogFileContext<TestChain100Setup>(CBaseChainParams::REGTEST, {"-checkmempool=1"}); + CTxMemPool& pool = *testing_setup.get()->m_node.mempool; LOCK2(cs_main, pool.cs); + testing_setup->PopulateMempool(det_rand, 400, true); const CCoinsViewCache& coins_tip = testing_setup.get()->m_node.chainman->ActiveChainstate().CoinsTip(); - for (auto& tx : ordered_coins) AddTx(tx, pool); bench.run([&]() NO_THREAD_SAFETY_ANALYSIS { - pool.check(coins_tip, /*spendheight=*/2); + // Bump up the spendheight so we don't hit premature coinbase spend errors. + pool.check(coins_tip, /*spendheight=*/300); }); } diff --git a/src/bench/prevector.cpp b/src/bench/prevector.cpp index 6343ed7848..b3688bab1b 100644 --- a/src/bench/prevector.cpp +++ b/src/bench/prevector.cpp @@ -10,8 +10,8 @@ #include <bench/bench.h> struct nontrivial_t { - int x; - nontrivial_t() :x(-1) {} + int x{-1}; + nontrivial_t() = default; SERIALIZE_METHODS(nontrivial_t, obj) { READWRITE(obj.x); } }; static_assert(!std::is_trivially_default_constructible<nontrivial_t>::value, diff --git a/src/bench/rpc_blockchain.cpp b/src/bench/rpc_blockchain.cpp index 2143bcf950..e6fc8d21f4 100644 --- a/src/bench/rpc_blockchain.cpp +++ b/src/bench/rpc_blockchain.cpp @@ -40,7 +40,7 @@ static void BlockToJsonVerbose(benchmark::Bench& bench) { TestBlockAndIndex data; bench.run([&] { - auto univalue = blockToJSON(data.block, &data.blockindex, &data.blockindex, TxVerbosity::SHOW_DETAILS_AND_PREVOUT); + auto univalue = blockToJSON(data.testing_setup->m_node.chainman->m_blockman, data.block, &data.blockindex, &data.blockindex, TxVerbosity::SHOW_DETAILS_AND_PREVOUT); ankerl::nanobench::doNotOptimizeAway(univalue); }); } @@ -50,7 +50,7 @@ BENCHMARK(BlockToJsonVerbose); static void BlockToJsonVerboseWrite(benchmark::Bench& bench) { TestBlockAndIndex data; - auto univalue = blockToJSON(data.block, &data.blockindex, &data.blockindex, TxVerbosity::SHOW_DETAILS_AND_PREVOUT); + auto univalue = blockToJSON(data.testing_setup->m_node.chainman->m_blockman, data.block, &data.blockindex, &data.blockindex, TxVerbosity::SHOW_DETAILS_AND_PREVOUT); bench.run([&] { auto str = univalue.write(); ankerl::nanobench::doNotOptimizeAway(str); diff --git a/src/bench/rpc_mempool.cpp b/src/bench/rpc_mempool.cpp index 6e322ba6aa..0e6fdae3d7 100644 --- a/src/bench/rpc_mempool.cpp +++ b/src/bench/rpc_mempool.cpp @@ -3,7 +3,9 @@ // file COPYING or http://www.opensource.org/licenses/mit-license.php. #include <bench/bench.h> +#include <chainparamsbase.h> #include <rpc/mempool.h> +#include <test/util/setup_common.h> #include <txmempool.h> #include <univalue.h> @@ -17,7 +19,8 @@ static void AddTx(const CTransactionRef& tx, const CAmount& fee, CTxMemPool& poo static void RpcMempool(benchmark::Bench& bench) { - CTxMemPool pool; + const auto testing_setup = MakeNoLogFileContext<const ChainTestingSetup>(CBaseChainParams::MAIN); + CTxMemPool& pool = *Assert(testing_setup->m_node.mempool); LOCK2(cs_main, pool.cs); for (int i = 0; i < 1000; ++i) { diff --git a/src/bench/strencodings.cpp b/src/bench/strencodings.cpp new file mode 100644 index 0000000000..69b3a83cbf --- /dev/null +++ b/src/bench/strencodings.cpp @@ -0,0 +1,18 @@ +// Copyright (c) 2022 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/bench.h> +#include <bench/data.h> +#include <util/strencodings.h> + +static void HexStrBench(benchmark::Bench& bench) +{ + auto const& data = benchmark::data::block413567; + bench.batch(data.size()).unit("byte").run([&] { + auto hex = HexStr(data); + ankerl::nanobench::doNotOptimizeAway(hex); + }); +} + +BENCHMARK(HexStrBench); diff --git a/src/bench/wallet_loading.cpp b/src/bench/wallet_loading.cpp new file mode 100644 index 0000000000..f611383788 --- /dev/null +++ b/src/bench/wallet_loading.cpp @@ -0,0 +1,133 @@ +// Copyright (c) 2022 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/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 <util/translation.h> +#include <validationinterface.h> +#include <wallet/context.h> +#include <wallet/receive.h> +#include <wallet/wallet.h> + +#include <optional> + +using wallet::CWallet; +using wallet::DatabaseFormat; +using wallet::DatabaseOptions; +using wallet::ISMINE_SPENDABLE; +using wallet::MakeWalletDatabase; +using wallet::TxStateInactive; +using wallet::WALLET_FLAG_DESCRIPTORS; +using wallet::WalletContext; +using wallet::WalletDatabase; + +static const std::shared_ptr<CWallet> BenchLoadWallet(std::unique_ptr<WalletDatabase> database, WalletContext& context, DatabaseOptions& options) +{ + bilingual_str error; + std::vector<bilingual_str> warnings; + auto wallet = CWallet::Create(context, "", std::move(database), options.create_flags, error, warnings); + NotifyWalletLoaded(context, wallet); + if (context.chain) { + wallet->postInitProcess(); + } + return wallet; +} + +static void BenchUnloadWallet(std::shared_ptr<CWallet>&& wallet) +{ + SyncWithValidationInterfaceQueue(); + wallet->m_chain_notifications_handler.reset(); + UnloadWallet(std::move(wallet)); +} + +static void AddTx(CWallet& wallet) +{ + bilingual_str error; + CTxDestination dest; + wallet.GetNewDestination(OutputType::BECH32, "", dest, error); + + CMutableTransaction mtx; + mtx.vout.push_back({COIN, GetScriptForDestination(dest)}); + mtx.vin.push_back(CTxIn()); + + wallet.AddToWallet(MakeTransactionRef(mtx), TxStateInactive{}); +} + +static std::unique_ptr<WalletDatabase> DuplicateMockDatabase(WalletDatabase& database, DatabaseOptions& options) +{ + auto new_database = CreateMockWalletDatabase(options); + + // Get a cursor to the original database + auto batch = database.MakeBatch(); + batch->StartCursor(); + + // Get a batch for the new database + auto new_batch = new_database->MakeBatch(); + + // Read all records from the original database and write them to the new one + while (true) { + CDataStream key(SER_DISK, CLIENT_VERSION); + CDataStream value(SER_DISK, CLIENT_VERSION); + bool complete; + batch->ReadAtCursor(key, value, complete); + if (complete) break; + new_batch->Write(key, value); + } + + return new_database; +} + +static void WalletLoading(benchmark::Bench& bench, bool legacy_wallet) +{ + const auto test_setup = MakeNoLogFileContext<TestingSetup>(); + test_setup->m_args.ForceSetArg("-unsafesqlitesync", "1"); + + WalletContext context; + context.args = &test_setup->m_args; + context.chain = test_setup->m_node.chain.get(); + + // Setup the wallet + // Loading the wallet will also create it + DatabaseOptions options; + if (legacy_wallet) { + options.require_format = DatabaseFormat::BERKELEY; + } else { + options.create_flags = WALLET_FLAG_DESCRIPTORS; + options.require_format = DatabaseFormat::SQLITE; + } + auto database = CreateMockWalletDatabase(options); + auto wallet = BenchLoadWallet(std::move(database), context, options); + + // Generate a bunch of transactions and addresses to put into the wallet + for (int i = 0; i < 1000; ++i) { + AddTx(*wallet); + } + + database = DuplicateMockDatabase(wallet->GetDatabase(), options); + + // reload the wallet for the actual benchmark + BenchUnloadWallet(std::move(wallet)); + + bench.epochs(5).run([&] { + wallet = BenchLoadWallet(std::move(database), context, options); + + // Cleanup + database = DuplicateMockDatabase(wallet->GetDatabase(), options); + BenchUnloadWallet(std::move(wallet)); + }); +} + +#ifdef USE_BDB +static void WalletLoadingLegacy(benchmark::Bench& bench) { WalletLoading(bench, /*legacy_wallet=*/true); } +BENCHMARK(WalletLoadingLegacy); +#endif + +#ifdef USE_SQLITE +static void WalletLoadingDescriptors(benchmark::Bench& bench) { WalletLoading(bench, /*legacy_wallet=*/false); } +BENCHMARK(WalletLoadingDescriptors); +#endif |