use std::cell::RefCell;
use std::time::Instant;
pub const FILL: usize = 0;
pub const STROKE: usize = 1;
pub const TEXT: usize = 2;
pub const SHADOW: usize = 3;
pub const IMAGE: usize = 4;
pub const CLIP: usize = 5;
pub const N: usize = 6;
const LABELS: [&str; N] = ["fill", "stroke", "text", "shadow", "image", "clip"];
thread_local! {
static NANOS: RefCell<[u64; N]> = const { RefCell::new([0; N]) };
static COUNTS: RefCell<[u32; N]> = const { RefCell::new([0; N]) };
}
pub fn enabled() -> bool {
use std::sync::OnceLock;
static E: OnceLock<bool> = OnceLock::new();
*E.get_or_init(|| std::env::var("WINDUI_PROF").is_ok_and(|v| v != "0" && !v.is_empty()))
}
pub fn start() -> Option<Instant> {
if enabled() {
Some(Instant::now())
} else {
None
}
}
pub fn end(bucket: usize, t: Option<Instant>) {
if let Some(t) = t {
let ns = t.elapsed().as_nanos() as u64;
NANOS.with(|b| b.borrow_mut()[bucket] += ns);
COUNTS.with(|c| c.borrow_mut()[bucket] += 1);
}
}
pub struct Guard(usize, Option<Instant>);
impl Drop for Guard {
fn drop(&mut self) {
end(self.0, self.1);
}
}
pub fn scope(bucket: usize) -> Guard {
Guard(bucket, start())
}
pub fn take_summary() -> String {
let (nanos, counts) = NANOS.with(|b| {
COUNTS.with(|c| {
let mut b = b.borrow_mut();
let mut c = c.borrow_mut();
let out = (*b, *c);
*b = [0; N];
*c = [0; N];
out
})
});
let mut items: Vec<(usize, u64, u32)> = (0..N)
.map(|i| (i, nanos[i], counts[i]))
.filter(|x| x.1 > 0)
.collect();
items.sort_by_key(|x| std::cmp::Reverse(x.1));
items
.iter()
.map(|(i, ns, cnt)| format!("{} {:.2}ms({})", LABELS[*i], *ns as f64 / 1e6, cnt))
.collect::<Vec<_>>()
.join(" ")
}