bump executor cache max entries (#25600)

* executor-cache: unify `remove` calls

* executor-cache: metrics - add one-hit-wonder counter

* executor-cache: bump max entries to 256
This commit is contained in:
Trent Nelson 2022-05-27 09:54:10 -06:00 committed by GitHub
parent e4409a87fe
commit 4e6b276f6c
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
1 changed files with 55 additions and 8 deletions

View File

@ -279,6 +279,7 @@ mod executor_cache {
pub evictions: HashMap<Pubkey, u64>,
pub insertions: AtomicU64,
pub replacements: AtomicU64,
pub one_hit_wonders: AtomicU64,
}
impl Stats {
@ -287,6 +288,7 @@ mod executor_cache {
let misses = self.misses.load(Relaxed);
let insertions = self.insertions.load(Relaxed);
let replacements = self.replacements.load(Relaxed);
let one_hit_wonders = self.one_hit_wonders.load(Relaxed);
let evictions: u64 = self.evictions.values().sum();
datapoint_info!(
"bank-executor-cache-stats",
@ -296,10 +298,11 @@ mod executor_cache {
("evictions", evictions, i64),
("insertions", insertions, i64),
("replacements", replacements, i64),
("one_hit_wonders", one_hit_wonders, i64),
);
debug!(
"Executor Cache Stats -- Hits: {}, Misses: {}, Evictions: {}, Insertions: {}, Replacements: {}",
hits, misses, evictions, insertions, replacements,
"Executor Cache Stats -- Hits: {}, Misses: {}, Evictions: {}, Insertions: {}, Replacements: {}, One-Hit-Wonders: {}",
hits, misses, evictions, insertions, replacements, one_hit_wonders,
);
if log_enabled!(log::Level::Trace) && !self.evictions.is_empty() {
let mut evictions = self.evictions.iter().collect::<Vec<_>>();
@ -323,12 +326,13 @@ mod executor_cache {
}
}
const MAX_CACHED_EXECUTORS: usize = 100; // 10 MB assuming programs are around 100k
const MAX_CACHED_EXECUTORS: usize = 256;
#[derive(Debug)]
struct CachedExecutorsEntry {
prev_epoch_count: u64,
epoch_count: AtomicU64,
executor: Arc<dyn Executor>,
hit_count: AtomicU64,
}
/// LFU Cache of executors with single-epoch memory of usage counts
#[derive(Debug)]
@ -366,6 +370,7 @@ impl Clone for CachedExecutors {
prev_epoch_count: entry.prev_epoch_count,
epoch_count: AtomicU64::new(entry.epoch_count.load(Relaxed)),
executor: entry.executor.clone(),
hit_count: AtomicU64::new(entry.hit_count.load(Relaxed)),
};
(key, entry)
});
@ -390,6 +395,7 @@ impl CachedExecutors {
prev_epoch_count: entry.epoch_count.load(Relaxed),
epoch_count: AtomicU64::default(),
executor: entry.executor.clone(),
hit_count: AtomicU64::new(entry.hit_count.load(Relaxed)),
};
(key, entry)
});
@ -414,6 +420,7 @@ impl CachedExecutors {
if let Some(entry) = self.executors.get(pubkey) {
self.stats.hits.fetch_add(1, Relaxed);
entry.epoch_count.fetch_add(1, Relaxed);
entry.hit_count.fetch_add(1, Relaxed);
Some(entry.executor.clone())
} else {
self.stats.misses.fetch_add(1, Relaxed);
@ -425,7 +432,7 @@ impl CachedExecutors {
let mut new_executors: Vec<_> = executors
.iter()
.filter_map(|(key, executor)| {
if let Some(mut entry) = self.executors.remove(key) {
if let Some(mut entry) = self.remove(key) {
self.stats.replacements.fetch_add(1, Relaxed);
entry.executor = executor.clone();
let _ = self.executors.insert(**key, entry);
@ -457,7 +464,7 @@ impl CachedExecutors {
.map(|least| *least.0)
.collect::<Vec<_>>();
for least_key in least_keys.drain(..) {
let _ = self.executors.remove(&least_key);
let _ = self.remove(&least_key);
self.stats
.evictions
.entry(least_key)
@ -471,14 +478,21 @@ impl CachedExecutors {
prev_epoch_count: 0,
epoch_count: AtomicU64::new(primer_count),
executor: executor.clone(),
hit_count: AtomicU64::new(1),
};
let _ = self.executors.insert(*key, entry);
}
}
}
fn remove(&mut self, pubkey: &Pubkey) {
let _ = self.executors.remove(pubkey);
fn remove(&mut self, pubkey: &Pubkey) -> Option<CachedExecutorsEntry> {
let maybe_entry = self.executors.remove(pubkey);
if let Some(entry) = maybe_entry.as_ref() {
if entry.hit_count.load(Relaxed) == 1 {
self.stats.one_hit_wonders.fetch_add(1, Relaxed);
}
}
maybe_entry
}
fn clear(&mut self) {
@ -4181,7 +4195,7 @@ impl Bank {
/// Remove an executor from the bank's cache
fn remove_executor(&self, pubkey: &Pubkey) {
let mut cache = self.cached_executors.write().unwrap();
Arc::make_mut(&mut cache).remove(pubkey);
let _ = Arc::make_mut(&mut cache).remove(pubkey);
}
pub fn clear_executors(&self) {
@ -14509,6 +14523,39 @@ pub(crate) mod tests {
assert!(cache.get(&entries[1].0).is_some());
}
#[test]
fn test_cached_executors_one_hit_wonder_counter() {
let mut cache = CachedExecutors::new(1, 0);
let one_hit_wonder = Pubkey::new_unique();
let popular = Pubkey::new_unique();
let executor: Arc<dyn Executor> = Arc::new(TestExecutor {});
// make sure we're starting from where we think we are
assert_eq!(cache.stats.one_hit_wonders.load(Relaxed), 0);
// add our one-hit-wonder
cache.put(&[(&one_hit_wonder, executor.clone())]);
assert_eq!(cache.executors[&one_hit_wonder].hit_count.load(Relaxed), 1);
// displace the one-hit-wonder with "popular program"
cache.put(&[(&popular, executor.clone())]);
assert_eq!(cache.executors[&popular].hit_count.load(Relaxed), 1);
// one-hit-wonder counter incremented
assert_eq!(cache.stats.one_hit_wonders.load(Relaxed), 1);
// make "popular program" popular
cache.get(&popular).unwrap();
assert_eq!(cache.executors[&popular].hit_count.load(Relaxed), 2);
// evict "popular program"
cache.put(&[(&one_hit_wonder, executor.clone())]);
assert_eq!(cache.executors[&one_hit_wonder].hit_count.load(Relaxed), 1);
// one-hit-wonder counter not incremented
assert_eq!(cache.stats.one_hit_wonders.load(Relaxed), 1);
}
#[test]
fn test_bank_executor_cache() {
solana_logger::setup();