use crate::OffsetSurfaceLane;
use std::cell::RefCell;
use std::collections::BTreeMap;
use web_time::{Duration, Instant};
pub(super) const CARRIER_REGULARITY: &str = "carrier_regularity";
pub(super) const CARRIER_AFFINE: &str = "carrier_affine";
pub(super) const CARRIER_ANALYTIC: &str = "carrier_analytic";
pub(super) const CARRIER_FIT: &str = "carrier_fit";
pub(super) const CARRIER_TRIM: &str = "carrier_trim";
pub(super) const APEX_CAPS: &str = "apex_caps";
pub(super) const WALLS: &str = "walls";
pub(super) const EXTENSION: &str = "extension";
pub(super) const IMPRINT: &str = "imprint";
pub(super) const FRAGMENT: &str = "fragment";
pub(super) const SELECT: &str = "select";
pub(super) const ASSEMBLY: &str = "assembly";
pub(super) const ACCEPTANCE: &str = "acceptance";
pub(super) const TOTAL: &str = "total";
#[derive(Clone, Debug, Default)]
pub(super) struct ShellTimings {
pub attempts: u64,
pub carriers: BTreeMap<&'static str, u64>,
pub ms: BTreeMap<&'static str, f64>,
}
thread_local! {
static TIMINGS: RefCell<ShellTimings> = RefCell::new(ShellTimings::default());
}
pub(super) fn reset() {
TIMINGS.with(|timings| *timings.borrow_mut() = ShellTimings::default());
}
pub(super) fn attempt() {
TIMINGS.with(|timings| timings.borrow_mut().attempts += 1);
}
pub(super) fn add(phase: &'static str, elapsed: Duration) {
TIMINGS.with(|timings| {
*timings.borrow_mut().ms.entry(phase).or_default() += elapsed.as_secs_f64() * 1_000.0;
});
}
pub(super) fn lap(started: &mut Instant, phase: &'static str) {
let now = Instant::now();
add(phase, now - *started);
*started = now;
}
pub(super) fn carrier_phase(lane: OffsetSurfaceLane) -> &'static str {
match lane {
OffsetSurfaceLane::Affine => CARRIER_AFFINE,
OffsetSurfaceLane::Analytic => CARRIER_ANALYTIC,
OffsetSurfaceLane::Fit | OffsetSurfaceLane::Reparameterised => CARRIER_FIT,
}
}
pub(super) fn carrier_built(lane: OffsetSurfaceLane, elapsed: Duration) {
let phase = carrier_phase(lane);
TIMINGS.with(|timings| *timings.borrow_mut().carriers.entry(phase).or_default() += 1);
add(phase, elapsed);
}
pub(super) fn snapshot() -> ShellTimings {
TIMINGS.with(|timings| timings.borrow().clone())
}
pub(super) fn report(entry: &str) {
if std::env::var("BREP_PROFILE").is_err() {
return;
}
let timings = snapshot();
let phases = timings
.ms
.iter()
.map(|(phase, ms)| format!("{phase}={ms:.2}"))
.collect::<Vec<_>>()
.join(" ");
let carriers = timings
.carriers
.iter()
.map(|(phase, count)| format!("{}={count}", phase.trim_start_matches("carrier_")))
.collect::<Vec<_>>()
.join(",");
eprintln!(
"{entry}.profile attempts={} carriers[{carriers}] {phases}",
timings.attempts
);
}