hillock/
lib.rs

1use std::time::{Duration, Instant};
2use std::collections::HashMap;
3
4/// A simple stopwatch to profile execution time
5pub 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    /// Create a new stopwatch
15    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    /// Reset the stopwatch
26    pub fn reset(&mut self) {
27        if !self.enabled {
28            return;
29        }
30        self.data.clear();
31        self.last = Instant::now();
32    }
33
34    /// Record the current time with a message
35    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    /// Print the breakdown of the time spent on each tick
56    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}