use crate::telemetry::MAX_RECORDED_DURATIONS;
use crate::telemetry::metrics::FunctionReport;
use std::fmt;
pub(super) struct RingBuffer {
data: Box<[u64; MAX_RECORDED_DURATIONS]>,
pos: usize,
len: usize,
lifetime_calls: u64,
}
impl fmt::Debug for RingBuffer {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("RingBuffer")
.field("len", &self.len)
.field("lifetime_calls", &self.lifetime_calls)
.finish_non_exhaustive()
}
}
impl RingBuffer {
pub fn new() -> Self {
Self { data: vec![0u64; MAX_RECORDED_DURATIONS].into_boxed_slice().try_into().unwrap(), pos: 0, len: 0, lifetime_calls: 0 }
}
#[inline]
pub fn push(&mut self, value: u64) {
self.data[self.pos] = value;
self.pos = (self.pos + 1) % MAX_RECORDED_DURATIONS;
if self.len < MAX_RECORDED_DURATIONS {
self.len += 1;
}
self.lifetime_calls += 1;
}
pub fn snapshot(&self, name: &'static str) -> FunctionReport {
let mut durations = Vec::with_capacity(self.len);
let mut min_ns = u64::MAX;
let mut max_ns = 0u64;
let mut sum = 0u64;
let start = if self.len < MAX_RECORDED_DURATIONS { 0 } else { self.pos };
for i in 0..self.len {
let d = self.data[(start + i) % MAX_RECORDED_DURATIONS];
durations.push(d);
min_ns = min_ns.min(d);
max_ns = max_ns.max(d);
sum += d;
}
FunctionReport {
name,
recent_durations_ns: durations,
lifetime_calls: self.lifetime_calls,
recent_sum_ns: sum,
recent_min_ns: if self.len > 0 { min_ns } else { 0 },
recent_max_ns: max_ns,
}
}
}