use std::sync::atomic::{AtomicU64, Ordering};
#[derive(Debug, Default)]
pub struct EgressMeter {
cumulative: AtomicU64,
last_sample_cumulative: AtomicU64,
seeded: AtomicU64,
bps: AtomicU64,
}
impl EgressMeter {
#[must_use]
pub fn new() -> Self {
Self::default()
}
pub fn record(&self, bytes: u64) {
self.cumulative.fetch_add(bytes, Ordering::Relaxed);
}
pub fn sample(&self, interval_secs: u64) -> u64 {
if interval_secs == 0 {
return self.bps.load(Ordering::Relaxed);
}
let now = self.cumulative.load(Ordering::Relaxed);
let prev = self.last_sample_cumulative.swap(now, Ordering::Relaxed);
let delta = now.saturating_sub(prev);
let instant = delta / interval_secs;
let next = if self.seeded.swap(1, Ordering::Relaxed) == 0 {
instant
} else {
let last = self.bps.load(Ordering::Relaxed);
(instant.saturating_add(last)) / 2
};
self.bps.store(next, Ordering::Relaxed);
next
}
#[must_use]
pub fn current_bps(&self) -> u64 {
self.bps.load(Ordering::Relaxed)
}
}
#[cfg(test)]
mod tests;