solana_measure/
measure.rs

1use std::{
2    fmt,
3    time::{Duration, Instant},
4};
5
6#[derive(Debug)]
7pub struct Measure {
8    name: &'static str,
9    start: Instant,
10    duration: u64,
11}
12
13impl Measure {
14    pub fn start(name: &'static str) -> Self {
15        Self {
16            name,
17            start: Instant::now(),
18            duration: 0,
19        }
20    }
21
22    pub fn stop(&mut self) {
23        self.duration = self.start.elapsed().as_nanos() as u64;
24    }
25
26    pub fn as_ns(&self) -> u64 {
27        self.duration
28    }
29
30    pub fn as_us(&self) -> u64 {
31        self.duration / 1000
32    }
33
34    pub fn as_ms(&self) -> u64 {
35        self.duration / (1000 * 1000)
36    }
37
38    pub fn as_s(&self) -> f32 {
39        self.duration as f32 / (1000.0f32 * 1000.0f32 * 1000.0f32)
40    }
41
42    pub fn as_duration(&self) -> Duration {
43        Duration::from_nanos(self.as_ns())
44    }
45
46    pub fn end_as_ns(self) -> u64 {
47        self.start.elapsed().as_nanos() as u64
48    }
49
50    pub fn end_as_us(self) -> u64 {
51        self.start.elapsed().as_micros() as u64
52    }
53
54    pub fn end_as_ms(self) -> u64 {
55        self.start.elapsed().as_millis() as u64
56    }
57
58    pub fn end_as_s(self) -> f32 {
59        self.start.elapsed().as_secs_f32()
60    }
61
62    pub fn end_as_duration(self) -> Duration {
63        self.start.elapsed()
64    }
65}
66
67impl fmt::Display for Measure {
68    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
69        if self.duration == 0 {
70            write!(f, "{} running", self.name)
71        } else if self.as_us() < 1 {
72            write!(f, "{} took {}ns", self.name, self.duration)
73        } else if self.as_ms() < 1 {
74            write!(f, "{} took {}us", self.name, self.as_us())
75        } else if self.as_s() < 1. {
76            write!(f, "{} took {}ms", self.name, self.as_ms())
77        } else {
78            write!(f, "{} took {:.1}s", self.name, self.as_s())
79        }
80    }
81}
82
83#[cfg(test)]
84mod tests {
85    use {super::*, std::thread::sleep};
86
87    #[test]
88    fn test_measure() {
89        let test_duration = Duration::from_millis(100);
90        let mut measure = Measure::start("test");
91        sleep(test_duration);
92        measure.stop();
93        assert!(measure.as_duration() >= test_duration);
94    }
95
96    #[test]
97    fn test_measure_as() {
98        let test_duration = Duration::from_millis(100);
99        let measure = Measure {
100            name: "test",
101            start: Instant::now(),
102            duration: test_duration.as_nanos() as u64,
103        };
104
105        assert!(f32::abs(measure.as_s() - 0.1f32) <= f32::EPSILON);
106        assert_eq!(measure.as_ms(), 100);
107        assert_eq!(measure.as_us(), 100_000);
108        assert_eq!(measure.as_ns(), 100_000_000);
109        assert_eq!(measure.as_duration(), test_duration);
110    }
111
112    #[test]
113    fn test_measure_display() {
114        let measure = Measure {
115            name: "test_ns",
116            start: Instant::now(),
117            duration: 1,
118        };
119        assert_eq!(format!("{measure}"), "test_ns took 1ns");
120
121        let measure = Measure {
122            name: "test_us",
123            start: Instant::now(),
124            duration: 1000,
125        };
126        assert_eq!(format!("{measure}"), "test_us took 1us");
127
128        let measure = Measure {
129            name: "test_ms",
130            start: Instant::now(),
131            duration: 1000 * 1000,
132        };
133        assert_eq!(format!("{measure}"), "test_ms took 1ms");
134
135        let measure = Measure {
136            name: "test_s",
137            start: Instant::now(),
138            duration: 1000 * 1000 * 1000,
139        };
140        assert_eq!(format!("{measure}"), "test_s took 1.0s");
141
142        let measure = Measure::start("test_not_stopped");
143        assert_eq!(format!("{measure}"), "test_not_stopped running");
144    }
145}