downsample
no_std + alloc + no_deps storage for keeping downsampled metric history over long periods of time.
Provides a method to track data points over long time, aggregating them eventually to keep storage constant.
Downsampling is configured with Reducer<T>, a plain function pointer that receives one aggregation window as up to two slices.
The aggregation to the next level always happens when one full batch as configured is reached.
Fixed-frequency usage
#
#
Custom reducers
Reducers are regular functions that can do any work to reduce a large set of data points into a single data point.
use ;
use NonZeroUsize;
let nz = ;
let mut samples = new
.level
.build;
samples.push;
Built-in reducers include:
reducers::average_f32()andreducers::average_f64()- integer averages for common integer widths
reducers::min::<T>()reducers::max::<T>()reducers::median::<T>()forOrdvalues, returning the lower median for even windowsreducers::median_f32()andreducers::median_f64(), ignoringNaNvalues unless all values areNaNreducers::first::<T>()reducers::last::<T>()
The built-in reducers module is enabled by the default reducers feature.
Disable default features if you only use custom Reducer::new(...) functions.
Read/write split
FixedWriter<T> owns the writable storage and the reducer list. The read side is exposed as FixedStorage<T>.
// Continuing the fixed-frequency example above:
let storage = temperature.storage;
let metadata = storage.level_metadata.unwrap;
assert_eq!;
Benchmarks
Representative local results from cargo bench --bench mod -- --sample-size 10 --measurement-time 1 --warm-up-time 1.
The time column uses Criterion's middle estimate.
| Benchmark | Work | Time | Throughput |
|---|---|---|---|
push/single_steady_state_average |
one fixed-frequency push | 4.23 ns | - |
push/batch/day_history_average/100000 |
100,000 pushes with day-history levels | 263.71 us | 379.20 Melem/s |
push/batch/dense_rollover_average/100000 |
100,000 pushes with frequent rollovers | 478.36 us | 209.05 Melem/s |
read/indexed_level_lookup |
1,000,000 indexed level reads | 1.38 ms | 723.14 Melem/s |
reducers/median_f32/split_1024 |
median over a wrapped 1,024-value window | 1.65 us | 620.27 Melem/s |
Recorded on an AMD Ryzen 9 5900X 12-Core Processor.
Time-based direction
Time-series configuration uses caller-chosen integer ticks for time tracking. This is currently still "under construction".
#
#
The time-series module currently contains the integer-tick storage and writer configuration. Bucket rollover and aggregation policy still need to be completed.
Limitations
- Fixed-frequency bucket sizes must be known when the object is built.
- Fixed-frequency downsample factors are whole numbers: e.g. 100Hz -> 25Hz -> 5Hz is possible with factor 4 and 5, but 100Hz -> 25Hz -> 10Hz isn't as factor 2.5 is no integer.
- This crate is still
0.0.x; API changes are expected.