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
use time::PreciseTime;

pub struct OpenTimer<'a> {
    name: &'static str,
    timer_tree: &'a mut TimerTree,
    start: PreciseTime,
    depth: u32,
}

impl<'a> OpenTimer<'a> {
    /// Starts timing a new named subtask
    ///
    /// The timer is stopped automatically
    /// when the `OpenTimer` is dropped.
    pub fn open(&mut self, name: &'static str) -> OpenTimer {
        OpenTimer {
            name: name,
            timer_tree: self.timer_tree,
            start: PreciseTime::now(),
            depth: self.depth + 1,
        }
    }
}

impl<'a> Drop for OpenTimer<'a> {
    fn drop(&mut self) {
        self.timer_tree.timings.push(Timing {
            name: self.name,
            duration: self.start
                .to(PreciseTime::now())
                .num_microseconds()
                .unwrap(),
            depth: self.depth,
        });
    }
}

/// Timing recording
#[derive(Debug, Serialize)]
pub struct Timing {
    name: &'static str,
    duration: i64,
    depth: u32,
}

/// Timer tree
#[derive(Debug, Serialize)]
pub struct TimerTree {
    timings: Vec<Timing>,
}

impl TimerTree {
    /// Returns the total time elapsed in microseconds
    pub fn total_time(&self) -> i64 {
        self.timings.last().unwrap().duration
    }

    /// Open a new named subtask
    pub fn open(&mut self, name: &'static str) -> OpenTimer {
        OpenTimer {
            name: name,
            timer_tree: self,
            start: PreciseTime::now(),
            depth: 0,
        }
    }
}

impl Default for TimerTree {
    fn default() -> TimerTree {
        TimerTree {
            timings: Vec::new(),
        }
    }
}

#[cfg(test)]
mod tests {

    use super::*;

    #[test]
    fn test_timer() {
        let mut timer_tree = TimerTree::default();
        {
            let mut a = timer_tree.open("a");
            {
                let mut ab = a.open("b");
                {
                    let _abc = ab.open("c");
                }
                {
                    let _abd = ab.open("d");
                }
            }
        }
        assert_eq!(timer_tree.timings.len(), 4);
    }
}