1
use std::cell::RefCell;
2
use std::io;
3
use std::io::Write;
4
use std::rc::Rc;
5
use std::time::Instant;
6

            
7
use log::info;
8
use log::warn;
9

            
10
/// A timing object to measure the time of different parts of the program. This
11
/// is useful for debugging and profiling.
12
#[derive(Default)]
13
pub struct Timing {
14
    results: Rc<RefCell<Vec<(String, f32)>>>,
15
}
16

            
17
/// A timer object that measures the time between its creation and the call to
18
/// `finish()`. Finish should be called explicitly before the timer is dropped,
19
/// otherwise we get zero values since the timer object is unused and can be
20
/// immediately dropped.
21
pub struct Timer {
22
    name: String,
23
    start: Instant,
24
    results: Rc<RefCell<Vec<(String, f32)>>>,
25
    registered: bool,
26
}
27

            
28
impl Timing {
29
    /// Creates a new timing object to track timers.
30
9500
    pub fn new() -> Self {
31
9500
        Self {
32
9500
            results: Rc::new(RefCell::new(Vec::new())),
33
9500
        }
34
9500
    }
35

            
36
    /// Starts a new timer with the given name.
37
47500
    pub fn start(&mut self, name: &str) -> Timer {
38
47500
        Timer {
39
47500
            name: name.to_string(),
40
47500
            start: Instant::now(),
41
47500
            results: self.results.clone(),
42
47500
            registered: false,
43
47500
        }
44
47500
    }
45

            
46
    /// Prints all the finished timers.
47
    pub fn print(&self) {
48
        for (name, time) in self.results.borrow().iter() {
49
            eprintln!("Time {name}: {time:.3}s");
50
        }
51
    }
52

            
53
    /// Writes a YAML report of the finished timers to the given writer.
54
    pub fn print_yaml(&self, tool_name: &str, writer: &mut impl Write) -> io::Result<()> {
55
        writeln!(writer, "- tool: {tool_name}")?;
56
        writeln!(writer, "  timing:")?;
57

            
58
        for (name, time) in self.results.borrow().iter() {
59
            writeln!(writer, "    {name}: {time:.3}s")?;
60
        }
61
        Ok(())
62
    }
63
}
64

            
65
impl Timer {
66
    /// Finishes the timer and registers the result.
67
47500
    pub fn finish(&mut self) {
68
47500
        let time = self.start.elapsed().as_secs_f64();
69
47500
        info!("Time {}: {:.3}s", self.name, time);
70

            
71
        // Register the result.
72
47500
        self.results.borrow_mut().push((self.name.clone(), time as f32));
73
47500
        self.registered = true
74
47500
    }
75
}
76

            
77
impl Drop for Timer {
78
47500
    fn drop(&mut self) {
79
47500
        if !self.registered {
80
            warn!("Timer {} was dropped before 'finish()'", self.name);
81
47500
        }
82
47500
    }
83
}