seq_timer/
lib.rs

1//! A simple timer for sequential events
2//!
3//! ```rust
4//! use std::{ time::Duration, thread::sleep };
5//!
6//! let mut timer = seq_timer::Timer::new();
7//!
8//! // starts the first event
9//! timer.start("the first event");
10//! sleep(Duration::from_millis(1));
11//!
12//! // finishes the first event and starts the second one
13//! // you can also `.finish()` the current event manually
14//! timer.start("the second event");
15//! sleep(Duration::from_millis(10));
16//!
17//! // finishes the last event and prints sorted measurments to stdout:
18//! timer.print();
19//! ```
20//! The output would be similar to:
21//! ```text
22//! the second event | 10078204 ns |  88%
23//!  the first event |  1265423 ns |  11%
24//! ```
25//! The timer also implements [Display](core::fmt::Display), but you must
26//! finish the last event manually in this case: `debug!("{}", timer.finish())`
27use std::{
28    fmt,
29    time::{Duration, Instant},
30};
31
32#[derive(Default)]
33pub struct Timer {
34    /// Event names
35    names: Vec<&'static str>,
36    /// Event durations
37    durations: Vec<Duration>,
38    /// Current event started
39    started: Option<Instant>,
40}
41
42impl Timer {
43    pub fn new() -> Self {
44        Default::default()
45    }
46
47    /// Finishes the current event if necessary and starts a new event
48    pub fn start(&mut self, name: &'static str) {
49        self.finish();
50        self.names.push(name);
51        self.started = Some(Instant::now());
52    }
53
54    /// Finishes the current event
55    pub fn finish(&mut self) -> &Self {
56        if let Some(started) = self.started {
57            self.durations.push(started.elapsed());
58            self.started = None;
59        }
60        self
61    }
62
63    /// Finishes the last event and prints the result
64    pub fn print(&mut self) {
65        self.finish();
66        println!("{self}");
67    }
68
69    /// Return the length of the longest name
70    fn max_name_len(&self) -> usize {
71        self.names.iter().map(|x| x.len()).max().unwrap_or_default()
72    }
73
74    /// Return the length of the longest name
75    fn max_duration_len(&self) -> usize {
76        self.durations
77            .iter()
78            .max()
79            .unwrap_or(&Duration::ZERO)
80            .as_nanos()
81            .to_string()
82            .len()
83    }
84
85    /// The total time all events took
86    fn total_duration(&self) -> Duration {
87        self.durations.iter().sum()
88    }
89}
90
91impl fmt::Display for Timer {
92    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
93        let max_name = self.max_name_len();
94        let max_duration = self.max_duration_len();
95        let total_duration = self.total_duration().as_nanos();
96        let mut sorted_durations: Vec<_> = self.names.iter().zip(&self.durations).collect();
97        sorted_durations.sort_by(|a, b| b.1.cmp(a.1));
98        for (name, duration) in sorted_durations {
99            let d = duration.as_nanos();
100            let percent = d * 100 / total_duration;
101            writeln!(
102                f,
103                "{:>max_name$} | {:>max_duration$} ns | {:>3}%",
104                name, d, percent
105            )?;
106        }
107        if self.started.is_some() {
108            writeln!(
109                f,
110                "WARNING: timer event `{}` has not been finished properly, run `Timer::finish()`",
111                self.names.iter().last().unwrap_or(&"")
112            )?;
113        }
114        Ok(())
115    }
116}