use std::time::Duration;
#[derive(Debug, Default, Clone)]
pub struct Stats {
pub steps: u64,
pub lifts: u64,
pub resolves: u64,
pub native_bodies: u64,
pub absorbed: u64,
pub fetch_bytes: u64,
pub fetch: Duration,
pub decode_lift: Duration,
pub optimize: Duration,
pub forwarded_loads: u64,
pub removed_stores: u64,
}
impl Stats {
pub fn translation(&self) -> Duration {
self.fetch + self.decode_lift + self.optimize
}
pub fn execute(&self, elapsed: Duration) -> Duration {
elapsed.saturating_sub(self.translation())
}
pub fn hit_rate(&self) -> Option<f64> {
let total = self.lifts + self.resolves;
(total > 0).then(|| self.resolves as f64 / total as f64)
}
pub fn report(&self, elapsed: Duration) -> String {
let percent = |part: Duration| {
if elapsed.is_zero() {
0.0
} else {
part.as_secs_f64() / elapsed.as_secs_f64() * 100.0
}
};
format!(
"steps={} lifts={} (translated) resolves={} (re-entered) lookup_hit_rate={} | \
fetch={:?} ({:.1}%) decode+lift={:?} ({:.1}%) optimize={:?} ({:.1}%) \
execute={:?} ({:.1}%)",
self.steps,
self.lifts,
self.resolves,
self.hit_rate()
.map_or_else(|| "n/a".to_owned(), |rate| format!("{:.1}%", rate * 100.0)),
self.fetch,
percent(self.fetch),
self.decode_lift,
percent(self.decode_lift),
self.optimize,
percent(self.optimize),
self.execute(elapsed),
percent(self.execute(elapsed)),
)
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn execute_time_is_what_translation_did_not_take() {
let stats = Stats {
fetch: Duration::from_millis(10),
decode_lift: Duration::from_millis(30),
optimize: Duration::from_millis(10),
..Stats::default()
};
assert_eq!(stats.translation(), Duration::from_millis(50));
assert_eq!(
stats.execute(Duration::from_millis(200)),
Duration::from_millis(150)
);
}
#[test]
fn execute_time_never_goes_negative() {
let stats = Stats {
decode_lift: Duration::from_millis(100),
..Stats::default()
};
assert_eq!(stats.execute(Duration::from_millis(10)), Duration::ZERO);
}
#[test]
fn hit_rate_needs_transitions_to_rate() {
assert_eq!(Stats::default().hit_rate(), None);
let stats = Stats {
lifts: 1,
resolves: 3,
..Stats::default()
};
assert_eq!(stats.hit_rate(), Some(0.75));
}
}