histogram
A collection of histogram data structures for Rust, providing standard, atomic, and sparse variants. Like HDRHistogram, values are stored in quantized buckets, but the bucket construction and indexing algorithm are modified for fast increments and lookups.
Getting Started
cargo add histogram
Usage
use ;
// Create a histogram with grouping power 7 and max value power 64.
let mut histogram = new.unwrap;
// Record some values.
for i in 1..=100
// Query quantiles using the 0.0..=1.0 scale.
let r50 = histogram.quantile.unwrap.unwrap;
let r99 = histogram.quantile.unwrap.unwrap;
// quantile() returns Result<Option<QuantilesResult>, Error>
// outer unwrap: quantile value is valid
// inner unwrap: histogram is non-empty
let median = r50.get.unwrap;
let p99 = r99.get.unwrap;
println!;
println!;
Histogram Types
- Histogram -- Standard histogram with plain 64-bit counters. Best for single-threaded use.
- AtomicHistogram -- Uses atomic 64-bit counters, allowing concurrent
recording from multiple threads. Take a snapshot via
load()ordrain()to query percentiles. - SparseHistogram -- Columnar representation that only stores non-zero buckets. Ideal for serialization and storage when most buckets are empty.
- CumulativeROHistogram -- Read-only histogram with cumulative counts for fast O(log n) quantile queries via binary search.
All four types ship with a *32 sibling (Histogram32, AtomicHistogram32,
SparseHistogram32, CumulativeROHistogram32) that uses 32-bit counters.
Counter Width
All four histogram types ship in two flavors:
- u64-counter family (
Histogram,AtomicHistogram,SparseHistogram,CumulativeROHistogram): the default. Counts up to 2^64 − 1 per bucket. - u32-counter siblings (
Histogram32,AtomicHistogram32,SparseHistogram32,CumulativeROHistogram32): half the memory and serialization size, counts up to 2^32 − 1 per bucket.
Pick the family based on the memory/range tradeoff. Conversions:
- Widening (
u32→u64) is infallible (From). - Narrowing (
u64→u32) is fallible (TryFrom, returnsErr(Overflow)). Direct cross-variant + narrowing paths support the snapshot pipeline.
Recommended Pipeline
Pick the histogram type based on the role it plays in your data flow:
- Recording —
AtomicHistogram(orHistogram). Use the u64-counter types for the long-running, continuously-updated histogram. Counts here are unbounded over the lifetime of the process;u64heads off any practical risk of overflow. - Snapshot delta —
Histogram, then narrowed. When you take periodic snapshots and compute a delta withchecked_sub, the delta covers only the activity in one window. UseHistogram::checked_subto compute the delta, thenTryFromto narrow into a*32type. - Read-only analytics —
CumulativeROHistogram32. This is the recommended storage and query format for completed snapshots. The cumulative-prefix-sum representation gives you O(log n) quantile queries via binary search, whileu32counts halve the on-the-wire and on-disk size versusu64. Narrowing is checked once against the total count (cheaper than per-bucket), and any total ≤ ~4.3B fits.
use ;
let recorder = new.unwrap;
# let snap_t0 = recorder.load;
let snap_t1 = recorder.load;
let delta = snap_t1.checked_sub.unwrap;
let analytic: CumulativeROHistogram32 =
try_from.unwrap;
If you don't take snapshots — i.e., you query the recording histogram directly — just stay on the u64 types everywhere. The narrowing optimization is specifically for the snapshot/delta pattern.
For JavaScript-frontend plotting specifically, prefer CumulativeROHistogram32 over a hypothetical f32-backed alternative: u32 is exact up to ~4.3B (vs f32 exact only to ~16M), and cumulative-monotonicity is structurally preserved (no rounding-induced plateau artifacts in ECDF rendering).
Features
serde-- EnablesSerializeandDeserializefor histogram types.schemars-- Enables JSON Schema generation (impliesserde).
Documentation
License
Licensed under either of Apache License, Version 2.0 or MIT license at your option.