1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
//! A simple wrapper around [`hdrhistogram::Histogram`] for latency measurements.
use std::time::Duration;
use hdrhistogram::{Histogram, RecordError};
pub(crate) const PERCENTAGES: &[f64] = &[10.0, 25.0, 50.0, 75.0, 90.0, 95.0, 99.0, 99.9, 99.99];
/// A simple wrapper around [`hdrhistogram::Histogram`] for latency measurements.
pub struct LatencyHistogram {
hist: Histogram<u64>,
}
impl LatencyHistogram {
/// Creates a new latency histogram.
pub fn new() -> LatencyHistogram {
Self { hist: Histogram::<u64>::new(3).expect("create histogram") }
}
/// Records a latency value.
pub fn record(&mut self, d: Duration) -> Result<(), RecordError> {
self.hist.record(d.as_nanos() as u64)
}
/// Returns true if this histogram has no recorded values.
pub fn is_empty(&self) -> bool {
self.hist.is_empty()
}
/// Get the highest recorded latency in the histogram.
pub fn max(&self) -> Duration {
Duration::from_nanos(self.hist.max())
}
/// Get the lowest recorded latency in the histogram.
pub fn min(&self) -> Duration {
Duration::from_nanos(self.hist.min())
}
/// Get the computed mean value of all recorded latencies in the histogram.
pub fn mean(&self) -> Duration {
Duration::from_nanos(self.hist.mean() as u64)
}
/// Get the computed standard deviation of all recorded latencies in the histogram.
pub fn stdev(&self) -> Duration {
Duration::from_nanos(self.hist.stdev() as u64)
}
/// Get the computed median value of all recorded latencies in the histogram.
pub fn median(&self) -> Duration {
self.value_at_quantile(0.5)
}
/// Get the latency at a given quantile.
pub fn value_at_quantile(&self, q: f64) -> Duration {
Duration::from_nanos(self.hist.value_at_quantile(q))
}
/// Iterate through histogram values by quantile levels.
///
/// See [`hdrhistogram::Histogram::iter_quantiles`] for more details.
pub fn quantiles(&self) -> impl Iterator<Item = (Duration, u64)> + '_ {
self.hist
.iter_quantiles(1)
.map(|t| {
(
Duration::from_nanos(t.value_iterated_to()),
t.count_since_last_iteration(),
)
})
.filter(|(_, n)| *n > 0)
}
/// Compute each latency value at the given percentages.
pub fn percentiles<'a>(&'a self, percentages: &'a [f64]) -> impl Iterator<Item = (f64, Duration)> + 'a {
percentages.iter().map(|&p| (p, self.value_at_quantile(p / 100.0)))
}
}
impl Default for LatencyHistogram {
fn default() -> Self {
Self::new()
}
}