1use std::{
28 fmt,
29 time::{Duration, Instant},
30};
31
32#[derive(Default)]
33pub struct Timer {
34 names: Vec<&'static str>,
36 durations: Vec<Duration>,
38 started: Option<Instant>,
40}
41
42impl Timer {
43 pub fn new() -> Self {
44 Default::default()
45 }
46
47 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 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 pub fn print(&mut self) {
65 self.finish();
66 println!("{self}");
67 }
68
69 fn max_name_len(&self) -> usize {
71 self.names.iter().map(|x| x.len()).max().unwrap_or_default()
72 }
73
74 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 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}