1use std::sync::Arc;
5use std::time::Duration;
6use std::time::Instant;
7
8use parking_lot::RwLock;
9use sketches_ddsketch::DDSketch;
10
11#[derive(Clone, Default)]
16pub struct Timer(Arc<RwLock<DDSketch>>);
17
18impl std::fmt::Debug for Timer {
19 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
20 f.debug_tuple("Timer").finish_non_exhaustive()
21 }
22}
23
24impl Timer {
25 pub(crate) fn new() -> Self {
26 Self(Default::default())
27 }
28
29 pub fn update(&self, duration: Duration) {
31 self.0.write().add(duration.as_secs_f64());
32 }
33
34 pub fn total(&self) -> Duration {
36 self.0
37 .read()
38 .sum()
39 .map(Duration::from_secs_f64)
40 .unwrap_or_default()
41 }
42
43 #[allow(clippy::expect_used)]
46 #[allow(clippy::unwrap_in_result)]
47 pub fn quantile(&self, quantile: f64) -> Option<Duration> {
48 assert!(
49 (0.0..=1.0).contains(&quantile),
50 "quantile must be between 0.0 and 1.0"
51 );
52
53 self.0
54 .read()
55 .quantile(quantile)
56 .expect("quantile range checked")
57 .map(Duration::from_secs_f64)
58 }
59
60 pub fn count(&self) -> usize {
62 self.0.read().count()
63 }
64
65 pub fn is_empty(&self) -> bool {
67 self.0.read().count() == 0
68 }
69
70 pub fn time(&self) -> TimeGuard<'_> {
72 TimeGuard {
73 source: self,
74 start: Instant::now(),
75 }
76 }
77}
78
79pub struct TimeGuard<'a> {
81 source: &'a Timer,
82 start: Instant,
83}
84
85impl Drop for TimeGuard<'_> {
86 fn drop(&mut self) {
87 let elapsed = self.start.elapsed();
88 self.source.update(elapsed);
89 }
90}