Perf/cache epoch version in ClarityDatabase#6959
Perf/cache epoch version in ClarityDatabase#6959jacinta-stacks wants to merge 14 commits intostacks-network:developfrom
Conversation
Signed-off-by: Jacinta Ferrant <236437600+jacinta-stacks@users.noreply.github.com>
…epoch Signed-off-by: Jacinta Ferrant <236437600+jacinta-stacks@users.noreply.github.com>
Codecov Report✅ All modified and coverable lines are covered by tests. Additional details and impacted files@@ Coverage Diff @@
## develop #6959 +/- ##
============================================
+ Coverage 68.63% 80.06% +11.42%
============================================
Files 412 412
Lines 219013 219023 +10
Branches 338 338
============================================
+ Hits 150330 175363 +25033
+ Misses 68683 43660 -25023
... and 257 files with indirect coverage changes Continue to review full report in Codecov by Sentry.
🚀 New features to boost your workflow:
|
cylewitruk-stacks
left a comment
There was a problem hiding this comment.
Makes sense to me. Just added a few benchmark suggestions.
clarity/benches/epoch_cache.rs
Outdated
| b.iter_batched( | ||
| setup_store, | ||
| |marf| run(&parsed, marf), | ||
| BatchSize::SmallInput, |
There was a problem hiding this comment.
I think that SmallInput may not be the best hint together with setup_store() since it tells Criterion that the values are small and it's okay to create thousands of them up-front (i.e. thousands of SQLite in-memory handles). Maybe use PerIteration or LargeInput?
But otoh if you don't see large memory usage when running the benchmarks then it might be small enough to not matter, I'm not sure off the top of my head how "resource hungry" the MemoryBackingStore + its SQLite in-mem instance is.
… into perf/cache-epoch-per-block
Signed-off-by: Jacinta Ferrant <236437600+jacinta-stacks@users.noreply.github.com>
|
Do you think we could add a couple of defensive regression tests specifically around the rollback and at-block cases asserting the cached value is cleared? The rollback case is clear in the diff, but not at-block (where I'm most insecure) -- and it's anyway cheap insurance that future changes don't mess this up? |
jcnelson
left a comment
There was a problem hiding this comment.
I think there could be a better way to do this: accept the epoch as an argument to ClarityDatabase::new() and ClarityDatabase::new_with_rollback_wrapper(). In all cases where we actually open the Clarity database on chainstate (i.e. not MemoryBackingStore), the epoch will be known to the caller. That could save you an additional MARF'ed read.
… into perf/cache-epoch-per-block
This is quite a substantial change. Not sure its worth the effort but I will give it a try and you can assess the result :) |
7d0bdcf to
7eecb90
Compare
7eecb90 to
e1d2a21
Compare
Signed-off-by: Jacinta Ferrant <236437600+jacinta-stacks@users.noreply.github.com>
e1d2a21 to
6bfa9fc
Compare
… read per transaction Signed-off-by: Jacinta Ferrant <236437600+jacinta-stacks@users.noreply.github.com>
… remove unused burn_state_db arg and in call chain
| /// Since Clarity did not exist in stacks 1.0, the lowest valid epoch ID is stacks 2.0. | ||
| /// The instantiation of subsequent epochs may bump up the epoch version in the clarity DB if | ||
| /// Clarity is updated in that epoch. |
There was a problem hiding this comment.
nit: this doc string belongs to get_clarity_epoch_version and not to parse_epoch
stackslib/src/clarity_vm/clarity.rs
Outdated
There was a problem hiding this comment.
This could benefit from using ClarityDatabase::read_epoch_from_store, as is done in other call sites such as read_only_connection_checked and eval_read_only
There was a problem hiding this comment.
crc: a2593d2
This also made burn_state_db arg unused and could be removed also from the call chain
| /// `get_clarity_epoch_version()` call and updated by | ||
| /// `set_clarity_epoch_version()`. The epoch never changes | ||
| /// mid-block except through `set_clarity_epoch_version()` | ||
| cached_epoch: Option<StacksEpochId>, |
There was a problem hiding this comment.
nit: improve docstring for methods involving cached_epoch (general comment)
| ClarityDatabase::new(self, headers_db, burn_state_db, None) | ||
| } | ||
|
|
||
| fn as_clarity_db_with_epoch<'b>( |
There was a problem hiding this comment.
nit: missing docstring
| store: &'a mut dyn ClarityBackingStore, | ||
| headers_db: &'a dyn HeadersDB, | ||
| burn_state_db: &'a dyn BurnStateDB, | ||
| cached_epoch: Option<StacksEpochId>, |
There was a problem hiding this comment.
improve test coverage for cache_epoch being set during construction
Coverage Report for CI Build 24140301216Coverage decreased (-38.9%) to 46.817%Details
Uncovered Changes
Coverage Regressions85999 previously-covered lines in 334 files lost coverage.
Coverage Stats
💛 - Coveralls |
federico-stacks
left a comment
There was a problem hiding this comment.
Actually moving the PR back to draft due this finding
| let mut clarity_db = datastore.as_clarity_db_with_epoch( | ||
| &NULL_HEADER_DB, | ||
| &NULL_BURN_STATE_DB, | ||
| epoch.epoch_id, | ||
| ); |
There was a problem hiding this comment.
the change from commit 6fd5f32, breaks some unit tests from chainstate::stacks::db::blocks::test (like process_transaction_fee_check)
I need to investigate this further.
Cache
get_clarity_epoch_version()in a field onClarityDatabaseto eliminate redundant KV store lookups (2-3 times permap-set,map-get?,map-insert,map-delete,var-set, and NFT operation (foradmits()type checks).set_clarity_epoch_version(), which updates the cacheroll_back()clears the cache defensively, so a rolled-backset_clarity_epoch_version()cannot leave a stale valueat-blockalso invalidates the store so it is reset thereClarityDatabaseinstances are short-lived (created/destroyed per closure inwith_clarity_db,as_transaction, etc.)Benchmark Results (
cargo bench --bench epoch_cache -p clarity)