From 9e404a98312d73c969adf4f8e87aad1ac4b3029d Mon Sep 17 00:00:00 2001 From: Andrew Chow Date: Tue, 19 Apr 2022 12:22:44 -0400 Subject: [PATCH 1/9] bench: Remove minEpochIterations from wallet loading benchmark This is probably unnecessary and just makes it slower. --- src/bench/wallet_loading.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/bench/wallet_loading.cpp b/src/bench/wallet_loading.cpp index 38d3460001..8dc46c2268 100644 --- a/src/bench/wallet_loading.cpp +++ b/src/bench/wallet_loading.cpp @@ -68,7 +68,7 @@ static void WalletLoading(benchmark::Bench& bench, bool legacy_wallet) // reload the wallet for the actual benchmark BenchUnloadWallet(std::move(wallet)); - bench.minEpochIterations(10).run([&] { + bench.run([&] { wallet = BenchLoadWallet(context, options); // Cleanup From 817c051364208d3f9e7e2af5700bd2bee5c9f303 Mon Sep 17 00:00:00 2001 From: Andrew Chow Date: Wed, 20 Apr 2022 12:58:29 -0400 Subject: [PATCH 2/9] bench: use unsafesqlitesync in wallet loading benchmark --- src/bench/wallet_loading.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/bench/wallet_loading.cpp b/src/bench/wallet_loading.cpp index 8dc46c2268..80c285667e 100644 --- a/src/bench/wallet_loading.cpp +++ b/src/bench/wallet_loading.cpp @@ -49,6 +49,7 @@ static void BenchUnloadWallet(std::shared_ptr&& wallet) static void WalletLoading(benchmark::Bench& bench, bool legacy_wallet) { const auto test_setup = MakeNoLogFileContext(); + test_setup->m_args.ForceSetArg("-unsafesqlitesync", "1"); WalletContext context; context.args = &test_setup->m_args; From d94244c4bf37365272a16eb2ce6517605b4c8a47 Mon Sep 17 00:00:00 2001 From: Andrew Chow Date: Wed, 20 Apr 2022 13:52:45 -0400 Subject: [PATCH 3/9] bench: reduce number of epochs for wallet loading benchmark --- src/bench/wallet_loading.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/bench/wallet_loading.cpp b/src/bench/wallet_loading.cpp index 80c285667e..5096895ed8 100644 --- a/src/bench/wallet_loading.cpp +++ b/src/bench/wallet_loading.cpp @@ -69,7 +69,7 @@ static void WalletLoading(benchmark::Bench& bench, bool legacy_wallet) // reload the wallet for the actual benchmark BenchUnloadWallet(std::move(wallet)); - bench.run([&] { + bench.epochs(5).run([&] { wallet = BenchLoadWallet(context, options); // Cleanup From f85b54ed27bd6eddb1e7035db02d542575b3ab24 Mon Sep 17 00:00:00 2001 From: Andrew Chow Date: Wed, 20 Apr 2022 13:25:06 -0400 Subject: [PATCH 4/9] bench: Add transactions directly instead of mining blocks --- src/bench/wallet_loading.cpp | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/src/bench/wallet_loading.cpp b/src/bench/wallet_loading.cpp index 5096895ed8..1a3ae65111 100644 --- a/src/bench/wallet_loading.cpp +++ b/src/bench/wallet_loading.cpp @@ -21,6 +21,7 @@ using wallet::DatabaseOptions; using wallet::DatabaseStatus; using wallet::ISMINE_SPENDABLE; using wallet::MakeWalletDatabase; +using wallet::TxStateInactive; using wallet::WALLET_FLAG_DESCRIPTORS; using wallet::WalletContext; @@ -46,6 +47,19 @@ static void BenchUnloadWallet(std::shared_ptr&& wallet) 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 void WalletLoading(benchmark::Bench& bench, bool legacy_wallet) { const auto test_setup = MakeNoLogFileContext(); @@ -63,7 +77,7 @@ static void WalletLoading(benchmark::Bench& bench, bool legacy_wallet) // Generate a bunch of transactions and addresses to put into the wallet for (int i = 0; i < 5000; ++i) { - generatetoaddress(test_setup->m_node, getnewaddress(*wallet)); + AddTx(*wallet); } // reload the wallet for the actual benchmark From 7c0d34476df446e3825198b27c6f62bba4c0b974 Mon Sep 17 00:00:00 2001 From: Andrew Chow Date: Wed, 20 Apr 2022 13:52:27 -0400 Subject: [PATCH 5/9] bench: reduce the number of txs in wallet for wallet loading bench --- src/bench/wallet_loading.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/bench/wallet_loading.cpp b/src/bench/wallet_loading.cpp index 1a3ae65111..8fbd814d29 100644 --- a/src/bench/wallet_loading.cpp +++ b/src/bench/wallet_loading.cpp @@ -76,7 +76,7 @@ static void WalletLoading(benchmark::Bench& bench, bool legacy_wallet) auto wallet = BenchLoadWallet(context, options); // Generate a bunch of transactions and addresses to put into the wallet - for (int i = 0; i < 5000; ++i) { + for (int i = 0; i < 1000; ++i) { AddTx(*wallet); } From a1080802f8d7c3d1251ec6f2be33031f568deafa Mon Sep 17 00:00:00 2001 From: Andrew Chow Date: Wed, 20 Apr 2022 12:51:59 -0400 Subject: [PATCH 6/9] walletdb: Create a mock database of specific type We may want to make a mock database of either SQLite or BDB, not just whatever the compiled default is. --- src/wallet/walletdb.cpp | 33 ++++++++++++++++++++++++++++----- src/wallet/walletdb.h | 1 + 2 files changed, 29 insertions(+), 5 deletions(-) diff --git a/src/wallet/walletdb.cpp b/src/wallet/walletdb.cpp index 7bbed7973f..26908b3777 100644 --- a/src/wallet/walletdb.cpp +++ b/src/wallet/walletdb.cpp @@ -1187,13 +1187,36 @@ std::unique_ptr CreateDummyWalletDatabase() } /** Return object for accessing temporary in-memory database. */ +std::unique_ptr CreateMockWalletDatabase(DatabaseOptions& options) +{ + + std::optional format; + if (options.require_format) format = options.require_format; + if (!format) { +#ifdef USE_BDB + format = DatabaseFormat::BERKELEY; +#endif +#ifdef USE_SQLITE + format = DatabaseFormat::SQLITE; +#endif + } + + if (format == DatabaseFormat::SQLITE) { +#ifdef USE_SQLITE + return std::make_unique("", "", options, true); +#endif + assert(false); + } + +#ifdef USE_BDB + return std::make_unique(std::make_shared(), "", options); +#endif + assert(false); +} + std::unique_ptr CreateMockWalletDatabase() { DatabaseOptions options; -#ifdef USE_SQLITE - return std::make_unique("", "", options, true); -#elif USE_BDB - return std::make_unique(std::make_shared(), "", options); -#endif + return CreateMockWalletDatabase(options); } } // namespace wallet diff --git a/src/wallet/walletdb.h b/src/wallet/walletdb.h index 3dfe781d56..a04ea598b6 100644 --- a/src/wallet/walletdb.h +++ b/src/wallet/walletdb.h @@ -301,6 +301,7 @@ bool ReadKeyValue(CWallet* pwallet, CDataStream& ssKey, CDataStream& ssValue, st std::unique_ptr CreateDummyWalletDatabase(); /** Return object for accessing temporary in-memory database. */ +std::unique_ptr CreateMockWalletDatabase(DatabaseOptions& options); std::unique_ptr CreateMockWalletDatabase(); } // namespace wallet From 49910f255f77e14fccf189353d188efac00d1445 Mon Sep 17 00:00:00 2001 From: Andrew Chow Date: Wed, 20 Apr 2022 13:51:53 -0400 Subject: [PATCH 7/9] sqlite: Use in-memory db instead of temp for mockdb The mock db can be in-memory rather than just at temp file. --- src/wallet/walletdb.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/wallet/walletdb.cpp b/src/wallet/walletdb.cpp index 26908b3777..72d483e617 100644 --- a/src/wallet/walletdb.cpp +++ b/src/wallet/walletdb.cpp @@ -1203,7 +1203,7 @@ std::unique_ptr CreateMockWalletDatabase(DatabaseOptions& option if (format == DatabaseFormat::SQLITE) { #ifdef USE_SQLITE - return std::make_unique("", "", options, true); + return std::make_unique(":memory:", "", options, true); #endif assert(false); } From 4af3547ebac672a2d516e8696fd3580a766c27eb Mon Sep 17 00:00:00 2001 From: Andrew Chow Date: Wed, 20 Apr 2022 13:03:45 -0400 Subject: [PATCH 8/9] bench: Use mock wallet database for wallet loading benchmark Using in-memory only databases speeds up the benchmark, at the cost of real world accuracy. --- src/bench/wallet_loading.cpp | 47 ++++++++++++++++++++++++++++++------ 1 file changed, 39 insertions(+), 8 deletions(-) diff --git a/src/bench/wallet_loading.cpp b/src/bench/wallet_loading.cpp index 8fbd814d29..0bbafee76e 100644 --- a/src/bench/wallet_loading.cpp +++ b/src/bench/wallet_loading.cpp @@ -17,21 +17,19 @@ #include using wallet::CWallet; +using wallet::DatabaseFormat; using wallet::DatabaseOptions; -using wallet::DatabaseStatus; 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 BenchLoadWallet(WalletContext& context, DatabaseOptions& options) +static const std::shared_ptr BenchLoadWallet(std::unique_ptr database, WalletContext& context, DatabaseOptions& options) { - DatabaseStatus status; bilingual_str error; std::vector warnings; - auto database = MakeWalletDatabase("", options, status, error); - assert(database); auto wallet = CWallet::Create(context, "", std::move(database), options.create_flags, error, warnings); NotifyWalletLoaded(context, wallet); if (context.chain) { @@ -60,6 +58,30 @@ static void AddTx(CWallet& wallet) wallet.AddToWallet(MakeTransactionRef(mtx), TxStateInactive{}); } +static std::unique_ptr 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(); @@ -72,21 +94,30 @@ static void WalletLoading(benchmark::Bench& bench, bool legacy_wallet) // Setup the wallet // Loading the wallet will also create it DatabaseOptions options; - if (!legacy_wallet) options.create_flags = WALLET_FLAG_DESCRIPTORS; - auto wallet = BenchLoadWallet(context, 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(context, options); + wallet = BenchLoadWallet(std::move(database), context, options); // Cleanup + database = DuplicateMockDatabase(wallet->GetDatabase(), options); BenchUnloadWallet(std::move(wallet)); }); } From e673d8b475995075b696208386c9e45ae7ca3e20 Mon Sep 17 00:00:00 2001 From: Andrew Chow Date: Wed, 20 Apr 2022 12:53:42 -0400 Subject: [PATCH 9/9] bench: Enable loading benchmarks depending on what's compiled Add descriptor wallet benchmark only if sqlite is compiled. Add legacy wallet benchmark only if bdb is compiled. --- src/bench/wallet_loading.cpp | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/src/bench/wallet_loading.cpp b/src/bench/wallet_loading.cpp index 0bbafee76e..f611383788 100644 --- a/src/bench/wallet_loading.cpp +++ b/src/bench/wallet_loading.cpp @@ -122,8 +122,12 @@ static void WalletLoading(benchmark::Bench& bench, bool legacy_wallet) }); } +#ifdef USE_BDB static void WalletLoadingLegacy(benchmark::Bench& bench) { WalletLoading(bench, /*legacy_wallet=*/true); } -static void WalletLoadingDescriptors(benchmark::Bench& bench) { WalletLoading(bench, /*legacy_wallet=*/false); } - BENCHMARK(WalletLoadingLegacy); +#endif + +#ifdef USE_SQLITE +static void WalletLoadingDescriptors(benchmark::Bench& bench) { WalletLoading(bench, /*legacy_wallet=*/false); } BENCHMARK(WalletLoadingDescriptors); +#endif