-
Notifications
You must be signed in to change notification settings - Fork 38.6k
bench: Make WalletLoading benchmark run faster #24924
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
bench: Make WalletLoading benchmark run faster #24924
Conversation
This is probably unnecessary and just makes it slower.
|
@fanquake Is this good enough or do you want faster? |
|
review ACK 9e404a9 |
|
On my machine: Before PR #24913 After PR #24913 This PR There's a good improvement (348.35 secs) over PR #24913 (540.03 secs), but it still takes a lot longer than before it (57.34 secs). |
I think to be good enough, it needs to run in a similar time to all of the other benchmarks, i.e max ~1-2 seconds, otherwise anyone running | 80,237.38 | 12,463.02 | 0.1% | 0.01 | `VerifyScriptBench`
| 8,190.91 | 122,086.52 | 1.2% | 0.01 | `WalletBalanceClean`
| 179,780.20 | 5,562.35 | 1.5% | 0.01 | `WalletBalanceDirty`
| 7,929.42 | 126,112.61 | 0.1% | 0.01 | `WalletBalanceMine`
| 42.47 | 23,546,683.62 | 0.0% | 0.01 | `WalletBalanceWatch`
| 902,283,977.00 | 1.11 | 1.4% | 105.48 | `WalletLoadingDescriptors`
^C
src/bench/bench_bitcoin 59.66s user 24.31s system 11% cpu 12:01.03 total
Given that, it seems like we've got another macOS only-performance issue, that we should probably figure out the root cause of? |
Agree. It's unacceptable to have a benchmark take in the order of minutes. Remember that benchmarks are there to measure small timespans (such as inner loop functions), not very long processes. I've also seen a CI timeout due to this. Remember that we do |
|
I've added the following changes:
This still doesn't make it as fast as the other benchmarks though. Before #24913: After #24913: This PR: |
|
This PR makes (Ubuntu 22.04 on a Ryzen 5950X system; my ZFS filesystem setup may make flushing/syncing relatively slower) |
|
Looks like this also introduces memory corruption, looking at the CI output? |
We may want to make a mock database of either SQLite or BDB, not just whatever the compiled default is.
The mock db can be in-memory rather than just at temp file.
Using in-memory only databases speeds up the benchmark, at the cost of real world accuracy.
Add descriptor wallet benchmark only if sqlite is compiled. Add legacy wallet benchmark only if bdb is compiled.
2b82a5e to
e673d8b
Compare
|
Haven't reviewed the code at all, but e673d8b reduces the runtime of the WalletLoadingDescriptors test from 4m25s to 0.1s for me |
theStack
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Concept ACK
Didn't look much at the code yet, but ran the benchmarks for both legacy and descriptor wallet on my (rather slow) system after each commit and master via
$ time ./src/bench/bench_bitcoin -filter=WalletLoadingLegacy
$ time ./src/bench/bench_bitcoin -filter=WalletLoadingDescriptors
with the following results:
| Legacy | Descriptors | |
|---|---|---|
| master | 3m18.39s | 5m40.95s |
| Remove minEpochIterations (9e404a9) | 1m54.15s | 2m51.50s |
| use unsafesqlitesync (817c051) | 1m53.68s | 2m46.76s |
| reduce number of epochs (d94244c) | 1m49.12s | 2m38.29s |
| add txs directly instead of mining blocks (f85b54e) | 1m27.61s | 1m51.24s |
| reduce number of txs in wallet (7c0d344) | 0m19.83s | 0m27.06s |
| create mock db (a108080) | 0m19.56s | 0m26.18s |
| use in-memory db for mock db (49910f2) | 0m19.36s | 0m26.03s |
| use mock db (4af3547) | 0m09.16s | 0m07.25s |
| load bench depending on what's compiled (e673d8b) | 0m09.51s | 0m07.19s |
Marked the commits in bold where the most gains (at least 2x) were observed. Looking closer at the descriptor wallet benchmark, if I (manually) revert commits 817c051 (using unsafesqlitesync) and 49910f2 (use in-memory mode for mock db) on the top commit via the patch
diff --git a/src/bench/wallet_loading.cpp b/src/bench/wallet_loading.cpp
index f61138378..994811c79 100644
--- a/src/bench/wallet_loading.cpp
+++ b/src/bench/wallet_loading.cpp
@@ -85,7 +85,6 @@ static std::unique_ptr<WalletDatabase> DuplicateMockDatabase(WalletDatabase& dat
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;
diff --git a/src/wallet/walletdb.cpp b/src/wallet/walletdb.cpp
index 72d483e61..26908b377 100644
--- a/src/wallet/walletdb.cpp
+++ b/src/wallet/walletdb.cpp
@@ -1203,7 +1203,7 @@ std::unique_ptr<WalletDatabase> CreateMockWalletDatabase(DatabaseOptions& option
if (format == DatabaseFormat::SQLITE) {
#ifdef USE_SQLITE
- return std::make_unique<SQLiteDatabase>(":memory:", "", options, true);
+ return std::make_unique<SQLiteDatabase>("", "", options, true);
#endif
assert(false);
}and got a run-time of 0m07.41s. From that result, I'd conclude that commits 817c051 and 49910f2 barely have any effect on the run-time and could in theory be removed from this PR (no hard feelings though).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Code review ACK e673d8b, nice PR.
With a note:
I think that we could keep generating a chain instead of adding the dummy txs directly, so the benchmark is more accurate to what happens in a real wallet (otherwise we are skipping some flows during the LoadToWallet(tx) process like the tx initial state update that requires a chain lookup).
What do you think about generating the chain manually instead of using the whole generatetoaddress flow, so we skip the entire BlockAssembler::CreateNewBlock, follow up TestBlockValidity, finding the correct nonce etc.. that are surely pretty slow.
As the wallet doesn't care about chain validity, we directly could: create, concatenate and append blocks into the chain index manually, which should be pretty fast, so the wallet can use them during the load flow.
| wallet = BenchLoadWallet(std::move(database), context, options); | ||
|
|
||
| // Cleanup | ||
| database = DuplicateMockDatabase(wallet->GetDatabase(), options); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
In 4af3547:
I'm not so sure why do we need to update the database here, guess that what you wanted to do is rollback the db to the first mocked database created at line 103 and not the recently loaded one? So in case of any modification, we ensure that the benchmark is always running from the same static db input?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actually it's because deleting the wallet so that we can load it again will delete the database.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
k, that is because of the db destructor, good.
I think |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Concept ACK e673d8b. For each commit, verified that there was a performance improvement without negating the purpose of the bench, and made some effort to verify that the code is correct.
Would be nice to get this merged. I haven't used make check without quitting at bench in months :(
Nit: could you update the OP to include the list of things you've changed to make it run faster? It currently only mentions minEpochIterations.
if I (manually) revert commits 817c051 (using unsafesqlitesync)
I think -unsafesqlitesync has more of an effect on macs than linux?
Fwiw, I don't know exactly what -unsafesqlitesync does, but tried dropping the commit on my mac and ubuntu machines. It seems like neither had any change (specifically on my machines though, not sure about others).
| #ifdef USE_BDB | ||
| return std::make_unique<BerkeleyDatabase>(std::make_shared<BerkeleyEnvironment>(), "", options); | ||
| #endif | ||
| assert(false); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
|
The following sections might be updated with supplementary metadata relevant to reviewers and maintainers. ConflictsReviewers, this pull request conflicts with the following ones:
If you consider this pull request important, please also help to review the conflicting pull requests. Ideally, start with the one that should be merged first. |
e673d8b bench: Enable loading benchmarks depending on what's compiled (Andrew Chow) 4af3547 bench: Use mock wallet database for wallet loading benchmark (Andrew Chow) 49910f2 sqlite: Use in-memory db instead of temp for mockdb (Andrew Chow) a108080 walletdb: Create a mock database of specific type (Andrew Chow) 7c0d344 bench: reduce the number of txs in wallet for wallet loading bench (Andrew Chow) f85b54e bench: Add transactions directly instead of mining blocks (Andrew Chow) d94244c bench: reduce number of epochs for wallet loading benchmark (Andrew Chow) 817c051 bench: use unsafesqlitesync in wallet loading benchmark (Andrew Chow) 9e404a9 bench: Remove minEpochIterations from wallet loading benchmark (Andrew Chow) Pull request description: `minEpochIterations` is probably unnecessary to set, so removing it makes the runtime much faster. ACKs for top commit: Rspigler: tACK e673d8b furszy: Code review ACK e673d8b, nice PR. glozow: Concept ACK e673d8b. For each commit, verified that there was a performance improvement without negating the purpose of the bench, and made some effort to verify that the code is correct. Tree-SHA512: 9337352ef846cf18642d5c14546c5abc1674b4975adb5dc961a1a276ca91f046b83b7a5e27ea6cd26264b96ae71151e14055579baf36afae7692ef4029800877
minEpochIterationsis probably unnecessary to set, so removing it makes the runtime much faster.