PhaseBucket

Struct PhaseBucket 

Source
pub struct PhaseBucket {
    pub step_index: u16,
    pub label: String,
    pub start_ms: u64,
    pub end_ms: u64,
    pub sample_count: usize,
    pub metrics: BTreeMap<String, f64>,
    pub per_cgroup: BTreeMap<String, PhaseCgroupStats>,
}
Expand description

Per-phase metric bucket — one entry per scenario phase in ScenarioStats::phases.

A scenario with N Steps yields N + 1 phases: phase 0 is the BASELINE (pre-first-Step settle window), and phases 1..=N correspond to Step 0..Step N-1 in scenario order. The 1-indexed Step encoding (instead of 0-indexed) lets BASELINE own step_index = 0 unambiguously — a step_index = 0 sample is always settle, not first-Step.

Each bucket carries the metric values reduced over the phase’s sample window. For crate::stats::MetricKind::Counter metrics the reduction is last - first across the phase’s periodic samples (cumulative-counter delta); for Gauge / Peak / Timestamp it dispatches per the kind via crate::stats::aggregate_samples. Missing metric keys mean the phase had no finite samples for that metric.

Metric keys match crate::stats::MetricDef::name — see crate::stats::METRICS for the canonical list of registered metric names a get / phase_metric lookup expects.

Fields§

§step_index: u16

Phase index. 0 = BASELINE (pre-first-Step settle window). 1..=N align with Step ordinals (1-indexed): Step 0 of the scenario lives at step_index = 1, Step 1 at step_index = 2, etc. The encoding avoids the collision where a 0-indexed Step would share step_index = 0 with the BASELINE settle window.

§label: String

Human-readable label. "BASELINE" for step_index = 0, "Step[0]" / "Step[1]" / … for step_index = 1..=N. Mirrors the formatting used by crate::timeline::Timeline’s phase rendering so operator inspection of the formatted diagnostic and the structured sidecar yield the same phase identifiers.

§start_ms: u64

Phase window start: the MINIMUM per-sample time anchor in the phase — each sample’s boundary_offset_ms, falling back to its elapsed_ms. Samples with neither anchor (both None — a not-measured timestamp) are excluded from the min.

§end_ms: u64

Phase window end: the MAXIMUM per-sample time anchor in the phase (the same boundary_offset_ms-or-elapsed_ms key as start_ms). A phase whose every sample is unanchored yields the inverted window (start_ms = u64::MAX, end_ms = 0), which folds no monitor samples. Downstream renderers should not assume the value is closed against a stimulus event.

§sample_count: usize

Number of periodic samples bucketed into this phase. Zero when the phase fired no captures: BASELINE when the settle window was shorter than the periodic interval, OR a synthesized capture-free interior step (the build_phase_buckets_with_stimulus seam — a StepStart-step whose window held no periodic boundary still gets a bucket so its capture-independent iteration_rate is not dropped).

§metrics: BTreeMap<String, f64>

Per-metric phase-aggregated values. See the PhaseBucket struct doc for the registry key source and per-kind reduction dispatch; missing keys mean the phase carried no finite samples for that metric (sentinel-free: None from the reducer surfaces as “key absent” rather than “value 0.0”).

§per_cgroup: BTreeMap<String, PhaseCgroupStats>

Per-cgroup raw telemetry components for this phase, keyed by cgroup name (see PhaseCgroupStats). Empty until a capture path populates it; the structural carrier for the per-phase per-cgroup distributional re-pool. Whole-run = aggregate of these per-phase per-cgroup components.

An ORPHAN bucket — a guest carrier whose step_index has NO paired host bucket (a dropped/absent StepStart frame, or a stimulus-less host/fixture path; NOT merely a short step, since build_phase_buckets_with_stimulus synthesizes a bucket for every StepStart so a captured-but-short step takes the matched arm) — is carried by fold_guest_per_cgroup_into_host_buckets with the shape (start_ms, end_ms) == (0, 0) AND empty metrics AND non-empty per_cgroup (it carries only these components). On every non-zero-duration window that shape is the orphan arm’s, so the timeline render keys on it to surface “window not measured” rather than a misleading 0ms (see crate::timeline::phase_from_bucket): a captured bucket has metrics. A zero-duration step at scenario start (StepStart==StepEnd==0) can also produce it via the matched arm, but harmlessly — a zero-duration step has no window, so “not measured” reads the same as “0ms”.

Implementations§

Source§

impl PhaseBucket

