use crate::*;
static PERF_COUNTERS: Lazy<AtomicRefCell<PerfCounters>> =
Lazy::new(|| AtomicRefCell::new(PerfCounters::default()));
static TIMINGS: Lazy<AtomicRefCell<Timings>> =
Lazy::new(|| AtomicRefCell::new(Timings::new()));
pub struct TimingEntry {
pub history: egui::util::History<f32>,
pub time: Instant,
}
pub struct Timings {
pub data: HashMap<&'static str, TimingEntry>,
}
impl Timings {
pub fn new() -> Self {
Self { data: HashMap::new() }
}
pub fn add_value(&mut self, name: &'static str, value: f32, time: Instant) {
let entry = self.data.entry(name).or_insert(TimingEntry {
history: egui::util::History::new(50..2000, 2.0),
time: Instant::now(),
});
entry.time = time;
entry.history.add(get_time(), value);
}
pub fn span(&mut self, name: &'static str) -> TimingGuard<'_> {
TimingGuard { timings: self, name, start: Instant::now() }
}
}
pub struct TimingGuard<'a> {
timings: &'a mut Timings,
name: &'static str,
start: Instant,
}
impl<'a> Drop for TimingGuard<'a> {
fn drop(&mut self) {
let elapsed = self.start.elapsed();
let elapsed_as_f32 = elapsed.as_secs_f32() * 1000.0; self.timings.add_value(self.name, elapsed_as_f32, self.start);
}
}
pub struct AtomicTimingGuard {
name: &'static str,
start: Instant,
}
impl Drop for AtomicTimingGuard {
fn drop(&mut self) {
let elapsed = self.start.elapsed();
let elapsed_as_f32 = elapsed.as_secs_f32();
TIMINGS.borrow_mut().add_value(self.name, elapsed_as_f32, self.start);
}
}
pub use std::ops::Deref;
pub fn timings() -> impl Deref<Target = Timings> {
TIMINGS.borrow_mut()
}
pub fn timing_start(name: &'static str) -> AtomicTimingGuard {
AtomicTimingGuard { name, start: Instant::now() }
}
pub fn timings_add_value(name: &'static str, value: f32) {
TIMINGS.borrow_mut().add_value(name, value, Instant::now());
}
#[derive(Default)]
pub struct PerfCounters {
pub counters: HashMap<Cow<'static, str>, Counter>,
}
#[derive(Default)]
pub struct Counter {
pub count: u64,
pub decayed_average: f64,
}
impl PerfCounters {
pub fn global() -> AtomicRef<'static, PerfCounters> {
PERF_COUNTERS.borrow()
}
pub fn update_counter(
&mut self,
counter_name: impl Into<Cow<'static, str>>,
count: u64,
) {
let counter = self.counters.entry(counter_name.into()).or_default();
counter.count = count;
}
pub fn new_frame(&mut self, delta: f64) {
for counter in self.counters.values_mut() {
counter.decayed_average = counter.decayed_average * (1.0 - delta) +
(counter.count as f64) * delta;
counter.count = 0;
}
}
pub fn get_counter(&self, counter_name: &str) -> (u64, f64) {
if let Some(counter) = self.counters.get(counter_name) {
(counter.count, counter.decayed_average)
} else {
(0, 0.0)
}
}
pub fn reset_counters(&mut self) {
self.counters.clear();
}
}
pub fn perf_counters_new_frame(delta: f64) {
let mut counters = PERF_COUNTERS.borrow_mut();
counters.new_frame(delta);
}
pub fn reset_perf_counters() {
let mut counters = PERF_COUNTERS.borrow_mut();
counters.reset_counters();
}
pub fn perf_counter(counter_name: impl Into<Cow<'static, str>>, count: u64) {
let mut counters = PERF_COUNTERS.borrow_mut();
counters.update_counter(counter_name, count);
}
pub fn perf_counter_inc(counter_name: impl Into<Cow<'static, str>>, inc: u64) {
let mut counters = PERF_COUNTERS.borrow_mut();
let counter_name_cow = counter_name.into();
let (current_value, _) = counters.get_counter(&counter_name_cow);
counters.update_counter(counter_name_cow, current_value + inc);
}
pub fn get_perf_counter(
counter_name: impl Into<Cow<'static, str>>,
) -> (u64, f64) {
let counters = PERF_COUNTERS.borrow_mut();
counters.get_counter(&counter_name.into())
}