use std::time::Instant;
pub fn enabled() -> bool {
static ENABLED: std::sync::OnceLock<bool> = std::sync::OnceLock::new();
*ENABLED
.get_or_init(|| std::env::var("FRESH_TEST_TIMING").is_ok_and(|v| !v.is_empty() && v != "0"))
}
pub struct Timer {
label: String,
start: Instant,
last: Instant,
indent: &'static str,
}
impl Timer {
pub fn start(label: impl Into<String>) -> Self {
let label = label.into();
let now = Instant::now();
if enabled() {
eprintln!("[timing] {label} start");
}
Self {
label,
start: now,
last: now,
indent: " ",
}
}
pub fn phase(&mut self, name: &str) {
if !enabled() {
return;
}
let now = Instant::now();
let delta = now.duration_since(self.last);
let cumul = now.duration_since(self.start);
eprintln!(
"[timing] {indent}{name:<24} +{delta:>8.1}ms (cumul {cumul:.1}ms)",
indent = self.indent,
name = name,
delta = delta.as_secs_f64() * 1000.0,
cumul = cumul.as_secs_f64() * 1000.0,
);
self.last = now;
}
pub fn finish(self) {
if !enabled() {
return;
}
let total = self.start.elapsed();
eprintln!(
"[timing] {label} total {total:.1}ms",
label = self.label,
total = total.as_secs_f64() * 1000.0,
);
}
}
pub fn time_phase<R>(timer: &mut Timer, name: &str, f: impl FnOnce() -> R) -> R {
let r = f();
timer.phase(name);
r
}