benchmark_rs/
stopwatch.rs

1use std::fmt::{Display, Formatter};
2use std::ops::AddAssign;
3use std::time::{Duration, Instant};
4
5use chrono::{DateTime, Utc};
6
7/// Measure elapsed time
8pub struct StopWatch {
9    accumulated: Duration,
10    checkpoint: Instant,
11    is_stopped: bool,
12}
13
14impl StopWatch {
15    /// Create a new [StopWatch]
16    pub fn new() -> StopWatch {
17        StopWatch {
18            accumulated: Duration::from_secs(0),
19            checkpoint: Instant::now(),
20            is_stopped: true,
21        }
22    }
23
24    /// Start duration measurement
25    pub fn start(&mut self) {
26        if self.is_stopped {
27            self.checkpoint = Instant::now();
28            self.is_stopped = false;
29        }
30    }
31
32    /// Resume duration measurement
33    pub fn resume(&mut self) {
34        self.start()
35    }
36
37    /// Reset duration measurement
38    pub fn reset(&mut self) {
39        self.accumulated = Duration::from_secs(0);
40        self.checkpoint = Instant::now();
41        self.is_stopped = true
42    }
43
44    /// Stop duration measurement
45    pub fn stop(&mut self) {
46        if !self.is_stopped {
47            self.accumulated.add_assign(Duration::from_nanos(
48                self.checkpoint.elapsed().as_nanos() as u64
49            ));
50            self.is_stopped = true;
51        }
52    }
53
54    /// Pause duration measurement
55    pub fn pause(&mut self) {
56        self.stop()
57    }
58
59    /// Get accumulated duration
60    pub fn accumulated(&self) -> Duration {
61        self.accumulated
62    }
63}
64
65impl Display for StopWatch {
66    /// Format accumulated duration as time
67    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
68        let mut accumulated = self.accumulated;
69        if !self.is_stopped {
70            accumulated.add_assign(Duration::from_nanos(
71                self.checkpoint.elapsed().as_nanos() as u64
72            ));
73        }
74        let datetime = DateTime::<Utc>::from_timestamp(
75            accumulated.as_secs() as i64,
76            accumulated.subsec_nanos(),
77        )
78        .unwrap();
79        let formatted_time = datetime.format("%H:%M:%S.%3f").to_string();
80        f.write_fmt(format_args!("{}", formatted_time))
81    }
82}
83
84impl Default for StopWatch {
85    fn default() -> Self {
86        Self::new()
87    }
88}
89
90#[cfg(test)]
91mod tests {
92    use std::thread;
93    use std::time::Duration;
94
95    use super::*;
96
97    #[test]
98    fn test_pause() {
99        let mut stop_watch = StopWatch::new();
100        stop_watch.resume();
101        thread::sleep(Duration::from_millis(3));
102        stop_watch.pause();
103        thread::sleep(Duration::from_millis(3));
104        stop_watch.resume();
105        assert!(stop_watch.accumulated() >= Duration::from_millis(3));
106        assert!(stop_watch.accumulated() <= Duration::from_millis(6));
107    }
108
109    #[test]
110    fn test_stopwatch() {
111        let mut stopwatch = StopWatch::new();
112        assert_eq!("00:00:00.000", stopwatch.to_string());
113        stopwatch.start();
114        thread::sleep(Duration::from_millis(3));
115        assert!("00:00:00.003".to_string() <= stopwatch.to_string());
116        thread::sleep(Duration::from_millis(1000));
117        assert!("00:00:01.003".to_string() <= stopwatch.to_string());
118    }
119}