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, 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, } 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, 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); } }