Add stats for LoadedPrograms (#31577)
This commit is contained in:
parent
e1b57b8a37
commit
04425b81ce
|
@ -3,6 +3,7 @@ use solana_rbpf::error::EbpfError;
|
||||||
use {
|
use {
|
||||||
crate::{invoke_context::InvokeContext, timings::ExecuteDetailsTimings},
|
crate::{invoke_context::InvokeContext, timings::ExecuteDetailsTimings},
|
||||||
itertools::Itertools,
|
itertools::Itertools,
|
||||||
|
log::{debug, log_enabled, trace},
|
||||||
percentage::PercentageInteger,
|
percentage::PercentageInteger,
|
||||||
solana_measure::measure::Measure,
|
solana_measure::measure::Measure,
|
||||||
solana_rbpf::{
|
solana_rbpf::{
|
||||||
|
@ -111,6 +112,60 @@ pub struct LoadedProgram {
|
||||||
pub usage_counter: AtomicU64,
|
pub usage_counter: AtomicU64,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Default)]
|
||||||
|
pub struct Stats {
|
||||||
|
pub hits: AtomicU64,
|
||||||
|
pub misses: AtomicU64,
|
||||||
|
pub evictions: HashMap<Pubkey, u64>,
|
||||||
|
pub insertions: AtomicU64,
|
||||||
|
pub replacements: AtomicU64,
|
||||||
|
pub one_hit_wonders: AtomicU64,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Stats {
|
||||||
|
/// Logs the measurement values
|
||||||
|
pub fn submit(&self, slot: Slot) {
|
||||||
|
let hits = self.hits.load(Ordering::Relaxed);
|
||||||
|
let misses = self.misses.load(Ordering::Relaxed);
|
||||||
|
let insertions = self.insertions.load(Ordering::Relaxed);
|
||||||
|
let replacements = self.replacements.load(Ordering::Relaxed);
|
||||||
|
let one_hit_wonders = self.one_hit_wonders.load(Ordering::Relaxed);
|
||||||
|
let evictions: u64 = self.evictions.values().sum();
|
||||||
|
datapoint_info!(
|
||||||
|
"bank-executor-cache-stats",
|
||||||
|
("slot", slot, i64),
|
||||||
|
("hits", hits, i64),
|
||||||
|
("misses", misses, i64),
|
||||||
|
("evictions", evictions, i64),
|
||||||
|
("insertions", insertions, i64),
|
||||||
|
("replacements", replacements, i64),
|
||||||
|
("one_hit_wonders", one_hit_wonders, i64),
|
||||||
|
);
|
||||||
|
debug!(
|
||||||
|
"Loaded Programs 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<_>>();
|
||||||
|
evictions.sort_by_key(|e| e.1);
|
||||||
|
let evictions = evictions
|
||||||
|
.into_iter()
|
||||||
|
.rev()
|
||||||
|
.map(|(program_id, evictions)| {
|
||||||
|
format!(" {:<44} {}", program_id.to_string(), evictions)
|
||||||
|
})
|
||||||
|
.collect::<Vec<_>>();
|
||||||
|
let evictions = evictions.join("\n");
|
||||||
|
trace!(
|
||||||
|
"Eviction Details:\n {:<44} {}\n{}",
|
||||||
|
"Program",
|
||||||
|
"Count",
|
||||||
|
evictions
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Debug, Default)]
|
#[derive(Debug, Default)]
|
||||||
pub struct LoadProgramMetrics {
|
pub struct LoadProgramMetrics {
|
||||||
pub program_id: String,
|
pub program_id: String,
|
||||||
|
@ -281,6 +336,7 @@ pub struct LoadedPrograms {
|
||||||
entries: HashMap<Pubkey, Vec<Arc<LoadedProgram>>>,
|
entries: HashMap<Pubkey, Vec<Arc<LoadedProgram>>>,
|
||||||
|
|
||||||
latest_root: Slot,
|
latest_root: Slot,
|
||||||
|
pub stats: Stats,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Default)]
|
#[derive(Debug, Default)]
|
||||||
|
@ -381,10 +437,12 @@ impl LoadedPrograms {
|
||||||
// a chance.
|
// a chance.
|
||||||
second_level.swap_remove(entry_index);
|
second_level.swap_remove(entry_index);
|
||||||
} else {
|
} else {
|
||||||
|
self.stats.replacements.fetch_add(1, Ordering::Relaxed);
|
||||||
return (true, existing.clone());
|
return (true, existing.clone());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
self.stats.insertions.fetch_add(1, Ordering::Relaxed);
|
||||||
second_level.insert(index.unwrap_or(second_level.len()), entry.clone());
|
second_level.insert(index.unwrap_or(second_level.len()), entry.clone());
|
||||||
(false, entry)
|
(false, entry)
|
||||||
}
|
}
|
||||||
|
@ -506,7 +564,14 @@ impl LoadedPrograms {
|
||||||
missing.push(key);
|
missing.push(key);
|
||||||
None
|
None
|
||||||
})
|
})
|
||||||
.collect();
|
.collect::<HashMap<Pubkey, Arc<LoadedProgram>>>();
|
||||||
|
|
||||||
|
self.stats
|
||||||
|
.misses
|
||||||
|
.fetch_add(missing.len() as u64, Ordering::Relaxed);
|
||||||
|
self.stats
|
||||||
|
.hits
|
||||||
|
.fetch_add(found.len() as u64, Ordering::Relaxed);
|
||||||
(
|
(
|
||||||
LoadedProgramsForTxBatch {
|
LoadedProgramsForTxBatch {
|
||||||
entries: found,
|
entries: found,
|
||||||
|
@ -592,6 +657,14 @@ impl LoadedPrograms {
|
||||||
for (id, program) in remove {
|
for (id, program) in remove {
|
||||||
if let Some(entries) = self.entries.get_mut(id) {
|
if let Some(entries) = self.entries.get_mut(id) {
|
||||||
if let Some(candidate) = entries.iter_mut().find(|entry| entry == &program) {
|
if let Some(candidate) = entries.iter_mut().find(|entry| entry == &program) {
|
||||||
|
if candidate.usage_counter.load(Ordering::Relaxed) == 1 {
|
||||||
|
self.stats.one_hit_wonders.fetch_add(1, Ordering::Relaxed);
|
||||||
|
}
|
||||||
|
self.stats
|
||||||
|
.evictions
|
||||||
|
.entry(*id)
|
||||||
|
.and_modify(|c| saturating_add_assign!(*c, 1))
|
||||||
|
.or_insert(1);
|
||||||
*candidate = Arc::new(candidate.to_unloaded());
|
*candidate = Arc::new(candidate.to_unloaded());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -150,7 +150,7 @@ pub fn load_program_from_account(
|
||||||
program: &BorrowedAccount,
|
program: &BorrowedAccount,
|
||||||
programdata: &BorrowedAccount,
|
programdata: &BorrowedAccount,
|
||||||
debugging_features: bool,
|
debugging_features: bool,
|
||||||
) -> Result<(Arc<LoadedProgram>, Option<LoadProgramMetrics>), InstructionError> {
|
) -> Result<(Arc<LoadedProgram>, LoadProgramMetrics), InstructionError> {
|
||||||
if !check_loader_id(program.get_owner()) {
|
if !check_loader_id(program.get_owner()) {
|
||||||
ic_logger_msg!(
|
ic_logger_msg!(
|
||||||
log_collector,
|
log_collector,
|
||||||
|
@ -189,7 +189,7 @@ pub fn load_program_from_account(
|
||||||
debugging_features,
|
debugging_features,
|
||||||
)?);
|
)?);
|
||||||
|
|
||||||
Ok((loaded_program, Some(load_program_metrics)))
|
Ok((loaded_program, load_program_metrics))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn find_program_in_cache(
|
fn find_program_in_cache(
|
||||||
|
|
|
@ -101,7 +101,7 @@ use {
|
||||||
},
|
},
|
||||||
log_collector::LogCollector,
|
log_collector::LogCollector,
|
||||||
sysvar_cache::SysvarCache,
|
sysvar_cache::SysvarCache,
|
||||||
timings::{ExecuteTimingType, ExecuteTimings},
|
timings::{ExecuteDetailsTimings, ExecuteTimingType, ExecuteTimings},
|
||||||
},
|
},
|
||||||
solana_sdk::{
|
solana_sdk::{
|
||||||
account::{
|
account::{
|
||||||
|
@ -1627,6 +1627,13 @@ impl Bank {
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
|
||||||
|
parent
|
||||||
|
.loaded_programs_cache
|
||||||
|
.read()
|
||||||
|
.unwrap()
|
||||||
|
.stats
|
||||||
|
.submit(parent.slot());
|
||||||
|
|
||||||
new
|
new
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -4155,7 +4162,11 @@ impl Bank {
|
||||||
programdata.as_ref().unwrap_or(&program),
|
programdata.as_ref().unwrap_or(&program),
|
||||||
debugging_features,
|
debugging_features,
|
||||||
)
|
)
|
||||||
.map(|(loaded_program, _create_executor_metrics)| loaded_program)
|
.map(|(loaded_program, metrics)| {
|
||||||
|
let mut timings = ExecuteDetailsTimings::default();
|
||||||
|
metrics.submit_datapoint(&mut timings);
|
||||||
|
loaded_program
|
||||||
|
})
|
||||||
.map_err(|err| TransactionError::InstructionError(0, err))
|
.map_err(|err| TransactionError::InstructionError(0, err))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue