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