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:
parent
e4409a87fe
commit
4e6b276f6c
|
@ -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();
|
||||
|
|
Loading…
Reference in New Issue