Rust CI / cargo fmt (push) Successful in 17s
Rust CI / cargo check (x86_64-unknown-linux-gnu) (push) Successful in 33s
Rust CI / cargo clippy (push) Successful in 34s
Rust CI / cargo test (x86_64-unknown-linux-gnu) (push) Failing after 33s
Rust CI / cargo check (x86_64-unknown-linux-musl) (push) Failing after 9s
Rust CI / cargo test (x86_64-unknown-linux-musl) (push) Failing after 8s
Rust CI / cargo doc (push) Successful in 22s
Fuzz Smoke / cargo fuzz smoke (push) Failing after 27s
Supply chain / cargo-deny advisories (push) Successful in 7s
Supply chain / cargo-deny bans licenses sources (push) Successful in 6s
Supply chain / actionlint (push) Successful in 3s
Netem Interop / netem interop (push) Successful in 1m3s
94 lines
3.2 KiB
Rust
94 lines
3.2 KiB
Rust
use crate::PacketCounts;
|
|
|
|
#[derive(Debug, Clone, Copy, PartialEq)]
|
|
/// Packet loss, duplicate, and late-packet statistics.
|
|
///
|
|
/// Percentage fields are percentages from `0.0` to `100.0` in normal cases.
|
|
/// Directional upstream and downstream loss can be negative when
|
|
/// server-reported counts exceed local expectations.
|
|
///
|
|
/// The directional fields are derived from
|
|
/// [`PacketCounts::server_packets_received`] and are `None` when the server
|
|
/// reported no receive count. [`PacketCounts::server_received_window`] is never
|
|
/// used to derive loss.
|
|
pub struct LossStats {
|
|
/// Locally inferred total lost packets.
|
|
pub lost_packets: u64,
|
|
/// Server-assisted upstream loss estimate, when server counts are available.
|
|
pub upstream_loss_packets: Option<i128>,
|
|
/// Server-assisted downstream loss estimate, when server counts are available.
|
|
pub downstream_loss_packets: Option<i128>,
|
|
/// Total packet loss percentage.
|
|
pub packet_loss_percent: f64,
|
|
/// Server-assisted upstream loss percentage.
|
|
pub upstream_loss_percent: f64,
|
|
/// Server-assisted downstream loss percentage.
|
|
pub downstream_loss_percent: f64,
|
|
/// Duplicate reply percentage.
|
|
pub duplicate_percent: f64,
|
|
/// Late reply packet percentage.
|
|
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,
|
|
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
|
|
}
|