Source

pub fn get(&self, metric_name: &str) -> Option<f64>

Look up the phase-aggregated value for metric_name (see PhaseBucket::metrics for the registry source). Returns None when the phase carried no finite samples for that metric — distinct from Some(0.0) which means the reducer produced a real zero from finite samples.

Source

pub fn expect_metric(&self, metric_name: &str) -> f64

Like Self::get, but panics with a diagnostic message citing the bucket’s step_index + label + sample_count + the set of metric keys actually present when the metric is absent. Use when the caller knows the metric MUST be in the bucket (the phase fired samples and the metric is registered — see PhaseBucket::metrics) — the panic message tells the operator whether the cause is “phase produced no samples” (sample_count of 0) or “metric key typo” (positive sample_count but the key isn’t in metrics).

let bucket = r.stats.phase(Phase::step(0)).expect("Step[0] phase");
let throughput = bucket.expect_metric("throughput");
Source

pub fn cgroup_counter_total(&self, name: &str) -> Option<f64>

Cross-cgroup phase total for a per-cgroup Counter metric that lives in Self::per_cgroup but never in Self::metrics — currently "total_migrations", "total_iterations", and "total_cpu_time_ns".

These are registered MetricKind::Counters (crate::stats::METRICS) whose per-sample source is absent (crate::stats::MetricDef::read_sample returns None — they are per-task guest counters not captured per tick), so crate::assert::build_phase_buckets never folds them into metrics; only the per-cgroup carrier (PhaseCgroupStats, built by phase_cgroup_stats) holds them. This sums them across the phase’s per_cgroup carriers — the SAME cross-cgroup Counter sum ScenarioStats::total_migrations takes run-level and merge_matched_phase_buckets takes per key — so the value is the phase total, not a per-cgroup fragment.

None when the phase has no per_cgroup carriers (NOT measured — distinct from a measured Some(0.0) when carriers exist but counted zero) or name is not one of the per-cgroup-sourced counters. Surfacing them here never double-sources the run-level ext_metrics, but by two different mechanisms: total_migrations / total_iterations are in TYPED_FIELD_NAMES (populate_run_ext_metrics_from_phases skips them; the typed GauntletRow accessor stays the single run-level authority), while total_cpu_time_ns is NOT in TYPED_FIELD_NAMES — it is safe because it is never written into any pooled metrics map (its MetricDef accessor and read_sample both return None, so no run-level fold ever picks it up; it lives only on the per-cgroup carrier).

Counterpart to Self::get (which reads metrics only). crate::vmm::VmResult::phase_metric falls back to this so a post_vm callback reading phase_metric(phase, "total_migrations") gets the value instead of a silent None.

Trait Implementations§

Source§

impl Clone for PhaseBucket

Source§

fn clone(&self) -> PhaseBucket

Returns a duplicate of the value. Read more
1.0.0 · Source§

fn clone_from(&mut self, source: &Self)

Performs copy-assignment from source. Read more
Source§

impl Debug for PhaseBucket

Source§

