refactor(irtt-stats): unify duration statistics into a single TimeStats type
Simplify the statistics model by merging signed and unsigned duration types into a single structure that uses i128 to consistently handle both positive and negative time offsets.
This commit is contained in:
3 files changed
+158
-327
No files matched your search
@@ -1,6 +1,6 @@
|
|||||||
use std::fmt::Write as _;
|
use std::fmt::Write as _;
|
||||||
|
|
||||||
use irtt_stats::{DurationStats, DurationStatsWithMedian, SignedDurationStatsWithMedian, Snapshot};
|
use irtt_stats::{Snapshot, TimeStats};
|
||||||
|
|
||||||
pub fn format_summary(summary: &Snapshot) -> String {
|
pub fn format_summary(summary: &Snapshot) -> String {
|
||||||
format_summary_with_options(summary, SummaryFormatOptions::default())
|
format_summary_with_options(summary, SummaryFormatOptions::default())
|
||||||
@@ -27,27 +27,27 @@ pub fn format_summary_with_options(summary: &Snapshot, options: SummaryFormatOpt
|
|||||||
.unwrap();
|
.unwrap();
|
||||||
writeln!(out, " {}", "-".repeat(82)).unwrap();
|
writeln!(out, " {}", "-".repeat(82)).unwrap();
|
||||||
|
|
||||||
write_signed_duration_row(&mut out, "RTT", &summary.rtt.primary);
|
write_time_row(&mut out, "RTT", &summary.rtt.primary);
|
||||||
if options.verbose {
|
if options.verbose {
|
||||||
write_duration_row(&mut out, "raw RTT", &summary.rtt.raw);
|
write_time_row(&mut out, "raw RTT", &summary.rtt.raw);
|
||||||
write_signed_duration_row(&mut out, "adjusted RTT", &summary.rtt.adjusted);
|
write_time_row(&mut out, "adjusted RTT", &summary.rtt.adjusted);
|
||||||
}
|
}
|
||||||
write_duration_row(&mut out, "IPDV/jitter", &summary.ipdv.round_trip);
|
write_time_row(&mut out, "IPDV/jitter", &summary.ipdv.round_trip);
|
||||||
write_duration_row(&mut out, "send IPDV", &summary.ipdv.send);
|
write_time_row(&mut out, "send IPDV", &summary.ipdv.send);
|
||||||
write_duration_row(&mut out, "receive IPDV", &summary.ipdv.receive);
|
write_time_row(&mut out, "receive IPDV", &summary.ipdv.receive);
|
||||||
write_duration_row(&mut out, "send delay", &summary.one_way_delay.send_delay);
|
write_time_row(&mut out, "send delay", &summary.one_way_delay.send_delay);
|
||||||
write_duration_row(
|
write_time_row(
|
||||||
&mut out,
|
&mut out,
|
||||||
"receive delay",
|
"receive delay",
|
||||||
&summary.one_way_delay.receive_delay,
|
&summary.one_way_delay.receive_delay,
|
||||||
);
|
);
|
||||||
write_duration_row_no_median(
|
write_time_row(
|
||||||
&mut out,
|
&mut out,
|
||||||
"server processing",
|
"server processing",
|
||||||
&summary.server_processing.processing,
|
&summary.server_processing.processing,
|
||||||
);
|
);
|
||||||
write_duration_row_no_median(&mut out, "send call", &summary.send_call);
|
write_time_row(&mut out, "send call", &summary.send_call);
|
||||||
write_duration_row_no_median(&mut out, "timer error", &summary.timer_error);
|
write_time_row(&mut out, "timer error", &summary.timer_error);
|
||||||
|
|
||||||
writeln!(out).unwrap();
|
writeln!(out).unwrap();
|
||||||
writeln!(
|
writeln!(
|
||||||
@@ -92,24 +92,7 @@ pub fn format_summary_with_options(summary: &Snapshot, options: SummaryFormatOpt
|
|||||||
out
|
out
|
||||||
}
|
}
|
||||||
|
|
||||||
fn write_duration_row(out: &mut String, label: &str, value: &DurationStatsWithMedian) {
|
fn write_time_row(out: &mut String, label: &str, value: &TimeStats) {
|
||||||
if value.stats.count == 0 {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
writeln!(
|
|
||||||
out,
|
|
||||||
" {label:<18} {:>7} {:>10} {:>10} {:>10} {:>10} {:>10}",
|
|
||||||
value.stats.count,
|
|
||||||
format_ns_u64(value.stats.min_ns),
|
|
||||||
format_ns_f64(value.stats.mean_ns),
|
|
||||||
format_ns_f64_opt(value.median_ns),
|
|
||||||
format_ns_u64(value.stats.max_ns),
|
|
||||||
format_ns_f64(value.stddev_ns())
|
|
||||||
)
|
|
||||||
.unwrap();
|
|
||||||
}
|
|
||||||
|
|
||||||
fn write_duration_row_no_median(out: &mut String, label: &str, value: &DurationStats) {
|
|
||||||
if value.count == 0 {
|
if value.count == 0 {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -117,27 +100,10 @@ fn write_duration_row_no_median(out: &mut String, label: &str, value: &DurationS
|
|||||||
out,
|
out,
|
||||||
" {label:<18} {:>7} {:>10} {:>10} {:>10} {:>10} {:>10}",
|
" {label:<18} {:>7} {:>10} {:>10} {:>10} {:>10} {:>10}",
|
||||||
value.count,
|
value.count,
|
||||||
format_ns_u64(value.min_ns),
|
format_ns_i128(value.min_ns),
|
||||||
format_ns_f64(value.mean_ns),
|
format_ns_f64(value.mean_ns),
|
||||||
"-",
|
|
||||||
format_ns_u64(value.max_ns),
|
|
||||||
format_ns_f64(value.stddev_ns())
|
|
||||||
)
|
|
||||||
.unwrap();
|
|
||||||
}
|
|
||||||
|
|
||||||
fn write_signed_duration_row(out: &mut String, label: &str, value: &SignedDurationStatsWithMedian) {
|
|
||||||
if value.stats.count == 0 {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
writeln!(
|
|
||||||
out,
|
|
||||||
" {label:<18} {:>7} {:>10} {:>10} {:>10} {:>10} {:>10}",
|
|
||||||
value.stats.count,
|
|
||||||
format_ns_i128(value.stats.min_ns),
|
|
||||||
format_ns_f64(value.stats.mean_ns),
|
|
||||||
format_ns_f64_opt(value.median_ns),
|
format_ns_f64_opt(value.median_ns),
|
||||||
format_ns_i128(value.stats.max_ns),
|
format_ns_i128(value.max_ns),
|
||||||
format_ns_f64(value.stddev_ns())
|
format_ns_f64(value.stddev_ns())
|
||||||
)
|
)
|
||||||
.unwrap();
|
.unwrap();
|
||||||
@@ -147,12 +113,6 @@ fn format_percent(value: f64) -> String {
|
|||||||
format!("{value:.2}%")
|
format!("{value:.2}%")
|
||||||
}
|
}
|
||||||
|
|
||||||
fn format_ns_u64(value: Option<u64>) -> String {
|
|
||||||
value
|
|
||||||
.map(|value| format_ns_f64(value as f64))
|
|
||||||
.unwrap_or_else(|| "-".to_owned())
|
|
||||||
}
|
|
||||||
|
|
||||||
fn format_ns_i128(value: Option<i128>) -> String {
|
fn format_ns_i128(value: Option<i128>) -> String {
|
||||||
value
|
value
|
||||||
.map(|value| format_ns_f64(value as f64))
|
.map(|value| format_ns_f64(value as f64))
|
||||||
@@ -183,7 +143,7 @@ mod tests {
|
|||||||
use irtt_client::{
|
use irtt_client::{
|
||||||
ClientEvent, ClientTimestamp, PacketMeta, RttSample, ServerTiming, SignedDuration,
|
ClientEvent, ClientTimestamp, PacketMeta, RttSample, ServerTiming, SignedDuration,
|
||||||
};
|
};
|
||||||
use irtt_stats::{SignedDurationStats, StatsCollector, StatsConfig};
|
use irtt_stats::{StatsCollector, StatsConfig};
|
||||||
use std::{
|
use std::{
|
||||||
net::{IpAddr, Ipv4Addr, SocketAddr},
|
net::{IpAddr, Ipv4Addr, SocketAddr},
|
||||||
time::{Duration, Instant, UNIX_EPOCH},
|
time::{Duration, Instant, UNIX_EPOCH},
|
||||||
@@ -308,20 +268,18 @@ mod tests {
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn signed_stats_can_format_negative_values() {
|
fn signed_stats_can_format_negative_values() {
|
||||||
let stats = SignedDurationStatsWithMedian {
|
let stats = TimeStats {
|
||||||
stats: SignedDurationStats {
|
|
||||||
count: 1,
|
count: 1,
|
||||||
total_ns: -500,
|
total_ns: -500,
|
||||||
min_ns: Some(-500),
|
min_ns: Some(-500),
|
||||||
max_ns: Some(-500),
|
max_ns: Some(-500),
|
||||||
mean_ns: -500.0,
|
mean_ns: -500.0,
|
||||||
variance_ns2: 0.0,
|
|
||||||
},
|
|
||||||
median_ns: Some(-500.0),
|
median_ns: Some(-500.0),
|
||||||
|
variance_ns2: 0.0,
|
||||||
};
|
};
|
||||||
|
|
||||||
let mut out = String::new();
|
let mut out = String::new();
|
||||||
write_signed_duration_row(&mut out, "RTT", &stats);
|
write_time_row(&mut out, "RTT", &stats);
|
||||||
assert!(out.contains("-500ns"));
|
assert!(out.contains("-500ns"));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
+125
-252
@@ -137,8 +137,8 @@ pub struct Snapshot {
|
|||||||
pub events: EventCounts,
|
pub events: EventCounts,
|
||||||
pub packets: PacketCounts,
|
pub packets: PacketCounts,
|
||||||
pub loss: LossStats,
|
pub loss: LossStats,
|
||||||
pub send_call: DurationStats,
|
pub send_call: TimeStats,
|
||||||
pub timer_error: DurationStats,
|
pub timer_error: TimeStats,
|
||||||
pub rtt: RttStats,
|
pub rtt: RttStats,
|
||||||
pub ipdv: IpdvStats,
|
pub ipdv: IpdvStats,
|
||||||
pub one_way_delay: OneWayDelayStats,
|
pub one_way_delay: OneWayDelayStats,
|
||||||
@@ -184,82 +184,47 @@ pub struct LossStats {
|
|||||||
|
|
||||||
#[derive(Debug, Clone, PartialEq)]
|
#[derive(Debug, Clone, PartialEq)]
|
||||||
pub struct RttStats {
|
pub struct RttStats {
|
||||||
pub primary: SignedDurationStatsWithMedian,
|
pub primary: TimeStats,
|
||||||
pub raw: DurationStatsWithMedian,
|
pub raw: TimeStats,
|
||||||
pub adjusted: SignedDurationStatsWithMedian,
|
pub adjusted: TimeStats,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone, PartialEq)]
|
#[derive(Debug, Clone, PartialEq)]
|
||||||
pub struct IpdvStats {
|
pub struct IpdvStats {
|
||||||
pub round_trip: DurationStatsWithMedian,
|
pub round_trip: TimeStats,
|
||||||
pub send: DurationStatsWithMedian,
|
pub send: TimeStats,
|
||||||
pub receive: DurationStatsWithMedian,
|
pub receive: TimeStats,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone, PartialEq)]
|
#[derive(Debug, Clone, PartialEq)]
|
||||||
pub struct OneWayDelayStats {
|
pub struct OneWayDelayStats {
|
||||||
pub send_delay: DurationStatsWithMedian,
|
pub send_delay: TimeStats,
|
||||||
pub receive_delay: DurationStatsWithMedian,
|
pub receive_delay: TimeStats,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone, PartialEq)]
|
#[derive(Debug, Clone, PartialEq)]
|
||||||
pub struct ServerProcessingStats {
|
pub struct ServerProcessingStats {
|
||||||
pub processing: DurationStats,
|
pub processing: TimeStats,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone, Copy, PartialEq)]
|
#[derive(Debug, Clone, Copy, PartialEq)]
|
||||||
pub struct DurationStats {
|
pub struct TimeStats {
|
||||||
pub count: u64,
|
|
||||||
pub total_ns: u128,
|
|
||||||
pub min_ns: Option<u64>,
|
|
||||||
pub max_ns: Option<u64>,
|
|
||||||
pub mean_ns: f64,
|
|
||||||
pub variance_ns2: f64,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl DurationStats {
|
|
||||||
pub fn stddev_ns(&self) -> f64 {
|
|
||||||
self.variance_ns2.sqrt()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug, Clone, Copy, PartialEq)]
|
|
||||||
pub struct DurationStatsWithMedian {
|
|
||||||
pub stats: DurationStats,
|
|
||||||
pub median_ns: Option<f64>,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl DurationStatsWithMedian {
|
|
||||||
pub fn stddev_ns(&self) -> f64 {
|
|
||||||
self.stats.stddev_ns()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug, Clone, Copy, PartialEq)]
|
|
||||||
pub struct SignedDurationStats {
|
|
||||||
pub count: u64,
|
pub count: u64,
|
||||||
pub total_ns: i128,
|
pub total_ns: i128,
|
||||||
pub min_ns: Option<i128>,
|
pub min_ns: Option<i128>,
|
||||||
pub max_ns: Option<i128>,
|
pub max_ns: Option<i128>,
|
||||||
pub mean_ns: f64,
|
pub mean_ns: f64,
|
||||||
|
pub median_ns: Option<f64>,
|
||||||
pub variance_ns2: f64,
|
pub variance_ns2: f64,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl SignedDurationStats {
|
impl TimeStats {
|
||||||
pub fn stddev_ns(&self) -> f64 {
|
pub fn stddev_ns(&self) -> f64 {
|
||||||
self.variance_ns2.sqrt()
|
self.variance_ns2.sqrt()
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug, Clone, Copy, PartialEq)]
|
pub fn is_empty(&self) -> bool {
|
||||||
pub struct SignedDurationStatsWithMedian {
|
self.count == 0
|
||||||
pub stats: SignedDurationStats,
|
|
||||||
pub median_ns: Option<f64>,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl SignedDurationStatsWithMedian {
|
|
||||||
pub fn stddev_ns(&self) -> f64 {
|
|
||||||
self.stats.stddev_ns()
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -269,17 +234,17 @@ struct CoreStats {
|
|||||||
sequence_limit: Option<usize>,
|
sequence_limit: Option<usize>,
|
||||||
events: EventCounts,
|
events: EventCounts,
|
||||||
packets: PacketCounts,
|
packets: PacketCounts,
|
||||||
send_call: MetricU64,
|
send_call: TimeMetric,
|
||||||
timer_error: MetricU64,
|
timer_error: TimeMetric,
|
||||||
rtt_primary: MetricI128,
|
rtt_primary: TimeMetric,
|
||||||
rtt_raw: MetricU64,
|
rtt_raw: TimeMetric,
|
||||||
rtt_adjusted: MetricI128,
|
rtt_adjusted: TimeMetric,
|
||||||
ipdv_round_trip: MetricU64,
|
ipdv_round_trip: TimeMetric,
|
||||||
ipdv_send: MetricU64,
|
ipdv_send: TimeMetric,
|
||||||
ipdv_receive: MetricU64,
|
ipdv_receive: TimeMetric,
|
||||||
send_delay: MetricU64,
|
send_delay: TimeMetric,
|
||||||
receive_delay: MetricU64,
|
receive_delay: TimeMetric,
|
||||||
server_processing: MetricU64,
|
server_processing: TimeMetric,
|
||||||
samples: HashMap<u32, UniqueSample>,
|
samples: HashMap<u32, UniqueSample>,
|
||||||
sample_order: VecDeque<u32>,
|
sample_order: VecDeque<u32>,
|
||||||
ipdv_pairs: HashSet<u32>,
|
ipdv_pairs: HashSet<u32>,
|
||||||
@@ -296,17 +261,17 @@ impl CoreStats {
|
|||||||
},
|
},
|
||||||
events: EventCounts::default(),
|
events: EventCounts::default(),
|
||||||
packets: PacketCounts::default(),
|
packets: PacketCounts::default(),
|
||||||
send_call: MetricU64::new(false),
|
send_call: TimeMetric::new(false),
|
||||||
timer_error: MetricU64::new(false),
|
timer_error: TimeMetric::new(false),
|
||||||
rtt_primary: MetricI128::new(median == MedianMode::ExactFinite),
|
rtt_primary: TimeMetric::new(median == MedianMode::ExactFinite),
|
||||||
rtt_raw: MetricU64::new(median == MedianMode::ExactFinite),
|
rtt_raw: TimeMetric::new(median == MedianMode::ExactFinite),
|
||||||
rtt_adjusted: MetricI128::new(median == MedianMode::ExactFinite),
|
rtt_adjusted: TimeMetric::new(median == MedianMode::ExactFinite),
|
||||||
ipdv_round_trip: MetricU64::new(median == MedianMode::ExactFinite),
|
ipdv_round_trip: TimeMetric::new(median == MedianMode::ExactFinite),
|
||||||
ipdv_send: MetricU64::new(median == MedianMode::ExactFinite),
|
ipdv_send: TimeMetric::new(median == MedianMode::ExactFinite),
|
||||||
ipdv_receive: MetricU64::new(median == MedianMode::ExactFinite),
|
ipdv_receive: TimeMetric::new(median == MedianMode::ExactFinite),
|
||||||
send_delay: MetricU64::new(median == MedianMode::ExactFinite),
|
send_delay: TimeMetric::new(median == MedianMode::ExactFinite),
|
||||||
receive_delay: MetricU64::new(median == MedianMode::ExactFinite),
|
receive_delay: TimeMetric::new(median == MedianMode::ExactFinite),
|
||||||
server_processing: MetricU64::new(false),
|
server_processing: TimeMetric::new(false),
|
||||||
samples: HashMap::new(),
|
samples: HashMap::new(),
|
||||||
sample_order: VecDeque::new(),
|
sample_order: VecDeque::new(),
|
||||||
ipdv_pairs: HashSet::new(),
|
ipdv_pairs: HashSet::new(),
|
||||||
@@ -325,8 +290,8 @@ impl CoreStats {
|
|||||||
self.events.sent_events += 1;
|
self.events.sent_events += 1;
|
||||||
self.packets.packets_sent += 1;
|
self.packets.packets_sent += 1;
|
||||||
self.packets.bytes_sent = self.packets.bytes_sent.saturating_add(bytes as u64);
|
self.packets.bytes_sent = self.packets.bytes_sent.saturating_add(bytes as u64);
|
||||||
self.send_call.push(send_call_ns);
|
self.send_call.push_ns(send_call_ns);
|
||||||
self.timer_error.push(timer_error_ns);
|
self.timer_error.push_ns(timer_error_ns);
|
||||||
}
|
}
|
||||||
WindowEvent::UniqueReply {
|
WindowEvent::UniqueReply {
|
||||||
is_late, sample, ..
|
is_late, sample, ..
|
||||||
@@ -349,19 +314,19 @@ impl CoreStats {
|
|||||||
self.packets.server_received_window = Some(window);
|
self.packets.server_received_window = Some(window);
|
||||||
}
|
}
|
||||||
|
|
||||||
self.rtt_primary.push(sample.rtt_primary_ns);
|
self.rtt_primary.push_ns(sample.rtt_primary_ns);
|
||||||
self.rtt_raw.push(sample.rtt_raw_ns);
|
self.rtt_raw.push_ns(sample.rtt_raw_ns);
|
||||||
if let Some(adjusted) = sample.rtt_adjusted_ns {
|
if let Some(adjusted) = sample.rtt_adjusted_ns {
|
||||||
self.rtt_adjusted.push(adjusted);
|
self.rtt_adjusted.push_ns(adjusted);
|
||||||
}
|
}
|
||||||
if let Some(processing) = sample.server_processing_ns {
|
if let Some(processing) = sample.server_processing_ns {
|
||||||
self.server_processing.push(processing);
|
self.server_processing.push_ns(processing);
|
||||||
}
|
}
|
||||||
if let Some(delay) = sample.send_delay_ns {
|
if let Some(delay) = sample.send_delay_ns {
|
||||||
self.send_delay.push(delay);
|
self.send_delay.push_ns(delay);
|
||||||
}
|
}
|
||||||
if let Some(delay) = sample.receive_delay_ns {
|
if let Some(delay) = sample.receive_delay_ns {
|
||||||
self.receive_delay.push(delay);
|
self.receive_delay.push_ns(delay);
|
||||||
}
|
}
|
||||||
|
|
||||||
let seq = sample.seq;
|
let seq = sample.seq;
|
||||||
@@ -432,26 +397,26 @@ impl CoreStats {
|
|||||||
|
|
||||||
// Compute everything before mutating metric fields, otherwise the borrow
|
// Compute everything before mutating metric fields, otherwise the borrow
|
||||||
// checker may quite reasonably start throwing furniture.
|
// checker may quite reasonably start throwing furniture.
|
||||||
let rtt_ipdv = abs_i128_to_u64(current.rtt_primary_ns - previous.rtt_primary_ns);
|
let rtt_ipdv = abs_i128_ns(current.rtt_primary_ns - previous.rtt_primary_ns);
|
||||||
let send_ipdv = send_ipdv_ns(previous, current).map(abs_i128_to_u64);
|
let send_ipdv = send_ipdv_ns(previous, current).map(abs_i128_ns);
|
||||||
let receive_ipdv = receive_ipdv_ns(previous, current).map(abs_i128_to_u64);
|
let receive_ipdv = receive_ipdv_ns(previous, current).map(abs_i128_ns);
|
||||||
|
|
||||||
self.ipdv_round_trip.push(rtt_ipdv);
|
self.ipdv_round_trip.push_ns(rtt_ipdv);
|
||||||
|
|
||||||
if let Some(value) = send_ipdv {
|
if let Some(value) = send_ipdv {
|
||||||
self.ipdv_send.push(value);
|
self.ipdv_send.push_ns(value);
|
||||||
}
|
}
|
||||||
|
|
||||||
if let Some(value) = receive_ipdv {
|
if let Some(value) = receive_ipdv {
|
||||||
self.ipdv_receive.push(value);
|
self.ipdv_receive.push_ns(value);
|
||||||
}
|
}
|
||||||
|
|
||||||
Some(IpdvPairUpdate {
|
Some(IpdvPairUpdate {
|
||||||
previous_seq,
|
previous_seq,
|
||||||
current_seq,
|
current_seq,
|
||||||
rtt_ipdv: Duration::from_nanos(rtt_ipdv),
|
rtt_ipdv: duration_from_i128_ns(rtt_ipdv),
|
||||||
send_ipdv: send_ipdv.map(Duration::from_nanos),
|
send_ipdv: send_ipdv.map(duration_from_i128_ns),
|
||||||
receive_ipdv: receive_ipdv.map(Duration::from_nanos),
|
receive_ipdv: receive_ipdv.map(duration_from_i128_ns),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -464,18 +429,18 @@ impl CoreStats {
|
|||||||
send_call: self.send_call.stats(),
|
send_call: self.send_call.stats(),
|
||||||
timer_error: self.timer_error.stats(),
|
timer_error: self.timer_error.stats(),
|
||||||
rtt: RttStats {
|
rtt: RttStats {
|
||||||
primary: self.rtt_primary.stats_with_median(),
|
primary: self.rtt_primary.stats(),
|
||||||
raw: self.rtt_raw.stats_with_median(),
|
raw: self.rtt_raw.stats(),
|
||||||
adjusted: self.rtt_adjusted.stats_with_median(),
|
adjusted: self.rtt_adjusted.stats(),
|
||||||
},
|
},
|
||||||
ipdv: IpdvStats {
|
ipdv: IpdvStats {
|
||||||
round_trip: self.ipdv_round_trip.stats_with_median(),
|
round_trip: self.ipdv_round_trip.stats(),
|
||||||
send: self.ipdv_send.stats_with_median(),
|
send: self.ipdv_send.stats(),
|
||||||
receive: self.ipdv_receive.stats_with_median(),
|
receive: self.ipdv_receive.stats(),
|
||||||
},
|
},
|
||||||
one_way_delay: OneWayDelayStats {
|
one_way_delay: OneWayDelayStats {
|
||||||
send_delay: self.send_delay.stats_with_median(),
|
send_delay: self.send_delay.stats(),
|
||||||
receive_delay: self.receive_delay.stats_with_median(),
|
receive_delay: self.receive_delay.stats(),
|
||||||
},
|
},
|
||||||
server_processing: ServerProcessingStats {
|
server_processing: ServerProcessingStats {
|
||||||
processing: self.server_processing.stats(),
|
processing: self.server_processing.stats(),
|
||||||
@@ -489,8 +454,8 @@ enum WindowEvent {
|
|||||||
Sent {
|
Sent {
|
||||||
at: Instant,
|
at: Instant,
|
||||||
bytes: usize,
|
bytes: usize,
|
||||||
send_call_ns: u64,
|
send_call_ns: i128,
|
||||||
timer_error_ns: u64,
|
timer_error_ns: i128,
|
||||||
},
|
},
|
||||||
UniqueReply {
|
UniqueReply {
|
||||||
at: Instant,
|
at: Instant,
|
||||||
@@ -523,8 +488,8 @@ impl WindowEvent {
|
|||||||
} => Some(Self::Sent {
|
} => Some(Self::Sent {
|
||||||
at: sent_at.mono,
|
at: sent_at.mono,
|
||||||
bytes: *bytes,
|
bytes: *bytes,
|
||||||
send_call_ns: duration_ns_u64(*send_call),
|
send_call_ns: duration_ns_i128(*send_call),
|
||||||
timer_error_ns: duration_ns_u64(*timer_error),
|
timer_error_ns: duration_ns_i128(*timer_error),
|
||||||
}),
|
}),
|
||||||
ClientEvent::EchoReply {
|
ClientEvent::EchoReply {
|
||||||
seq,
|
seq,
|
||||||
@@ -605,11 +570,11 @@ struct UniqueSample {
|
|||||||
seq: u32,
|
seq: u32,
|
||||||
bytes: usize,
|
bytes: usize,
|
||||||
rtt_primary_ns: i128,
|
rtt_primary_ns: i128,
|
||||||
rtt_raw_ns: u64,
|
rtt_raw_ns: i128,
|
||||||
rtt_adjusted_ns: Option<i128>,
|
rtt_adjusted_ns: Option<i128>,
|
||||||
send_delay_ns: Option<u64>,
|
send_delay_ns: Option<i128>,
|
||||||
receive_delay_ns: Option<u64>,
|
receive_delay_ns: Option<i128>,
|
||||||
server_processing_ns: Option<u64>,
|
server_processing_ns: Option<i128>,
|
||||||
received_count: Option<u32>,
|
received_count: Option<u32>,
|
||||||
received_window: Option<u64>,
|
received_window: Option<u64>,
|
||||||
client_send_mono: Instant,
|
client_send_mono: Instant,
|
||||||
@@ -638,17 +603,17 @@ impl UniqueSample {
|
|||||||
seq,
|
seq,
|
||||||
bytes,
|
bytes,
|
||||||
rtt_primary_ns: signed_duration_ns(rtt.effective_signed),
|
rtt_primary_ns: signed_duration_ns(rtt.effective_signed),
|
||||||
rtt_raw_ns: duration_ns_u64(rtt.raw),
|
rtt_raw_ns: duration_ns_i128(rtt.raw),
|
||||||
rtt_adjusted_ns: rtt.adjusted_signed.map(signed_duration_ns),
|
rtt_adjusted_ns: rtt.adjusted_signed.map(signed_duration_ns),
|
||||||
send_delay_ns: one_way
|
send_delay_ns: one_way
|
||||||
.and_then(|sample| sample.client_to_server)
|
.and_then(|sample| sample.client_to_server)
|
||||||
.map(duration_ns_u64),
|
.map(duration_ns_i128),
|
||||||
receive_delay_ns: one_way
|
receive_delay_ns: one_way
|
||||||
.and_then(|sample| sample.server_to_client)
|
.and_then(|sample| sample.server_to_client)
|
||||||
.map(duration_ns_u64),
|
.map(duration_ns_i128),
|
||||||
server_processing_ns: server_timing
|
server_processing_ns: server_timing
|
||||||
.and_then(|timing| timing.processing)
|
.and_then(|timing| timing.processing)
|
||||||
.map(duration_ns_u64),
|
.map(duration_ns_i128),
|
||||||
received_count: received_stats.and_then(|stats| stats.count),
|
received_count: received_stats.and_then(|stats| stats.count),
|
||||||
received_window: received_stats.and_then(|stats| stats.window),
|
received_window: received_stats.and_then(|stats| stats.window),
|
||||||
client_send_mono: sent_at.mono,
|
client_send_mono: sent_at.mono,
|
||||||
@@ -664,143 +629,69 @@ impl UniqueSample {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone, PartialEq)]
|
#[derive(Debug, Clone, PartialEq)]
|
||||||
struct MetricU64 {
|
struct TimeMetric {
|
||||||
running: RunningU64,
|
running: RunningStats,
|
||||||
samples: Option<Vec<u64>>,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl MetricU64 {
|
|
||||||
fn new(retain_samples: bool) -> Self {
|
|
||||||
Self {
|
|
||||||
running: RunningU64::default(),
|
|
||||||
samples: retain_samples.then(Vec::new),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn push(&mut self, value: u64) {
|
|
||||||
self.running.push(value);
|
|
||||||
if let Some(samples) = self.samples.as_mut() {
|
|
||||||
samples.push(value);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn stats(&self) -> DurationStats {
|
|
||||||
self.running.stats()
|
|
||||||
}
|
|
||||||
|
|
||||||
fn stats_with_median(&self) -> DurationStatsWithMedian {
|
|
||||||
DurationStatsWithMedian {
|
|
||||||
stats: self.stats(),
|
|
||||||
median_ns: self
|
|
||||||
.samples
|
|
||||||
.as_ref()
|
|
||||||
.and_then(|samples| median_u64(samples)),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug, Clone, PartialEq)]
|
|
||||||
struct MetricI128 {
|
|
||||||
running: RunningI128,
|
|
||||||
samples: Option<Vec<i128>>,
|
samples: Option<Vec<i128>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl MetricI128 {
|
impl TimeMetric {
|
||||||
fn new(retain_samples: bool) -> Self {
|
fn new(retain_samples: bool) -> Self {
|
||||||
Self {
|
Self {
|
||||||
running: RunningI128::default(),
|
running: RunningStats::default(),
|
||||||
samples: retain_samples.then(Vec::new),
|
samples: retain_samples.then(Vec::new),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn push(&mut self, value: i128) {
|
fn push_ns(&mut self, value: i128) {
|
||||||
self.running.push(value);
|
self.running.push(value);
|
||||||
if let Some(samples) = self.samples.as_mut() {
|
if let Some(samples) = self.samples.as_mut() {
|
||||||
samples.push(value);
|
samples.push(value);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn stats(&self) -> SignedDurationStats {
|
#[allow(dead_code)]
|
||||||
self.running.stats()
|
fn push_duration(&mut self, duration: Duration) {
|
||||||
|
self.push_ns(duration_ns_i128(duration));
|
||||||
}
|
}
|
||||||
|
|
||||||
fn stats_with_median(&self) -> SignedDurationStatsWithMedian {
|
fn stats(&self) -> TimeStats {
|
||||||
SignedDurationStatsWithMedian {
|
self.running
|
||||||
stats: self.stats(),
|
.stats(self.samples.as_ref().and_then(|samples| median_ns(samples)))
|
||||||
median_ns: self
|
|
||||||
.samples
|
|
||||||
.as_ref()
|
|
||||||
.and_then(|samples| median_i128(samples)),
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone, PartialEq, Default)]
|
#[derive(Debug, Clone, PartialEq, Default)]
|
||||||
struct RunningU64 {
|
struct RunningStats {
|
||||||
count: u64,
|
count: u64,
|
||||||
total: u128,
|
total_ns: i128,
|
||||||
min: Option<u64>,
|
min_ns: Option<i128>,
|
||||||
max: Option<u64>,
|
max_ns: Option<i128>,
|
||||||
mean: f64,
|
mean_ns: f64,
|
||||||
m2: f64,
|
m2_ns2: f64,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl RunningU64 {
|
impl RunningStats {
|
||||||
fn push(&mut self, value: u64) {
|
|
||||||
self.count += 1;
|
|
||||||
self.total = self.total.saturating_add(u128::from(value));
|
|
||||||
self.min = Some(self.min.map_or(value, |min| min.min(value)));
|
|
||||||
self.max = Some(self.max.map_or(value, |max| max.max(value)));
|
|
||||||
let x = value as f64;
|
|
||||||
let delta = x - self.mean;
|
|
||||||
self.mean += delta / self.count as f64;
|
|
||||||
let delta2 = x - self.mean;
|
|
||||||
self.m2 += delta * delta2;
|
|
||||||
}
|
|
||||||
|
|
||||||
fn stats(&self) -> DurationStats {
|
|
||||||
DurationStats {
|
|
||||||
count: self.count,
|
|
||||||
total_ns: self.total,
|
|
||||||
min_ns: self.min,
|
|
||||||
max_ns: self.max,
|
|
||||||
mean_ns: if self.count == 0 { 0.0 } else { self.mean },
|
|
||||||
variance_ns2: sample_variance(self.count, self.m2),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug, Clone, PartialEq, Default)]
|
|
||||||
struct RunningI128 {
|
|
||||||
count: u64,
|
|
||||||
total: i128,
|
|
||||||
min: Option<i128>,
|
|
||||||
max: Option<i128>,
|
|
||||||
mean: f64,
|
|
||||||
m2: f64,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl RunningI128 {
|
|
||||||
fn push(&mut self, value: i128) {
|
fn push(&mut self, value: i128) {
|
||||||
self.count += 1;
|
self.count += 1;
|
||||||
self.total = self.total.saturating_add(value);
|
self.total_ns = self.total_ns.saturating_add(value);
|
||||||
self.min = Some(self.min.map_or(value, |min| min.min(value)));
|
self.min_ns = Some(self.min_ns.map_or(value, |min| min.min(value)));
|
||||||
self.max = Some(self.max.map_or(value, |max| max.max(value)));
|
self.max_ns = Some(self.max_ns.map_or(value, |max| max.max(value)));
|
||||||
let x = value as f64;
|
let x = value as f64;
|
||||||
let delta = x - self.mean;
|
let delta = x - self.mean_ns;
|
||||||
self.mean += delta / self.count as f64;
|
self.mean_ns += delta / self.count as f64;
|
||||||
let delta2 = x - self.mean;
|
let delta2 = x - self.mean_ns;
|
||||||
self.m2 += delta * delta2;
|
self.m2_ns2 += delta * delta2;
|
||||||
}
|
}
|
||||||
|
|
||||||
fn stats(&self) -> SignedDurationStats {
|
fn stats(&self, median_ns: Option<f64>) -> TimeStats {
|
||||||
SignedDurationStats {
|
TimeStats {
|
||||||
count: self.count,
|
count: self.count,
|
||||||
total_ns: self.total,
|
total_ns: self.total_ns,
|
||||||
min_ns: self.min,
|
min_ns: self.min_ns,
|
||||||
max_ns: self.max,
|
max_ns: self.max_ns,
|
||||||
mean_ns: if self.count == 0 { 0.0 } else { self.mean },
|
mean_ns: if self.count == 0 { 0.0 } else { self.mean_ns },
|
||||||
variance_ns2: sample_variance(self.count, self.m2),
|
median_ns,
|
||||||
|
variance_ns2: sample_variance(self.count, self.m2_ns2),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -821,25 +712,7 @@ fn sample_variance(count: u64, m2: f64) -> f64 {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn median_u64(samples: &[u64]) -> Option<f64> {
|
fn median_ns(samples: &[i128]) -> Option<f64> {
|
||||||
if samples.is_empty() {
|
|
||||||
return None;
|
|
||||||
}
|
|
||||||
let mut sorted = samples.to_vec();
|
|
||||||
sorted.sort_unstable();
|
|
||||||
Some(median_sorted_u64(&sorted))
|
|
||||||
}
|
|
||||||
|
|
||||||
fn median_sorted_u64(sorted: &[u64]) -> f64 {
|
|
||||||
let mid = sorted.len() / 2;
|
|
||||||
if sorted.len() % 2 == 1 {
|
|
||||||
sorted[mid] as f64
|
|
||||||
} else {
|
|
||||||
(sorted[mid - 1] as f64 + sorted[mid] as f64) / 2.0
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn median_i128(samples: &[i128]) -> Option<f64> {
|
|
||||||
if samples.is_empty() {
|
if samples.is_empty() {
|
||||||
return None;
|
return None;
|
||||||
}
|
}
|
||||||
@@ -978,10 +851,6 @@ fn system_time_ns(time: SystemTime) -> Option<i128> {
|
|||||||
.map(|duration| -duration_ns_i128(duration))
|
.map(|duration| -duration_ns_i128(duration))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn duration_ns_u64(duration: Duration) -> u64 {
|
|
||||||
u64::try_from(duration.as_nanos()).unwrap_or(u64::MAX)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn duration_ns_i128(duration: Duration) -> i128 {
|
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)
|
||||||
}
|
}
|
||||||
@@ -990,8 +859,12 @@ fn signed_duration_ns(duration: SignedDuration) -> i128 {
|
|||||||
duration.ns
|
duration.ns
|
||||||
}
|
}
|
||||||
|
|
||||||
fn abs_i128_to_u64(value: i128) -> u64 {
|
fn abs_i128_ns(value: i128) -> i128 {
|
||||||
u64::try_from(value.saturating_abs()).unwrap_or(u64::MAX)
|
value.saturating_abs()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn duration_from_i128_ns(value: i128) -> Duration {
|
||||||
|
Duration::from_nanos(u64::try_from(value).unwrap_or(u64::MAX))
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
@@ -1001,10 +874,10 @@ mod tests {
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn running_duration_stats_use_sample_variance() {
|
fn running_duration_stats_use_sample_variance() {
|
||||||
let mut metric = MetricU64::new(false);
|
let mut metric = TimeMetric::new(false);
|
||||||
metric.push(1);
|
metric.push_ns(1);
|
||||||
metric.push(2);
|
metric.push_ns(2);
|
||||||
metric.push(3);
|
metric.push_ns(3);
|
||||||
let stats = metric.stats();
|
let stats = metric.stats();
|
||||||
assert_eq!(stats.count, 3);
|
assert_eq!(stats.count, 3);
|
||||||
assert_eq!(stats.total_ns, 6);
|
assert_eq!(stats.total_ns, 6);
|
||||||
@@ -1017,16 +890,16 @@ mod tests {
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn exact_median_handles_odd_and_even_samples() {
|
fn exact_median_handles_odd_and_even_samples() {
|
||||||
assert_eq!(median_u64(&[3, 1, 2]), Some(2.0));
|
assert_eq!(median_ns(&[3, 1, 2]), Some(2.0));
|
||||||
assert_eq!(median_u64(&[4, 1, 2, 3]), Some(2.5));
|
assert_eq!(median_ns(&[4, 1, 2, 3]), Some(2.5));
|
||||||
assert_eq!(median_i128(&[-5, 1, 3]), Some(1.0));
|
assert_eq!(median_ns(&[-5, 1, 3]), Some(1.0));
|
||||||
assert_eq!(median_i128(&[-5, 1, 3, 7]), Some(2.0));
|
assert_eq!(median_ns(&[-5, 1, 3, 7]), Some(2.0));
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn single_sample_stddev_is_zero() {
|
fn single_sample_stddev_is_zero() {
|
||||||
let mut metric = MetricU64::new(false);
|
let mut metric = TimeMetric::new(false);
|
||||||
metric.push(42);
|
metric.push_ns(42);
|
||||||
let stats = metric.stats();
|
let stats = metric.stats();
|
||||||
assert_eq!(stats.variance_ns2, 0.0);
|
assert_eq!(stats.variance_ns2, 0.0);
|
||||||
assert_eq!(stats.stddev_ns(), 0.0);
|
assert_eq!(stats.stddev_ns(), 0.0);
|
||||||
|
|||||||
@@ -29,8 +29,8 @@ fn continuous_mode_tracks_samples_without_exact_medians() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
let snapshot = collector.snapshot();
|
let snapshot = collector.snapshot();
|
||||||
assert_eq!(snapshot.rtt.primary.stats.count, 4104);
|
assert_eq!(snapshot.rtt.primary.count, 4104);
|
||||||
assert_eq!(snapshot.ipdv.round_trip.stats.count, 4103);
|
assert_eq!(snapshot.ipdv.round_trip.count, 4103);
|
||||||
assert_eq!(snapshot.rtt.primary.median_ns, None);
|
assert_eq!(snapshot.rtt.primary.median_ns, None);
|
||||||
assert_eq!(snapshot.ipdv.round_trip.median_ns, None);
|
assert_eq!(snapshot.ipdv.round_trip.median_ns, None);
|
||||||
}
|
}
|
||||||
@@ -42,10 +42,10 @@ fn cumulative_rtt_uses_signed_effective_and_tracks_raw() {
|
|||||||
collector.process(&reply(1, 10, 8));
|
collector.process(&reply(1, 10, 8));
|
||||||
|
|
||||||
let snapshot = collector.snapshot();
|
let snapshot = collector.snapshot();
|
||||||
assert_eq!(snapshot.rtt.primary.stats.count, 2);
|
assert_eq!(snapshot.rtt.primary.count, 2);
|
||||||
assert_eq!(snapshot.rtt.primary.stats.min_ns, Some(-2_000_000));
|
assert_eq!(snapshot.rtt.primary.min_ns, Some(-2_000_000));
|
||||||
assert_eq!(snapshot.rtt.primary.median_ns, Some(3_000_000.0));
|
assert_eq!(snapshot.rtt.primary.median_ns, Some(3_000_000.0));
|
||||||
assert_eq!(snapshot.rtt.raw.stats.total_ns, 11_000_000);
|
assert_eq!(snapshot.rtt.raw.total_ns, 11_000_000);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
@@ -68,7 +68,7 @@ fn late_unique_counts_and_duplicates_do_not_update_measurements() {
|
|||||||
assert_eq!(snapshot.packets.unique_replies, 2);
|
assert_eq!(snapshot.packets.unique_replies, 2);
|
||||||
assert_eq!(snapshot.packets.duplicates, 1);
|
assert_eq!(snapshot.packets.duplicates, 1);
|
||||||
assert_eq!(snapshot.packets.late_packets, 1);
|
assert_eq!(snapshot.packets.late_packets, 1);
|
||||||
assert_eq!(snapshot.rtt.primary.stats.count, 2);
|
assert_eq!(snapshot.rtt.primary.count, 2);
|
||||||
assert_eq!(snapshot.loss.lost_packets, 0);
|
assert_eq!(snapshot.loss.lost_packets, 0);
|
||||||
assert_eq!(snapshot.loss.duplicate_percent, 100.0 / 3.0);
|
assert_eq!(snapshot.loss.duplicate_percent, 100.0 / 3.0);
|
||||||
}
|
}
|
||||||
@@ -126,8 +126,8 @@ fn ipdv_is_sequence_adjacent_and_gap_preserving() {
|
|||||||
|
|
||||||
assert!(adjacent.contributed_sample);
|
assert!(adjacent.contributed_sample);
|
||||||
assert_one_ipdv_pair(&adjacent, 2, 3, Duration::from_millis(3));
|
assert_one_ipdv_pair(&adjacent, 2, 3, Duration::from_millis(3));
|
||||||
assert_eq!(snapshot.ipdv.round_trip.stats.count, 1);
|
assert_eq!(snapshot.ipdv.round_trip.count, 1);
|
||||||
assert_eq!(snapshot.ipdv.round_trip.stats.total_ns, 3_000_000);
|
assert_eq!(snapshot.ipdv.round_trip.total_ns, 3_000_000);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
@@ -141,8 +141,8 @@ fn late_reply_can_complete_ipdv_pair() {
|
|||||||
assert!(update.contributed_sample);
|
assert!(update.contributed_sample);
|
||||||
assert_one_ipdv_pair(&update, 0, 1, Duration::from_millis(10));
|
assert_one_ipdv_pair(&update, 0, 1, Duration::from_millis(10));
|
||||||
|
|
||||||
assert_eq!(snapshot.ipdv.round_trip.stats.count, 1);
|
assert_eq!(snapshot.ipdv.round_trip.count, 1);
|
||||||
assert_eq!(snapshot.ipdv.round_trip.stats.total_ns, 10_000_000);
|
assert_eq!(snapshot.ipdv.round_trip.total_ns, 10_000_000);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
@@ -184,8 +184,8 @@ fn gap_fill_update_exposes_both_completed_ipdv_pairs() {
|
|||||||
assert_eq!(fill.ipdv_pairs[1].rtt_ipdv, Duration::from_millis(7));
|
assert_eq!(fill.ipdv_pairs[1].rtt_ipdv, Duration::from_millis(7));
|
||||||
|
|
||||||
let snapshot = collector.snapshot();
|
let snapshot = collector.snapshot();
|
||||||
assert_eq!(snapshot.ipdv.round_trip.stats.count, 2);
|
assert_eq!(snapshot.ipdv.round_trip.count, 2);
|
||||||
assert_eq!(snapshot.ipdv.round_trip.stats.total_ns, 10_000_000);
|
assert_eq!(snapshot.ipdv.round_trip.total_ns, 10_000_000);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
@@ -208,7 +208,7 @@ fn server_processing_and_one_way_require_available_samples() {
|
|||||||
|
|
||||||
let snapshot = collector.snapshot();
|
let snapshot = collector.snapshot();
|
||||||
assert_eq!(snapshot.server_processing.processing.count, 1);
|
assert_eq!(snapshot.server_processing.processing.count, 1);
|
||||||
assert_eq!(snapshot.one_way_delay.send_delay.stats.count, 1);
|
assert_eq!(snapshot.one_way_delay.send_delay.count, 1);
|
||||||
assert_eq!(snapshot.events.untracked_late_replies, 1);
|
assert_eq!(snapshot.events.untracked_late_replies, 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -226,7 +226,7 @@ fn rolling_count_eviction_recomputes_from_bounded_events() {
|
|||||||
let rolling = collector.rolling_count().unwrap();
|
let rolling = collector.rolling_count().unwrap();
|
||||||
assert_eq!(rolling.packets.packets_sent, 0);
|
assert_eq!(rolling.packets.packets_sent, 0);
|
||||||
assert_eq!(rolling.packets.unique_replies, 2);
|
assert_eq!(rolling.packets.unique_replies, 2);
|
||||||
assert_eq!(rolling.rtt.primary.stats.count, 2);
|
assert_eq!(rolling.rtt.primary.count, 2);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
|||||||
Reference in new issue
Block a user