fleischwolf_pdf/
timing.rs1use std::collections::BTreeMap;
9use std::sync::{Mutex, OnceLock};
10use std::time::Instant;
11
12fn enabled() -> bool {
13 static ON: OnceLock<bool> = OnceLock::new();
14 *ON.get_or_init(|| std::env::var("FLEISCHWOLF_TIMING").is_ok())
15}
16
17fn store() -> &'static Mutex<BTreeMap<&'static str, (u128, u64)>> {
18 static S: OnceLock<Mutex<BTreeMap<&'static str, (u128, u64)>>> = OnceLock::new();
19 S.get_or_init(|| Mutex::new(BTreeMap::new()))
20}
21
22pub fn record(stage: &'static str, nanos: u128) {
24 if !enabled() {
25 return;
26 }
27 let mut g = store().lock().unwrap();
28 let e = g.entry(stage).or_insert((0, 0));
29 e.0 += nanos;
30 e.1 += 1;
31}
32
33pub fn timed<T>(stage: &'static str, f: impl FnOnce() -> T) -> T {
35 if !enabled() {
36 return f();
37 }
38 let t = Instant::now();
39 let out = f();
40 record(stage, t.elapsed().as_nanos());
41 out
42}
43
44pub fn report() {
47 if !enabled() {
48 return;
49 }
50 let g = store().lock().unwrap();
51 let mut rows: Vec<_> = g.iter().map(|(k, v)| (*k, v.0, v.1)).collect();
52 rows.sort_by_key(|r| std::cmp::Reverse(r.1));
53 let total: u128 = rows.iter().map(|r| r.1).sum();
54 eprintln!("=== FLEISCHWOLF timing (per stage, wall-clock) ===");
55 for (stage, nanos, calls) in &rows {
56 let ms = *nanos as f64 / 1e6;
57 let pct = if total > 0 {
58 *nanos as f64 / total as f64 * 100.0
59 } else {
60 0.0
61 };
62 eprintln!(" {stage:<22} {ms:>9.1} ms {pct:>5.1}% ({calls} calls)");
63 }
64 eprintln!(" {:<22} {:>9.1} ms", "TOTAL (summed)", total as f64 / 1e6);
65}