diff --git a/runtime/src/accounts_index.rs b/runtime/src/accounts_index.rs index fa000bdcd..d4655f31b 100644 --- a/runtime/src/accounts_index.rs +++ b/runtime/src/accounts_index.rs @@ -734,7 +734,7 @@ impl AccountsIndex { let storage = AccountsIndexStorage::new(); let account_maps = (0..bins) .into_iter() - .map(|_bin| RwLock::new(AccountMap::new(&storage))) + .map(|bin| RwLock::new(AccountMap::new(&storage, bin))) .collect::>(); (account_maps, bin_calculator, storage) } diff --git a/runtime/src/bucket_map_holder_stats.rs b/runtime/src/bucket_map_holder_stats.rs index af118e101..2eb7b6187 100644 --- a/runtime/src/bucket_map_holder_stats.rs +++ b/runtime/src/bucket_map_holder_stats.rs @@ -16,12 +16,55 @@ pub struct BucketMapHolderStats { pub keys: AtomicU64, pub deletes: AtomicU64, pub inserts: AtomicU64, + pub count_in_mem: AtomicU64, + pub per_bucket_count: Vec, } impl BucketMapHolderStats { + pub fn new(bins: usize) -> BucketMapHolderStats { + BucketMapHolderStats { + per_bucket_count: (0..bins) + .into_iter() + .map(|_| AtomicU64::default()) + .collect(), + ..BucketMapHolderStats::default() + } + } + + pub fn insert_or_delete(&self, insert: bool, bin: usize) { + let per_bucket = self.per_bucket_count.get(bin); + if insert { + self.inserts.fetch_add(1, Ordering::Relaxed); + self.count_in_mem.fetch_add(1, Ordering::Relaxed); + per_bucket.map(|count| count.fetch_add(1, Ordering::Relaxed)); + } else { + self.deletes.fetch_add(1, Ordering::Relaxed); + self.count_in_mem.fetch_sub(1, Ordering::Relaxed); + per_bucket.map(|count| count.fetch_sub(1, Ordering::Relaxed)); + } + } + pub fn report_stats(&self) { + let mut ct = 0; + let mut min = usize::MAX; + let mut max = 0; + for d in &self.per_bucket_count { + let d = d.load(Ordering::Relaxed) as usize; + ct += d; + min = std::cmp::min(min, d); + max = std::cmp::max(max, d); + } + datapoint_info!( "accounts_index", + ( + "count_in_mem", + self.count_in_mem.load(Ordering::Relaxed), + i64 + ), + ("min_in_bin", min, i64), + ("max_in_bin", max, i64), + ("count_from_bins", ct, i64), ( "gets_from_mem", self.gets_from_mem.swap(0, Ordering::Relaxed), diff --git a/runtime/src/in_mem_accounts_index.rs b/runtime/src/in_mem_accounts_index.rs index d5237910e..06dfdf776 100644 --- a/runtime/src/in_mem_accounts_index.rs +++ b/runtime/src/in_mem_accounts_index.rs @@ -23,13 +23,15 @@ pub struct InMemAccountsIndex { // backing store map: HashMap>, storage: Arc, + bin: usize, } impl InMemAccountsIndex { - pub fn new(storage: &AccountsIndexStorage) -> Self { + pub fn new(storage: &AccountsIndexStorage, bin: usize) -> Self { Self { map: HashMap::new(), storage: storage.storage().clone(), + bin, } } @@ -90,7 +92,7 @@ impl InMemAccountsIndex { if let Entry::Occupied(index_entry) = self.entry(pubkey) { if index_entry.get().slot_list.read().unwrap().is_empty() { index_entry.remove(); - self.storage.stats.deletes.fetch_add(1, Ordering::Relaxed); + self.stats().insert_or_delete(false, self.bin); return true; } } @@ -113,11 +115,11 @@ impl InMemAccountsIndex { reclaims, previous_slot_entry_was_cached, ); - Self::update_stat(&self.storage.stats.updates_in_mem, 1); + Self::update_stat(&self.stats().updates_in_mem, 1); } Entry::Vacant(vacant) => { vacant.insert(new_value); - Self::update_stat(&self.storage.stats.inserts, 1); + self.stats().insert_or_delete(true, self.bin); } } } @@ -231,14 +233,11 @@ impl InMemAccountsIndex { } }; let stats = self.stats(); - Self::update_stat( - if result.is_none() { - &stats.inserts - } else { - &stats.updates_in_mem - }, - 1, - ); + if result.is_none() { + stats.insert_or_delete(true, self.bin); + } else { + Self::update_stat(&stats.updates_in_mem, 1); + } result }