refactor(irtt-stats): extract loss stats module

This commit is contained in:
Nils Andreas Svee committed 2026-05-13 14:32:12 +07:00
1 parent cc43b43f00
commit ebc0d46621
2 files changed
+98 -76

No files matched your search

+3 -76
View File
@@ -13,9 +13,12 @@ use irtt_client::{
}; };
mod ipdv; mod ipdv;
mod loss;
mod time_stats; mod time_stats;
use ipdv::{IpdvSample, IpdvTracker}; use ipdv::{IpdvSample, IpdvTracker};
use loss::loss_stats;
pub use loss::LossStats;
use time_stats::TimeMetric; use time_stats::TimeMetric;
pub use time_stats::TimeStats; pub use time_stats::TimeStats;
@@ -197,19 +200,6 @@ pub struct PacketCounts {
pub server_received_window: Option<u64>, pub server_received_window: Option<u64>,
} }
#[derive(Debug, Clone, Copy, PartialEq)]
pub struct LossStats {
pub lost_packets: u64,
pub unknown_loss_packets: u64,
pub upstream_loss_packets: Option<i128>,
pub downstream_loss_packets: Option<i128>,
pub packet_loss_percent: f64,
pub upstream_loss_percent: f64,
pub downstream_loss_percent: f64,
pub duplicate_percent: f64,
pub late_packets_percent: f64,
}
#[derive(Debug, Clone, PartialEq)] #[derive(Debug, Clone, PartialEq)]
pub struct RttStats { pub struct RttStats {
pub primary: TimeStats, pub primary: TimeStats,
@@ -649,69 +639,6 @@ fn snapshot_window(events: &VecDeque<StatsEvent>) -> Snapshot {
core.snapshot() core.snapshot()
} }
fn loss_stats(packets: PacketCounts) -> LossStats {
let lost = packets.packets_sent.saturating_sub(packets.unique_replies);
let packet_loss_percent = if packets.packets_sent == 0 {
0.0
} else if packets.unique_replies == 0 {
100.0
} else {
percent(lost as f64, packets.packets_sent as f64)
};
let (
upstream_loss_packets,
upstream_loss_percent,
downstream_loss_packets,
downstream_loss_percent,
) = if let Some(server_received) = packets.server_packets_received {
let upstream = i128::from(packets.packets_sent) - i128::from(server_received);
let downstream = i128::from(server_received) - i128::from(packets.packets_received);
let upstream_percent = if packets.packets_sent == 0 {
0.0
} else {
percent(upstream as f64, packets.packets_sent as f64)
};
let downstream_percent = if server_received == 0 {
0.0
} else {
percent(downstream as f64, server_received as f64)
};
(
Some(upstream),
upstream_percent,
Some(downstream),
downstream_percent,
)
} else {
(None, 0.0, None, 0.0)
};
LossStats {
lost_packets: lost,
unknown_loss_packets: lost,
upstream_loss_packets,
downstream_loss_packets,
packet_loss_percent,
upstream_loss_percent,
downstream_loss_percent,
duplicate_percent: if packets.packets_received == 0 {
0.0
} else {
percent(packets.duplicates as f64, packets.packets_received as f64)
},
late_packets_percent: if packets.packets_received == 0 {
0.0
} else {
percent(packets.late_packets as f64, packets.packets_received as f64)
},
}
}
fn percent(numerator: f64, denominator: f64) -> f64 {
100.0 * numerator / denominator
}
fn system_time_ns(time: SystemTime) -> Option<i128> { fn system_time_ns(time: SystemTime) -> Option<i128> {
if let Ok(duration) = time.duration_since(UNIX_EPOCH) { if let Ok(duration) = time.duration_since(UNIX_EPOCH) {
return Some(duration_ns_i128(duration)); return Some(duration_ns_i128(duration));
+95
View File
@@ -0,0 +1,95 @@
use crate::PacketCounts;
#[derive(Debug, Clone, Copy, PartialEq)]
pub struct LossStats {
pub lost_packets: u64,
pub unknown_loss_packets: u64,
pub upstream_loss_packets: Option<i128>,
pub downstream_loss_packets: Option<i128>,
pub packet_loss_percent: f64,
pub upstream_loss_percent: f64,
pub downstream_loss_percent: f64,
pub duplicate_percent: f64,
pub late_packets_percent: f64,
}
pub(crate) fn loss_stats(packets: PacketCounts) -> LossStats {
let lost = packets.packets_sent.saturating_sub(packets.unique_replies);
let packet_loss_percent = if packets.packets_sent == 0 {
0.0
} else if packets.unique_replies == 0 {
100.0
} else {
percent(lost as f64, packets.packets_sent as f64)
};
let (
upstream_loss_packets,
upstream_loss_percent,
downstream_loss_packets,
downstream_loss_percent,
) = if let Some(server_received) = packets.server_packets_received {
let upstream = i128::from(packets.packets_sent) - i128::from(server_received);
let downstream = i128::from(server_received) - i128::from(packets.packets_received);
let upstream_percent = if packets.packets_sent == 0 {
0.0
} else {
percent(upstream as f64, packets.packets_sent as f64)
};
let downstream_percent = if server_received == 0 {
0.0
} else {
percent(downstream as f64, server_received as f64)
};
(
Some(upstream),
upstream_percent,
Some(downstream),
downstream_percent,
)
} else {
(None, 0.0, None, 0.0)
};
LossStats {
lost_packets: lost,
unknown_loss_packets: lost,
upstream_loss_packets,
downstream_loss_packets,
packet_loss_percent,
upstream_loss_percent,
downstream_loss_percent,
duplicate_percent: if packets.packets_received == 0 {
0.0
} else {
percent(packets.duplicates as f64, packets.packets_received as f64)
},
late_packets_percent: if packets.packets_received == 0 {
0.0
} else {
percent(packets.late_packets as f64, packets.packets_received as f64)
},
}
}
fn percent(numerator: f64, denominator: f64) -> f64 {
100.0 * numerator / denominator
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn duplicate_and_late_percentages_use_packets_received_denominator() {
let loss = loss_stats(PacketCounts {
packets_received: 4,
duplicates: 1,
late_packets: 2,
..PacketCounts::default()
});
assert_eq!(loss.duplicate_percent, 25.0);
assert_eq!(loss.late_packets_percent, 50.0);
}
}