fix(stats): preserve signed per-packet IPDV in output

This commit is contained in:
Nils Andreas Svee committed 2026-10-21 12:19:43 +07:00
1 parent d7d3f58716
commit 06fff94505
4 files changed
+28 -20

No files matched your search

+7 -3
View File
@@ -541,7 +541,7 @@ columns! {
SendDelay("sd", ["send_delay"], 9, right, "human-readable client-to-server delay"); SendDelay("sd", ["send_delay"], 9, right, "human-readable client-to-server delay");
SendDelayUs("sd_us", ["send_delay_us"], 10, right, "client-to-server delay in signed microseconds"); SendDelayUs("sd_us", ["send_delay_us"], 10, right, "client-to-server delay in signed microseconds");
Ipdv("ipdv", [], 9, right, "human-readable round-trip IPDV for adjacent samples"); Ipdv("ipdv", [], 9, right, "human-readable round-trip IPDV for adjacent samples");
IpdvUs("ipdv_us", [], 10, right, "round-trip IPDV in microseconds"); IpdvUs("ipdv_us", [], 10, right, "round-trip IPDV in signed microseconds");
ServerProcessing("proc", ["server_processing"], 9, right, "human-readable server processing time"); ServerProcessing("proc", ["server_processing"], 9, right, "human-readable server processing time");
ServerProcessingUs("server_processing_us", [], 20, right, "server processing time in microseconds"); ServerProcessingUs("server_processing_us", [], 20, right, "server processing time in microseconds");
Bytes("bytes", [], 10, right, "packet bytes for packet events"); Bytes("bytes", [], 10, right, "packet bytes for packet events");
@@ -820,11 +820,15 @@ fn cell_for(row: &OutputRow, column: Column, context: RenderContext<'_>) -> Opti
Column::Ipdv => row Column::Ipdv => row
.seq() .seq()
.and_then(|seq| ipdv_pair(context.stats, seq)) .and_then(|seq| ipdv_pair(context.stats, seq))
.map(|pair| CellValue::text(format_duration(pair.rtt_ipdv))), .map(|pair| {
CellValue::text(format_signed_duration(SignedDuration::from_nanos(
pair.rtt_ipdv_ns,
)))
}),
Column::IpdvUs => row Column::IpdvUs => row
.seq() .seq()
.and_then(|seq| ipdv_pair(context.stats, seq)) .and_then(|seq| ipdv_pair(context.stats, seq))
.map(|pair| CellValue::Unsigned(duration_us(pair.rtt_ipdv))), .map(|pair| CellValue::Integer(pair.rtt_ipdv_ns / 1_000)),
Column::ServerProcessing => row Column::ServerProcessing => row
.reply() .reply()
.and_then(|reply| reply.server_timing.and_then(|timing| timing.processing)) .and_then(|reply| reply.server_timing.and_then(|timing| timing.processing))
+12 -10
View File
@@ -175,29 +175,31 @@ impl CoreStats {
let mut updates = Vec::new(); let mut updates = Vec::new();
for pair in self.ipdv_tracker.insert(sample) { for pair in self.ipdv_tracker.insert(sample) {
let Some(rtt_ipdv) = duration_from_non_negative_i128_ns(pair.rtt_ipdv_ns) else { let rtt_magnitude_ns = pair.rtt_ipdv_ns.saturating_abs();
let send_magnitude_ns = pair.send_ipdv_ns.map(i128::saturating_abs);
let receive_magnitude_ns = pair.receive_ipdv_ns.map(i128::saturating_abs);
let Some(rtt_ipdv) = duration_from_non_negative_i128_ns(rtt_magnitude_ns) else {
continue; continue;
}; };
let send_ipdv = pair let send_ipdv = send_magnitude_ns.and_then(duration_from_non_negative_i128_ns);
.send_ipdv_ns let receive_ipdv = receive_magnitude_ns.and_then(duration_from_non_negative_i128_ns);
.and_then(duration_from_non_negative_i128_ns);
let receive_ipdv = pair
.receive_ipdv_ns
.and_then(duration_from_non_negative_i128_ns);
self.ipdv_round_trip.push_ns(pair.rtt_ipdv_ns); self.ipdv_round_trip.push_ns(rtt_magnitude_ns);
if let Some(value) = pair.send_ipdv_ns { if let Some(value) = send_magnitude_ns {
self.ipdv_send.push_ns(value); self.ipdv_send.push_ns(value);
} }
if let Some(value) = pair.receive_ipdv_ns { if let Some(value) = receive_magnitude_ns {
self.ipdv_receive.push_ns(value); self.ipdv_receive.push_ns(value);
} }
updates.push(IpdvPairUpdate { updates.push(IpdvPairUpdate {
previous_seq: pair.previous_seq, previous_seq: pair.previous_seq,
current_seq: pair.current_seq, current_seq: pair.current_seq,
rtt_ipdv_ns: pair.rtt_ipdv_ns,
send_ipdv_ns: pair.send_ipdv_ns,
receive_ipdv_ns: pair.receive_ipdv_ns,
rtt_ipdv, rtt_ipdv,
send_ipdv, send_ipdv,
receive_ipdv, receive_ipdv,
+3 -7
View File
@@ -89,9 +89,9 @@ impl IpdvTracker {
Some(CompletedIpdvPair { Some(CompletedIpdvPair {
previous_seq, previous_seq,
current_seq, current_seq,
rtt_ipdv_ns: abs_i128_ns(current.rtt_primary_ns - previous.rtt_primary_ns), rtt_ipdv_ns: current.rtt_primary_ns - previous.rtt_primary_ns,
send_ipdv_ns: send_ipdv_ns(previous, current).map(abs_i128_ns), send_ipdv_ns: send_ipdv_ns(previous, current),
receive_ipdv_ns: receive_ipdv_ns(previous, current).map(abs_i128_ns), receive_ipdv_ns: receive_ipdv_ns(previous, current),
}) })
} }
} }
@@ -161,10 +161,6 @@ fn duration_ns_i128(duration: Duration) -> i128 {
i128::try_from(duration.as_nanos()).unwrap_or(i128::MAX) i128::try_from(duration.as_nanos()).unwrap_or(i128::MAX)
} }
fn abs_i128_ns(value: i128) -> i128 {
value.saturating_abs()
}
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
use super::*; use super::*;
+6
View File
@@ -520,6 +520,12 @@ pub struct IpdvPairUpdate {
pub previous_seq: u32, pub previous_seq: u32,
/// Sequence number of the later reply in the adjacent pair. /// Sequence number of the later reply in the adjacent pair.
pub current_seq: u32, pub current_seq: u32,
/// Signed round-trip delay change (current minus previous) in nanoseconds.
pub rtt_ipdv_ns: i128,
/// Signed send-side delay change in nanoseconds, when available for both replies.
pub send_ipdv_ns: Option<i128>,
/// Signed receive-side delay change in nanoseconds, when available for both replies.
pub receive_ipdv_ns: Option<i128>,
/// Absolute round-trip IPDV between the adjacent replies. /// Absolute round-trip IPDV between the adjacent replies.
pub rtt_ipdv: Duration, pub rtt_ipdv: Duration,
/// Absolute send-side IPDV when send one-way delay is available for both replies. /// Absolute send-side IPDV when send one-way delay is available for both replies.