1use std::time::{Duration, Instant};
2use std::collections::HashMap;
3
4pub struct StopWatch {
6 last: Instant,
7 data: HashMap<String, Duration>,
8 keys: Vec<String>,
9 enabled: bool,
10 prints: bool,
11}
12
13impl StopWatch {
14 pub fn new(enabled: bool, prints: bool) -> Self {
16 StopWatch {
17 last: Instant::now(),
18 data: HashMap::new(),
19 keys: Vec::new(),
20 enabled,
21 prints,
22 }
23 }
24
25 pub fn reset(&mut self) {
27 if !self.enabled {
28 return;
29 }
30 self.data.clear();
31 self.last = Instant::now();
32 }
33
34 pub fn tick(&mut self, msg: &str) {
36 if self.prints {
37 println!("{}", msg);
38 }
39 if !self.enabled {
40 return;
41 }
42 let now = Instant::now();
43 let elapsed = now.duration_since(self.last);
44 self.last = now;
45 if !self.data.contains_key(msg) {
46 self.keys.push(msg.to_string());
47 }
48 let counter = self
49 .data
50 .entry(msg.to_string())
51 .or_insert_with(|| Duration::new(0, 0));
52 *counter += elapsed;
53 }
54
55 pub fn breakdown(&self, n: u32, unit: &str) {
57 if !self.enabled {
58 return;
59 }
60 let total_duration: Duration = self.data.values().sum();
61 let total_ms = total_duration.as_millis();
62 let mut top = format!("%%%%%%%%%%%%% Breakdown of {} {} %%%%%%%%%%%%%\n", n, unit);
63 let mut breakdown_message = top.clone();
64 for k in &self.keys {
65 let duration = self.data.get(k).unwrap();
66 let ms = duration.as_millis();
67 let percentage = ms as f64 / total_ms as f64 * 100.0;
68 breakdown_message.push_str(&StopWatch::highlight_if(
69 &format!("> {} {}ms {:.1}%\n", k, ms, percentage),
70 percentage > 10.0,
71 ));
72 }
73 breakdown_message.push_str(&format!(
74 "finished in {}ms ({:.2} {} per second)\n",
75 total_ms,
76 n as f64 * 1000.0 / total_ms as f64,
77 unit
78 ));
79 top = StopWatch::highlight_if(&top, true);
80 breakdown_message.push_str(&StopWatch::highlight_if(
81 &"%".repeat(std::cmp::max(top.len() - 10, 26)),
82 false,
83 ));
84 println!("{}", breakdown_message);
85 }
86
87 fn highlight_if(s: &str, b: bool) -> String {
88 if b {
89 format!("\x1B[93m{}\x1B[0m", s)
90 } else {
91 s.to_string()
92 }
93 }
94}