fn fmt(&self, f: &mut Formatter<'_>) -> Result

Formats the value using the given formatter. Read more
Source§

impl Default for PhaseBucket

Source§

fn default() -> PhaseBucket

Returns the “default value” for a type. Read more
Source§

impl<'de> Deserialize<'de> for PhaseBucket

Source§

fn deserialize<__D>(__deserializer: __D) -> Result<Self, __D::Error>
where __D: Deserializer<'de>,

Deserialize this value from the given Serde deserializer. Read more
Source§

impl PartialEq for PhaseBucket

Source§

fn eq(&self, other: &PhaseBucket) -> bool

Tests for self and other values to be equal, and is used by ==.
1.0.0 · Source§

fn ne(&self, other: &Rhs) -> bool

Tests for !=. The default implementation is almost always sufficient, and should not be overridden without very good reason.
Source§

impl PhaseBucketClaim for PhaseBucket

Source§

fn claim_step_index<'a>( &'a self, verdict: &'a mut Verdict, ) -> ClaimBuilder<'a, u16>

Source§

fn claim_label<'a>( &'a self, verdict: &'a mut Verdict, ) -> ClaimBuilder<'a, String>

Source§

fn claim_start_ms<'a>( &'a self, verdict: &'a mut Verdict, ) -> ClaimBuilder<'a, u64>

Source§

fn claim_end_ms<'a>(&'a self, verdict: &'a mut Verdict) -> ClaimBuilder<'a, u64>

Source§

fn claim_sample_count<'a>( &'a self, verdict: &'a mut Verdict, ) -> ClaimBuilder<'a, usize>

Source§

impl Serialize for PhaseBucket

Source§

fn serialize<__S>(&self, __serializer: __S) -> Result<__S::Ok, __S::Error>
where __S: Serializer,

Serialize this value into the given Serde serializer. Read more
Source§

impl StructuralPartialEq for PhaseBucket

Auto Trait Implementations§

Blanket Implementations§

Source§

impl<T> Any for T
where T: 'static + ?Sized,

Source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
Source§

impl<T> Borrow<T> for T
where T: ?Sized,

Source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
Source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

Source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
Source§

impl<T> CloneToUninit for T
where T: Clone,

Source§

unsafe fn clone_to_uninit(&self, dest: *mut u8)

🔬This is a nightly-only experimental API. (clone_to_uninit)
Performs copy-assignment from self to dest. Read more
Source§

impl<T> From<T> for T

Source§

fn from(t: T) -> T

Returns the argument unchanged.

§

impl<T> Instrument for T

§

fn instrument(self, span: Span) -> Instrumented<Self>

Instruments this type with the provided [Span], returning an Instrumented wrapper. Read more
§

fn in_current_span(self) -> Instrumented<Self>

Instruments this type with the current Span, returning an Instrumented wrapper. Read more
Source§

impl<T, U> Into<U> for T
where U: From<T>,

Source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

Source§

impl<T> IntoEither for T

Source§

fn into_either(self, into_left: bool) -> Either<Self, Self>

Converts self into a Left variant of Either<Self, Self> if into_left is true. Converts self into a Right variant of Either<Self, Self> otherwise. Read more
Source§

fn into_either_with<F>(self, into_left: F) -> Either<Self, Self>
where F: FnOnce(&Self) -> bool,

Converts self into a Left variant of Either<Self, Self> if into_left(&self) returns true. Converts self into a Right variant of Either<Self, Self> otherwise. Read more
§

impl<T> Pointable for T

§

const ALIGN: usize

The alignment of pointer.
§

type Init = T

The type for initializers.
§

unsafe fn init(init: <T as Pointable>::Init) -> usize

Initializes a with the given initializer. Read more
§

unsafe fn deref<'a>(ptr: usize) -> &'a T

Dereferences the given pointer. Read more
§

unsafe fn deref_mut<'a>(ptr: usize) -> &'a mut T

Mutably dereferences the given pointer. Read more
§

unsafe fn drop(ptr: usize)

Drops the object pointed to by the given pointer. Read more
§

impl<T> PolicyExt for T
where T: ?Sized,

§

fn and<P, B, E>(self, other: P) -> And<T, P>
where T: Policy<B, E>, P: Policy<B, E>,

Create a new Policy that returns [Action::Follow] only if self and other return Action::Follow. Read more
§

fn or<P, B, E>(self, other: P) -> Or<T, P>
where T: Policy<B, E>, P: Policy<B, E>,

Create a new Policy that returns [Action::Follow] if either self or other returns Action::Follow. Read more
Source§

impl<T> Same for T

Source§

type Output = T

Should always be Self
Source§

impl<T> ToOwned for T
where T: Clone,

Source§

type Owned = T

The resulting type after obtaining ownership.
Source§

fn to_owned(&self) -> T

Creates owned data from borrowed data, usually by cloning. Read more
Source§

fn clone_into(&self, target: &mut T)

Uses borrowed data to replace owned data, usually by cloning. Read more
Source§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

Source§

type Error = Infallible

The type returned in the event of a conversion error.
Source§

fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>

Performs the conversion.
Source§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

Source§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
Source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.
§

impl<V, T> VZip<V> for T
where V: MultiLane<T>,

§

fn vzip(self) -> V

§

impl<T> WithSubscriber for T

§

fn with_subscriber<S>(self, subscriber: S) -> WithDispatch<Self>
where S: Into<Dispatch>,

Attaches the provided Subscriber to this type, returning a [WithDispatch] wrapper. Read more
§

fn with_current_subscriber(self) -> WithDispatch<Self>

Attaches the current default Subscriber to this type, returning a [WithDispatch] wrapper. Read more
Source§

impl<T> DeserializeOwned for T
where T: for<'de> Deserialize<'de>,

§

impl<T> MaybeSend for T
where T: Send,

§

impl<T> MaybeSend for T
where T: Send,