use crate::model::LatencySummary;
#[derive(Debug, Default, Clone)]
pub struct OnlineStats {
n: u64,
mean: f64,
m2: f64,
}
impl OnlineStats {
pub fn push(&mut self, x: f64) {
self.n += 1;
let delta = x - self.mean;
self.mean += delta / (self.n as f64);
let delta2 = x - self.mean;
self.m2 += delta * delta2;
}
pub fn stddev(&self) -> Option<f64> {
if self.n < 2 {
None
} else {
Some((self.m2 / ((self.n - 1) as f64)).sqrt())
}
}
}
pub fn latency_summary_from_samples(
sent: u64,
received: u64,
samples_ms: &[f64],
jitter_ms: Option<f64>,
) -> LatencySummary {
let loss = if sent == 0 {
0.0
} else {
((sent - received) as f64) / (sent as f64)
};
if samples_ms.is_empty() {
return LatencySummary {
sent,
received,
loss,
jitter_ms,
..Default::default()
};
}
let mut sorted = samples_ms.to_vec();
sorted.sort_by(|a, b| a.partial_cmp(b).unwrap_or(std::cmp::Ordering::Equal));
let n = sorted.len();
let min_ms = Some(sorted[0]);
let max_ms = Some(sorted[n - 1]);
if let Some((mean, median, p25, p75)) = crate::metrics::compute_metrics(samples_ms) {
let jitter = jitter_ms.or_else(|| crate::metrics::compute_jitter(samples_ms));
LatencySummary {
sent,
received,
loss,
min_ms,
mean_ms: Some(mean),
median_ms: Some(median),
p25_ms: Some(p25),
p75_ms: Some(p75),
max_ms,
jitter_ms: jitter,
}
} else {
LatencySummary {
sent,
received,
loss,
jitter_ms,
..Default::default()
}
}
}