High Dynamic Range Histogram implementation in Zig.
A Histogram that supports recording and analyzing sampled data value counts across a configurable integer value range with configurable value precision within the range. Value precision is expressed as the number of significant digits in the value recording, and provides control over value quantization behavior across the value range and the subsequent value resolution at any given level.
This implementation provides static struct type, which size is computed in
comptime.
const HdrHistogram = @import("hdrhistogram").HdrHistogram;
pub fn main() void {
std.debug.print("Size of plain array : {d:12} bytes\n", .{@sizeOf([10_000_000_000]u64)});
std.debug.print("Size of HdrHistogram : {d:12} bytes\n", .
{@sizeOf(HdrHistogram(1, 10_000_000_000, .three_digits))
});
/// Size of plain array : 80000000000 bytes
/// Size of HdrHistogram : 204808 bytes
}Many methods are absent yet, but most common are implemented.
total_countmin()max()mean()stdDev()percentiles(&.{...})
To iterate over all counts with their lowers and highest equivalent values:
var iter = h.iterator();
while (iter.next()) |bucket| {
std.debug.print("count={d} in {d}..{d} range\n", .{
bucket.count,
bucket.lowest_equivalent_value,
bucket.highest_equivalent_value,
});
}You can use PercentileIterator wrapper to iterate over percentiles:
var iter = h.iterator().percentile();
while (iter.next()) |p| {
std.debug.print("value={d} in {d:.2}%\n", .{p.value, p.percentile});
}Use merge method to add data from one histogram to another.
const other1: HdrHistogram(1, 10_000_000_000, .three_digits);
const other2: HdrHistogram(1, 10_000_000_000, .three_digits);
var sum: HdrHistogram(1, 10_000_000_000, .three_digits) = .init();
sum.merge(other1);
sum.merge(other2);Inserting 10_000_000 records in a for-loop:
Benchmark 1 (460 runs): ./bench/c-recording/zig-out/bin/c_recording
measurement mean ± σ min … max outliers delta
wall_time 21.7ms ± 7.61ms 19.9ms … 183ms 5 ( 1%) 0%
peak_rss 2.05MB ± 61.4KB 1.77MB … 2.23MB 174 (38%) 0%
cpu_cycles 94.5M ± 37.0M 91.8M … 885M 28 ( 6%) 0%
instructions 520M ± 8.56 520M … 520M 10 ( 2%) 0%
cache_references 59.5K ± 821K 16.9K … 17.6M 58 (13%) 0%
cache_misses 5.18K ± 279 4.70K … 6.41K 65 (14%) 0%
branch_misses 3.62K ± 30.7 3.57K … 4.04K 11 ( 2%) 0%
Benchmark 2 (1487 runs): ./bench/zig-recording/zig-out/bin/zig_recording
measurement mean ± σ min … max outliers delta
wall_time 6.69ms ± 460us 5.87ms … 9.33ms 63 ( 4%) ⚡- 69.2% ± 1.8%
peak_rss 815KB ± 8.06KB 659KB … 815KB 4 ( 0%) ⚡- 60.2% ± 0.2%
cpu_cycles 26.6M ± 127K 26.5M … 27.6M 128 ( 9%) ⚡- 71.9% ± 2.0%
instructions 114M ± 1.65 114M … 114M 18 ( 1%) ⚡- 78.1% ± 0.0%
cache_references 6.13K ± 585 5.33K … 19.0K 41 ( 3%) ⚡- 89.7% ± 70.2%
cache_misses 156 ± 104 50 … 1.85K 87 ( 6%) ⚡- 97.0% ± 0.3%
branch_misses 122 ± 6.67 83 … 146 104 ( 7%) ⚡- 96.6% ± 0.0%
Run make bench-poop or make bench-hyperfine to start benchmarks.