use crate::telemetry::report::Report;
use crate::telemetry::ringbuffer::RingBuffer;
use std::sync::Mutex;
use std::sync::atomic::{AtomicBool, Ordering};
use std::time::Instant;
#[derive(Debug)]
pub struct Function {
name: &'static str,
durations: Mutex<RingBuffer>,
}
#[doc(hidden)]
pub struct MetricsRecorder {
enabled: AtomicBool,
epoch: Instant,
functions: Vec<Function>,
}
impl MetricsRecorder {
#[must_use]
pub fn from(functions: &[&'static str]) -> Self {
Self {
enabled: AtomicBool::new(false),
epoch: Instant::now(),
functions: functions.iter().map(|name| Function { name, durations: Mutex::new(RingBuffer::new()) }).collect(),
}
}
#[inline]
pub fn time_ns(&self) -> u64 {
if !self.enabled.load(Ordering::Relaxed) {
return 0;
}
u64::try_from(self.epoch.elapsed().as_nanos()).unwrap_or(u64::MAX)
}
#[inline]
pub fn record_call(&self, index: usize, start_ns: u64, stop_ns: u64) {
if start_ns == 0 || stop_ns == 0 {
return;
}
if let Some(function) = self.functions.get(index) {
function.durations.lock().unwrap().push(stop_ns.saturating_sub(start_ns));
}
}
#[inline]
pub fn record(&self, enabled: bool) {
self.enabled.store(enabled, Ordering::Relaxed);
}
pub fn report(&self) -> Report {
Report { functions: self.functions.iter().map(|f| f.durations.lock().unwrap().snapshot(f.name)).collect() }
}
}