pub struct MeasurementHistogram<const N: usize> { /* private fields */ }Expand description
Canonical shared arithmetic for local diagnostic summaries and distributions.
Re-exported so callers can name returned summaries without selecting a separate Metrics dependency. This is the shared type, with no local wrapper or arithmetic. Fixed-size histogram of observations in one consumer-selected unit.
N strictly increasing inclusive upper bounds define N disjoint buckets.
The first bucket includes zero; later buckets exclude the preceding bound.
Values above the last bound go into a separate overflow bucket. With no
bounds, every observation goes into overflow. A final bound of u64::MAX
is valid and leaves overflow empty.
Each observation updates one bucket and the accompanying
MeasurementAggregate. Counts clip independently at u64::MAX, with sticky
flags for actual overflow; exactly reached caps remain exact. Unsaturated
bucket counts remain useful after the aggregate’s total overflows. Overflow
can prevent bucket counts from summing to the aggregate’s sample count.
Buckets describe ranges, not exact percentiles; no latest value is retained.
Storage is fixed arrays, overflow state and one aggregate, with no heap
allocation. Recording searches at most N bounds. Consumers choose bounds,
units, sample admission, identity and reset boundaries. Bounds are immutable
after construction; report encoding and persistence remain consumer-owned.
use ic_metrics::MeasurementHistogram;
let mut histogram = MeasurementHistogram::new([10, 100])?;
for value in [0, 10, 11, 101] {
histogram.record(value);
}
assert_eq!(histogram.bucket_counts(), &[2, 1]);
assert_eq!(histogram.overflow(), 1);
assert_eq!(histogram.aggregate().samples(), 4);Implementations§
Source§impl<const N: usize> MeasurementHistogram<N>
impl<const N: usize> MeasurementHistogram<N>
Sourcepub const fn new(
upper_bounds: [u64; N],
) -> Result<MeasurementHistogram<N>, HistogramBoundsError>
pub const fn new( upper_bounds: [u64; N], ) -> Result<MeasurementHistogram<N>, HistogramBoundsError>
Construct an empty histogram with inclusive upper bounds.
Bounds and observations must use the same unit. A bound of zero and an empty bounds array are valid.
§Errors
Returns HistogramBoundsError for the first duplicate or descending
bound. The error identifies the right-hand bound in that pair.
Sourcepub const fn record(&mut self, value: u64)
pub const fn record(&mut self, value: u64)
Record one completed observation, including zero.
Updates the aggregate and exactly one disjoint bucket. Every observation must use the same unit as the bounds and earlier observations.
Sourcepub const fn upper_bounds(&self) -> &[u64; N]
pub const fn upper_bounds(&self) -> &[u64; N]
Immutable inclusive upper bounds corresponding to Self::bucket_counts.
Sourcepub const fn bucket_counts(&self) -> &[u64; N]
pub const fn bucket_counts(&self) -> &[u64; N]
Disjoint bucket counts, each saturating independently at u64::MAX.
These exclude overflow and are not cumulative counts. Inspect
Self::bucket_saturation before using clipped counts as exact values.
Sourcepub const fn overflow(&self) -> u64
pub const fn overflow(&self) -> u64
Count above the last bound, saturating independently at u64::MAX.
With no bounds, this counts all observations. Inspect
Self::overflow_saturated before treating the clipped count as exact.
Sourcepub const fn bucket_saturation(&self) -> &[bool; N]
pub const fn bucket_saturation(&self) -> &[bool; N]
Sticky actual-overflow flags corresponding to Self::bucket_counts.
Sourcepub const fn overflow_saturated(&self) -> bool
pub const fn overflow_saturated(&self) -> bool
Whether the overflow bucket’s count has actually overflowed.
Sourcepub const fn aggregate(&self) -> MeasurementAggregate
pub const fn aggregate(&self) -> MeasurementAggregate
Mergeable aggregate of all observations, including overflow.
Sourcepub const fn merge(
&mut self,
other: &MeasurementHistogram<N>,
) -> Result<(), HistogramMergeError>
pub const fn merge( &mut self, other: &MeasurementHistogram<N>, ) -> Result<(), HistogramMergeError>
Combine a distribution with exactly the same finite bounds.
Consumers establish matching units and deliberate sample attribution. This adds observations without deduplication or ordering. Source overflow propagates independently for each count and the aggregate.
§Errors
Returns HistogramMergeError for the first differing bound, leaving
the entire destination unchanged. Different bound counts are different
Rust types and cannot be merged.
Sourcepub const fn cumulative_count(
&self,
index: usize,
) -> Result<u64, HistogramQueryError>
pub const fn cumulative_count( &self, index: usize, ) -> Result<u64, HistogramQueryError>
Count observations at or below the finite upper bound at index.
Sums disjoint buckets through that index, excluding overflow. Empty histograms return zero for valid indices. Later buckets, overflow and aggregate saturation do not invalidate an otherwise exact prefix count. Arbitrary thresholds inside a bucket cannot be answered exactly.
§Errors
Returns HistogramQueryError::BucketOutOfBounds when index >= N, or
HistogramQueryError::SaturatedCount when a contributing count or sum
has actually overflowed; an exactly reached u64::MAX is valid.
Sourcepub const fn quantile_bucket(
&self,
numerator: u64,
denominator: u64,
) -> Result<Option<HistogramRange>, HistogramQueryError>
pub const fn quantile_bucket( &self, numerator: u64, denominator: u64, ) -> Result<Option<HistogramRange>, HistogramQueryError>
Locate the bucket containing the nearest-rank quantile numerator / denominator.
The one-based rank is ceil(samples * numerator / denominator), with
0 < numerator <= denominator. Returns None for no observations and
otherwise a range, including overflow. It never interpolates an exact
percentile value. Recording and retained state are unchanged.
§Errors
Returns HistogramQueryError::InvalidQuantile first for an invalid
fraction, or HistogramQueryError::SaturatedCount if the sample count
or any bucket count has actually overflowed. A saturated value total does not
invalidate a distribution whose counts remain exact.
use ic_metrics::MeasurementHistogram;
let mut histogram = MeasurementHistogram::new([10, 100])?;
for value in [0, 10, 11, 101] { histogram.record(value); }
assert_eq!(histogram.cumulative_count(0)?, 2);
let median = histogram.quantile_bucket(1, 2)?.unwrap();
assert_eq!(median.upper_inclusive(), Some(10));
assert_eq!(histogram.quantile_bucket(95, 100)?.unwrap().upper_inclusive(), None);Trait Implementations§
Source§impl<const N: usize> Clone for MeasurementHistogram<N>
impl<const N: usize> Clone for MeasurementHistogram<N>
Source§fn clone(&self) -> MeasurementHistogram<N>
fn clone(&self) -> MeasurementHistogram<N>
1.0.0 (const: unstable) · Source§fn clone_from(&mut self, source: &Self)
fn clone_from(&mut self, source: &Self)
source. Read more