pub struct StatsConfig {
pub samples: SampleMode,
pub rolling_count: Option<usize>,
pub rolling_time: Option<Duration>,
pub late_replies: LateReplyMode,
}Expand description
Configuration for statistics collection.
Fields§
§samples: SampleModeHow timing samples are retained, and so whether the cumulative snapshot reports medians.
rolling_count: Option<usize>Number of recent normalized events retained for count-based rolling snapshots.
A successful probe usually contributes two normalized events: one send event and one unique reply event.
rolling_time: Option<Duration>Time span of recent normalized events retained for time-based rolling snapshots.
This window has no item cap, even in continuous mode. Its memory depends on event volume inside the interval. Expiry occurs on insertion, anchored at the maximum observed normalized event timestamp, not when a snapshot is read. Events exactly at the cutoff are included. Backdated events cannot move the anchor backwards or restore expired history. Retained events are replayed in arrival order.
late_replies: LateReplyModeWhether matched late replies contribute measurements.
Implementations§
Source§impl StatsConfig
impl StatsConfig
Sourcepub fn finite() -> Self
pub fn finite() -> Self
Returns the default configuration for finite runs.
Finite mode retains exact samples for every timing metric, so each of them reports a median in the cumulative snapshot once it has samples, and keeps unbounded adjacent-sequence IPDV tracking so late adjacent replies can still complete IPDV pairs.
§Example
use irtt_stats::{StatsCollector, StatsConfig};
let mut collector = StatsCollector::new(StatsConfig::finite());
for (seq, send_call_us) in [10_u64, 30, 20].into_iter().enumerate() {
collector.process(&sent(seq as u32, seq as u64 * 10, send_call_us));
}
let snapshot = collector.snapshot();
// Finite mode retains exact samples, so the send-call metric reports an
// exact median once it has samples: the middle of the sorted
// 10, 20, 30 µs values, not their mean.
assert_eq!(snapshot.send_call.count, 3);
assert_eq!(snapshot.send_call.median_ns, Some(20_000.0));Sourcepub fn continuous() -> Self
pub fn continuous() -> Self
Returns a configuration for long-running use.
Continuous mode uses running statistics, retains no exact samples so no
timing metric reports a median, and bounds adjacent-sequence IPDV
tracking for long-running sessions. An explicitly enabled rolling_time
window is not hard-bounded; use rolling_count for bounded event storage.
§Example
use irtt_stats::{StatsCollector, StatsConfig};
let mut collector = StatsCollector::new(StatsConfig::continuous());
for seq in 0..3 {
collector.process(&sent(seq, u64::from(seq) * 10, 10));
}
let snapshot = collector.snapshot();
// Continuous mode still tracks running statistics — count, mean, min,
// and max — but retains no exact samples, so it reports no median.
assert_eq!(snapshot.send_call.count, 3);
assert!(snapshot.send_call.mean_ns > 0.0);
assert_eq!(snapshot.send_call.median_ns, None);Sourcepub fn estimated_retained_bytes(&self, probe_count: u64) -> u64
pub fn estimated_retained_bytes(&self, probe_count: u64) -> u64
Returns an approximate estimate of the bytes a StatsCollector with
this configuration retains after processing probe_count probes.
This is a planning aid — it exists so callers can warn about a run before starting it — and deliberately not allocator accounting. It is derived from the structures this crate retains and a fixed capacity-headroom factor for the amortized-doubling containers those structures use, so it errs toward overestimating.
§What is included
- Exact timing samples, for every metric that retains them.
- Adjacent-sequence IPDV tracking state.
- Count-based rolling storage, when
StatsConfig::rolling_countis set, assuming a probe contributes one send event and one unique reply event.
§What is excluded
- Time-based rolling storage.
StatsConfig::rolling_timeretains whatever arrives inside its window, which cannot be bounded from a probe count alone without assuming traffic timing, so it does not contribute to this estimate. - Everything outside this crate: sockets, client session state, rendered output, and caller structures.
§Sample mode
SampleMode::Exact retains one value per timing metric per ordinary
successful probe and keeps unbounded IPDV state, so the estimate grows
with probe_count. SampleMode::RunningOnly retains no exact
samples and bounds its IPDV state, so the estimate reaches a ceiling
and stops growing.
§Optional measurements
Adjusted RTT, one-way delay, send/receive IPDV, and server processing are only measured when the negotiated session supplies the necessary timestamps. The estimate assumes all of them are available, which is the upper bound.
§Saturation
The result is deterministic and computed with saturating arithmetic, so
an enormous probe_count saturates at u64::MAX rather than
wrapping or panicking.
§Example
use irtt_stats::StatsConfig;
// Finite retention grows with the probe count...
let finite = StatsConfig::finite();
assert!(
finite.estimated_retained_bytes(1_000_000)
> finite.estimated_retained_bytes(1_000)
);
// ...while continuous retention is bounded, so a far longer run is no
// more expensive.
let continuous = StatsConfig::continuous();
assert_eq!(
continuous.estimated_retained_bytes(1_000_000),
continuous.estimated_retained_bytes(10_000_000),
);
assert!(
continuous.estimated_retained_bytes(1_000_000)
< finite.estimated_retained_bytes(1_000_000)
);
// Enormous probe counts saturate rather than wrapping or panicking.
assert_eq!(finite.estimated_retained_bytes(u64::MAX), u64::MAX);