refactor(stats): retain exact finite timing samples
`SampleMode::Exact` retained exact samples for eight of the eleven public timing metrics. Send call, timer error, and server processing always built their `TimeMetric` with retention disabled, so a finite run reported no median for them even though they are the same public `TimeStats` type and appear in the same summary table with a Median column. Derive one `retain_exact` decision from the sample mode in `CoreStats::new` and apply it to every timing metric, so exact mode means the same thing for all of them. Running-only mode is unchanged and still retains none of them. The retention estimator counted eight exact sample streams per measurable reply. Rename it to the eleven exact samples an ordinary successful probe can retain and document the wider optional-measurement upper bound, which raises the finite estimate on this target from 668 to 764 bytes per probe. A test counts the metrics a fully measured probe actually retains and compares it against that constant, so retention and its estimate cannot drift apart unnoticed. No new median-capability type was needed: `TimeStats::median_ns` already distinguishes a retained median from an absent one, and an optional measurement the server never supplied still produces no samples at all.
This commit is contained in:
8 files changed
+491
-44
No files matched your search
@@ -28,7 +28,7 @@ pub use time_stats::TimeStats;
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
||||
/// Configuration for statistics collection.
|
||||
pub struct StatsConfig {
|
||||
/// How timing samples are retained for median-capable metrics.
|
||||
/// How timing samples are retained, and so whether medians are available.
|
||||
pub samples: SampleMode,
|
||||
/// Number of recent normalized events retained for count-based rolling snapshots.
|
||||
///
|
||||
@@ -44,9 +44,10 @@ pub struct StatsConfig {
|
||||
impl StatsConfig {
|
||||
/// Returns the default configuration for finite runs.
|
||||
///
|
||||
/// Finite mode retains exact samples where needed for medians and keeps
|
||||
/// unbounded adjacent-sequence IPDV tracking so late adjacent replies can
|
||||
/// still complete IPDV pairs.
|
||||
/// Finite mode retains exact samples for every timing metric, so each of
|
||||
/// them reports a median once it has samples, and keeps unbounded
|
||||
/// adjacent-sequence IPDV tracking so late adjacent replies can still
|
||||
/// complete IPDV pairs.
|
||||
pub fn finite() -> Self {
|
||||
Self {
|
||||
samples: SampleMode::Exact,
|
||||
@@ -58,9 +59,9 @@ impl StatsConfig {
|
||||
|
||||
/// Returns a configuration for long-running use.
|
||||
///
|
||||
/// Continuous mode uses running statistics, does not retain exact samples
|
||||
/// for medians, and bounds adjacent-sequence IPDV tracking for long-running
|
||||
/// sessions.
|
||||
/// 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.
|
||||
pub fn continuous() -> Self {
|
||||
Self {
|
||||
samples: SampleMode::RunningOnly,
|
||||
@@ -81,7 +82,7 @@ impl StatsConfig {
|
||||
///
|
||||
/// # What is included
|
||||
///
|
||||
/// - Exact timing samples, for the metrics that retain them.
|
||||
/// - Exact timing samples, for every metric that retains them.
|
||||
/// - Adjacent-sequence IPDV tracking state.
|
||||
/// - Count-based rolling storage, when [`StatsConfig::rolling_count`] is
|
||||
/// set, assuming a probe contributes one send event and one unique
|
||||
@@ -98,17 +99,18 @@ impl StatsConfig {
|
||||
///
|
||||
/// # Sample mode
|
||||
///
|
||||
/// [`SampleMode::Exact`] retains one value per metric per measurable
|
||||
/// reply 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.
|
||||
/// [`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, and send/receive IPDV are only measured
|
||||
/// when the negotiated session supplies the necessary timestamps. The
|
||||
/// estimate assumes all of them are available, which is the upper bound.
|
||||
/// 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
|
||||
///
|
||||
@@ -151,10 +153,16 @@ impl Default for StatsConfig {
|
||||
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
||||
/// Controls whether exact timing samples are retained.
|
||||
///
|
||||
/// The choice applies uniformly to every timing metric a [`Snapshot`] exposes,
|
||||
/// so a snapshot never mixes median-capable and median-incapable timing
|
||||
/// metrics.
|
||||
pub enum SampleMode {
|
||||
/// Keep only running statistics; exact medians are not available.
|
||||
/// Keep only running statistics; medians are not available for any timing
|
||||
/// metric, and retention stays bounded for long-running sessions.
|
||||
RunningOnly,
|
||||
/// Retain exact samples for metrics that report exact medians.
|
||||
/// Retain exact samples for every timing metric, so each one reports a
|
||||
/// median once it has samples. Retention grows with the probe count.
|
||||
Exact,
|
||||
}
|
||||
|
||||
|
||||
Reference in new issue
Block a user