krabka_bench_driver/
hist.rs1use {
12 crate::scenario::LatencyPercentiles,
13 hdrhistogram::{CreationError, Histogram},
14 krabka_units::prelude::*,
15};
16
17pub fn new() -> Result<Histogram<u64>, CreationError> {
25 Histogram::<u64>::new_with_bounds(1, 60_000_000, 3)
26}
27
28pub fn record(h: &mut Histogram<u64>, latency: Time) {
31 let micros = u64::try_from(latency.micros_i64()).unwrap_or_default();
32 let _ = h.record(micros.clamp(1, h.high()));
33}
34
35#[must_use]
37pub fn percentiles(h: &Histogram<u64>) -> LatencyPercentiles {
38 let at = |quantile: f64| Time::from_micros(saturating_micros(h.value_at_quantile(quantile)));
39 LatencyPercentiles {
40 p50: at(0.50),
41 p95: at(0.95),
42 p99: at(0.99),
43 p999: at(0.999),
44 max: Time::from_micros(saturating_micros(h.max())),
45 mean: micros(1) * h.mean(),
46 count: h.len(),
47 }
48}
49
50fn saturating_micros(value: u64) -> i64 { i64::try_from(value).unwrap_or(i64::MAX) }
53
54#[cfg(test)]
55mod tests {
56 use {super::*, assert2::check};
57
58 #[test]
59 fn percentiles_report_recorded_extents() {
60 let mut h = new().unwrap();
61 for v in [millis(1), millis(2), millis(3), millis(4), millis(5)] {
62 record(&mut h, v);
63 }
64 let p = percentiles(&h);
65 check!(p.count == 5);
66 check!(p.p50 > Time::ZERO);
67 check!(p.max >= p.p99);
68 check!((p.max - millis(5)).secs_f64().abs() < millis(1).secs_f64() * 0.01);
70 check!((p.mean - millis(3)).secs_f64().abs() < millis(1).secs_f64() * 0.01);
71 }
72
73 #[test]
74 fn sub_millisecond_latencies_keep_their_resolution() {
75 let mut h = new().unwrap();
76 record(&mut h, micros(250));
77 let p = percentiles(&h);
78 check!(p.p50 >= micros(240));
79 check!(p.p50 <= micros(260));
80 }
81
82 #[test]
83 fn clamps_above_max_into_range() {
84 let mut h = new().unwrap();
85 record(&mut h, days(1));
86 check!(h.len() == 1);
87 }
88
89 #[test]
90 fn clamps_below_min_into_range() {
91 let mut h = new().unwrap();
92 record(&mut h, Time::ZERO);
93 check!(h.len() == 1);
94 }
95}