witchcraft_metrics/
histogram.rs1use crate::{ExponentiallyDecayingReservoir, Reservoir, Snapshot};
15use std::sync::atomic::{AtomicU64, Ordering};
16
17pub struct Histogram {
22 count: AtomicU64,
23 reservoir: Box<dyn Reservoir>,
24}
25
26impl Default for Histogram {
27 #[inline]
28 fn default() -> Histogram {
29 Histogram::new(ExponentiallyDecayingReservoir::new())
30 }
31}
32
33impl Histogram {
34 pub fn new<R>(reservoir: R) -> Histogram
36 where
37 R: Reservoir,
38 {
39 Histogram {
40 count: AtomicU64::new(0),
41 reservoir: Box::new(reservoir),
42 }
43 }
44
45 #[inline]
47 pub fn update(&self, value: i64) {
48 self.count.fetch_add(1, Ordering::Relaxed);
49 self.reservoir.update(value);
50 }
51
52 #[inline]
54 pub fn count(&self) -> u64 {
55 self.count.load(Ordering::Relaxed)
56 }
57
58 #[inline]
60 pub fn snapshot(&self) -> Box<dyn Snapshot> {
61 self.reservoir.snapshot()
62 }
63}
64
65#[cfg(test)]
66mod test {
67 use crate::{Histogram, Reservoir, Snapshot};
68 use std::sync::atomic::{AtomicI64, Ordering};
69
70 struct TestReservoir(AtomicI64);
71
72 impl Reservoir for TestReservoir {
73 fn update(&self, value: i64) {
74 self.0.store(value, Ordering::SeqCst);
75 }
76
77 fn snapshot(&self) -> Box<dyn Snapshot> {
78 Box::new(TestSnapshot(self.0.load(Ordering::SeqCst)))
79 }
80 }
81
82 struct TestSnapshot(i64);
83
84 impl Snapshot for TestSnapshot {
85 fn value(&self, _: f64) -> f64 {
86 unimplemented!()
87 }
88
89 fn max(&self) -> i64 {
90 unimplemented!()
91 }
92
93 fn min(&self) -> i64 {
94 self.0
95 }
96
97 fn mean(&self) -> f64 {
98 unimplemented!()
99 }
100
101 fn stddev(&self) -> f64 {
102 unimplemented!()
103 }
104 }
105
106 #[test]
107 fn basic() {
108 let histogram = Histogram::new(TestReservoir(AtomicI64::new(0)));
109 assert_eq!(histogram.count(), 0);
110
111 histogram.update(15);
112 assert_eq!(histogram.count(), 1);
113 assert_eq!(histogram.snapshot().min(), 15);
114
115 histogram.update(10);
116 assert_eq!(histogram.count(), 2);
117 assert_eq!(histogram.snapshot().min(), 10);
118 }
119}