From dc98510d6d632b83e9477674a9c4675b46c80ffd Mon Sep 17 00:00:00 2001 From: "Jeff Washington (jwash)" Date: Tue, 19 Apr 2022 08:29:09 -0500 Subject: [PATCH] accounts hash calls maybe_rehash_skipped_rewrite (#24316) --- runtime/src/accounts_db.rs | 52 ++++++++++++++++++++++++- runtime/src/accounts_hash.rs | 16 +++++++- runtime/src/expected_rent_collection.rs | 14 +++++-- 3 files changed, 76 insertions(+), 6 deletions(-) diff --git a/runtime/src/accounts_db.rs b/runtime/src/accounts_db.rs index cb70491578..381c35d48c 100644 --- a/runtime/src/accounts_db.rs +++ b/runtime/src/accounts_db.rs @@ -40,6 +40,7 @@ use { append_vec::{AppendVec, StoredAccountMeta, StoredMeta, StoredMetaWriteVersion}, cache_hash_data::CacheHashData, contains::Contains, + expected_rent_collection::ExpectedRentCollection, pubkey_bins::PubkeyBinCalculator24, read_only_accounts_cache::ReadOnlyAccountsCache, rent_collector::RentCollector, @@ -5137,6 +5138,11 @@ impl AccountsDb { ); } + /// find slot >= 'slot' which is a root or in 'ancestors' + pub fn find_unskipped_slot(&self, slot: Slot, ancestors: Option<&Ancestors>) -> Option { + self.accounts_index.get_next_original_root(slot, ancestors) + } + pub fn checked_iterative_sum_for_capitalization(total_cap: u64, new_cap: u64) -> u64 { let new_total = total_cap as u128 + new_cap as u128; AccountsHash::checked_cast_for_capitalization(new_total) @@ -5171,6 +5177,8 @@ impl AccountsDb { // We'll also accumulate the lamports within each chunk and fewer chunks results in less contention to accumulate the sum. let chunks = crate::accounts_hash::MERKLE_FANOUT.pow(4); let total_lamports = Mutex::::new(0); + let stats = HashStats::default(); + let get_hashes = || { keys.par_chunks(chunks) .map(|pubkeys| { @@ -5203,7 +5211,22 @@ impl AccountsDb { .get_loaded_account() .and_then( |loaded_account| { + let find_unskipped_slot = |slot: Slot| { + self.find_unskipped_slot(slot, config.ancestors) + }; let loaded_hash = loaded_account.loaded_hash(); + let new_hash = ExpectedRentCollection::maybe_rehash_skipped_rewrite( + &loaded_account, + &loaded_hash, + pubkey, + *slot, + config.rent_collector, + &stats, + max_slot + 1, // this wants an 'exclusive' number + find_unskipped_slot, + self.filler_account_suffix.as_ref(), + ); + let loaded_hash = new_hash.unwrap_or(loaded_hash); let balance = loaded_account.lamports(); if config.check_hash && !self.is_filler_account(pubkey) { // this will not be supported anymore let computed_hash = @@ -5260,6 +5283,16 @@ impl AccountsDb { ("hash", hash_time.as_us(), i64), ("hash_total", hash_total, i64), ("collect", collect.as_us(), i64), + ( + "rehashed_rewrites", + stats.rehash_required.load(Ordering::Relaxed), + i64 + ), + ( + "rehashed_rewrites_unnecessary", + stats.rehash_unnecessary.load(Ordering::Relaxed), + i64 + ), ); Ok((accumulated_hash, total_lamports)) } @@ -5663,6 +5696,8 @@ impl AccountsDb { let range = bin_range.end - bin_range.start; let sort_time = AtomicU64::new(0); + let find_unskipped_slot = |slot: Slot| self.find_unskipped_slot(slot, config.ancestors); + let result: Vec = self.scan_account_storage_no_bank( cache_hash_data, config, @@ -5685,8 +5720,21 @@ impl AccountsDb { raw_lamports }; - let source_item = - CalculateHashIntermediate::new(loaded_account.loaded_hash(), balance, *pubkey); + let loaded_hash = loaded_account.loaded_hash(); + let new_hash = ExpectedRentCollection::maybe_rehash_skipped_rewrite( + &loaded_account, + &loaded_hash, + pubkey, + slot, + config.rent_collector, + stats, + storage.range().end, + find_unskipped_slot, + filler_account_suffix, + ); + let loaded_hash = new_hash.unwrap_or(loaded_hash); + + let source_item = CalculateHashIntermediate::new(loaded_hash, balance, *pubkey); if config.check_hash && !Self::is_filler_account_helper(pubkey, filler_account_suffix) diff --git a/runtime/src/accounts_hash.rs b/runtime/src/accounts_hash.rs index 8c72845e41..c247b6c4f0 100644 --- a/runtime/src/accounts_hash.rs +++ b/runtime/src/accounts_hash.rs @@ -11,7 +11,7 @@ use { borrow::Borrow, convert::TryInto, sync::{ - atomic::{AtomicUsize, Ordering}, + atomic::{AtomicU64, AtomicUsize, Ordering}, Mutex, }, }, @@ -70,6 +70,10 @@ pub struct HashStats { pub min_bin_size: usize, pub max_bin_size: usize, pub storage_size_quartiles: StorageSizeQuartileStats, + /// time spent hashing during rehash calls + pub rehash_hash_us: AtomicU64, + /// time spent determining whether to rehash during rehash calls + pub rehash_calc_us: AtomicU64, /// # rehashes that took place and were necessary pub rehash_required: AtomicUsize, /// # rehashes that took place and were UNnecessary @@ -173,6 +177,16 @@ impl HashStats { self.rehash_required.load(Ordering::Relaxed) as i64, i64 ), + ( + "rehash_hash_us", + self.rehash_hash_us.load(Ordering::Relaxed) as i64, + i64 + ), + ( + "rehash_calc_us", + self.rehash_calc_us.load(Ordering::Relaxed) as i64, + i64 + ), ( "rehashed_rewrites_unnecessary", self.rehash_unnecessary.load(Ordering::Relaxed) as i64, diff --git a/runtime/src/expected_rent_collection.rs b/runtime/src/expected_rent_collection.rs index 506c1da5a7..ff6d1cc4a5 100644 --- a/runtime/src/expected_rent_collection.rs +++ b/runtime/src/expected_rent_collection.rs @@ -396,7 +396,9 @@ impl ExpectedRentCollection { find_unskipped_slot: impl Fn(Slot) -> Option, filler_account_suffix: Option<&Pubkey>, ) -> Option { - let expected = match ExpectedRentCollection::new( + use solana_measure::measure::Measure; + let mut m = Measure::start("rehash_calc_us"); + let expected = ExpectedRentCollection::new( pubkey, loaded_account, storage_slot, @@ -404,20 +406,26 @@ impl ExpectedRentCollection { max_slot_in_storages_exclusive, find_unskipped_slot, filler_account_suffix, - ) { + ); + + m.stop(); + stats.rehash_calc_us.fetch_add(m.as_us(), Ordering::Relaxed); + let expected = match expected { None => { // use the previously calculated hash return None; } Some(expected) => expected, }; - + let mut m = Measure::start("rehash_hash_us"); let recalc_hash = AccountsDb::hash_account_with_rent_epoch( expected.expected_rent_collection_slot_max_epoch, loaded_account, pubkey, expected.rent_epoch, ); + m.stop(); + stats.rehash_hash_us.fetch_add(m.as_us(), Ordering::Relaxed); if &recalc_hash == loaded_hash { // unnecessary calculation occurred stats.rehash_unnecessary.fetch_add(1, Ordering::Relaxed);