use std::cell::RefCell;
use std::sync::atomic::{AtomicBool, Ordering};
use std::time::{Duration, Instant};
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
pub(crate) enum Phase {
Normalize,
RingBuild,
ToRf,
AnsatzSetup,
AtomDerivs,
ClearDenoms,
MatrixBuild,
Solve,
Rebuild,
Verify,
}
pub(crate) const N_PHASES: usize = 10;
impl Phase {
#[cfg_attr(not(test), allow(dead_code))]
pub(crate) const ALL: [Phase; N_PHASES] = [
Phase::Normalize,
Phase::RingBuild,
Phase::ToRf,
Phase::AnsatzSetup,
Phase::AtomDerivs,
Phase::ClearDenoms,
Phase::MatrixBuild,
Phase::Solve,
Phase::Rebuild,
Phase::Verify,
];
#[cfg_attr(not(test), allow(dead_code))]
pub(crate) fn label(self) -> &'static str {
match self {
Phase::Normalize => "normalize",
Phase::RingBuild => "ring_build",
Phase::ToRf => "to_rf",
Phase::AnsatzSetup => "ansatz_setup",
Phase::AtomDerivs => "atom_derivs",
Phase::ClearDenoms => "clear_denoms",
Phase::MatrixBuild => "matrix_build",
Phase::Solve => "solve",
Phase::Rebuild => "rebuild",
Phase::Verify => "verify",
}
}
}
static ENABLED: AtomicBool = AtomicBool::new(false);
thread_local! {
static TOTALS: RefCell<[Duration; N_PHASES]> =
const { RefCell::new([Duration::ZERO; N_PHASES]) };
}
#[cfg_attr(not(test), allow(dead_code))]
pub(crate) fn enable() {
ENABLED.store(true, Ordering::Relaxed);
}
#[cfg_attr(not(test), allow(dead_code))]
pub(crate) fn reset() {
TOTALS.with(|t| *t.borrow_mut() = [Duration::ZERO; N_PHASES]);
SHAPE.with(|s| *s.borrow_mut() = Shape::default());
}
#[cfg_attr(not(test), allow(dead_code))]
pub(crate) fn totals() -> [Duration; N_PHASES] {
TOTALS.with(|t| *t.borrow())
}
#[derive(Debug, Clone, Copy, Default, PartialEq, Eq)]
pub(crate) struct Shape {
pub equations: usize,
pub unknowns: usize,
pub denom_terms: usize,
pub generators: usize,
pub atoms: usize,
pub max_pow: u64,
pub depth: u32,
pub peak_cells: usize,
}
thread_local! {
static SHAPE: RefCell<Shape> = const { RefCell::new(Shape {
equations: 0,
unknowns: 0,
denom_terms: 0,
generators: 0,
atoms: 0,
max_pow: 0,
depth: 0,
peak_cells: 0,
}) };
}
#[inline]
pub(crate) fn record(update: impl FnOnce(&mut Shape)) {
if !ENABLED.load(Ordering::Relaxed) {
return;
}
SHAPE.with(|s| update(&mut s.borrow_mut()));
}
#[cfg_attr(not(test), allow(dead_code))]
pub(crate) fn shape() -> Shape {
SHAPE.with(|s| *s.borrow())
}
#[inline]
pub(crate) fn timed<T>(phase: Phase, body: impl FnOnce() -> T) -> T {
if !ENABLED.load(Ordering::Relaxed) {
return body();
}
let start = Instant::now();
let out = body();
let dt = start.elapsed();
TOTALS.with(|t| t.borrow_mut()[phase as usize] += dt);
out
}