use std::collections::HashMap;
use std::sync::Mutex;
use std::time::{Duration, Instant};
static STATS: Mutex<Option<HashMap<&'static str, (u64, u128)>>> = Mutex::new(None);
pub fn enabled() -> bool {
rlx_ir::env::flag("RLX_METAL_ENCODE_PROFILE")
}
pub fn reset() {
if enabled() {
*STATS.lock().unwrap() = Some(HashMap::new());
}
}
fn record(name: &'static str, dt: Duration) {
let mut guard = STATS.lock().unwrap();
let map = guard.get_or_insert_with(HashMap::new);
let e = map.entry(name).or_insert((0, 0));
e.0 += 1;
e.1 += dt.as_nanos();
}
pub struct EncodeTimer {
name: &'static str,
t0: Instant,
}
impl EncodeTimer {
#[inline]
pub fn new(name: &'static str) -> Option<Self> {
if enabled() {
Some(Self {
name,
t0: Instant::now(),
})
} else {
None
}
}
}
impl Drop for EncodeTimer {
fn drop(&mut self) {
record(self.name, self.t0.elapsed());
}
}
pub fn print_summary() {
if !enabled() {
return;
}
let guard = STATS.lock().unwrap();
let Some(map) = guard.as_ref() else {
return;
};
if map.is_empty() {
return;
}
let total_ns: u128 = map.values().map(|(_, ns)| *ns).sum();
let mut rows: Vec<_> = map
.iter()
.map(|(name, (count, ns))| (*name, *count, *ns as f64 / 1e6))
.collect();
rows.sort_by(|a, b| b.2.partial_cmp(&a.2).unwrap_or(std::cmp::Ordering::Equal));
eprintln!(
"[rlx-metal] ENCODE profile (CPU encode time, {:.2} ms total):",
total_ns as f64 / 1e6
);
eprintln!("{:<32} {:>6} {:>10} {:>7}", "thunk", "count", "ms", "pct");
eprintln!("{}", "-".repeat(60));
for (name, count, ms) in &rows {
let pct = if total_ns > 0 {
100.0 * (ms * 1e6) / total_ns as f64
} else {
0.0
};
eprintln!("{name:<32} {count:>6} {ms:>10.2} {pct:>6.1}%");
}
}