solana_measure/
measure.rs1use 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}