scirs2_core/profiling/
timer.rs

1//! Timer functionality for profiling code execution time
2
3use crate::profiling::profiler::Profiler;
4use std::time::{Duration, Instant};
5
6/// Timer for measuring code execution time
7pub struct Timer {
8    /// Name of the operation being timed
9    name: String,
10    /// Start time
11    start_time: Instant,
12    /// Whether the timer is currently running
13    running: bool,
14    /// Whether to automatically report the timing when dropped
15    auto_report: bool,
16    /// Parent timer name for hierarchical profiling
17    parent: Option<String>,
18}
19
20impl Timer {
21    /// Start a new timer with the given name
22    pub fn start(name: &str) -> Self {
23        let timer = Self {
24            name: name.to_string(),
25            start_time: Instant::now(),
26            running: true,
27            auto_report: true,
28            parent: None,
29        };
30        if let Ok(mut profiler) = Profiler::global().lock() {
31            profiler.register_timer_start(&timer);
32        }
33        timer
34    }
35
36    /// Start a new hierarchical timer with a parent
37    pub fn start_with_parent(name: &str, parent: &str) -> Self {
38        let timer = Self {
39            name: name.to_string(),
40            start_time: Instant::now(),
41            running: true,
42            auto_report: true,
43            parent: Some(parent.to_string()),
44        };
45        if let Ok(mut profiler) = Profiler::global().lock() {
46            profiler.register_timer_start(&timer);
47        }
48        timer
49    }
50
51    /// Time a function call and return its result
52    pub fn time_function<F, R>(name: &str, f: F) -> R
53    where
54        F: FnOnce() -> R,
55    {
56        let timer = Self::start(name);
57        let result = f();
58        timer.stop();
59        result
60    }
61
62    /// Time a function call with a parent timer and return its result
63    pub fn time_function_with_parent<F, R>(name: &str, parent: &str, f: F) -> R
64    where
65        F: FnOnce() -> R,
66    {
67        let timer = Self::start_with_parent(name, parent);
68        let result = f();
69        timer.stop();
70        result
71    }
72
73    /// Stop the timer and record the elapsed time
74    pub fn stop(&self) {
75        if !self.running {
76            return;
77        }
78
79        let elapsed = self.start_time.elapsed();
80        if let Ok(mut profiler) = Profiler::global().lock() {
81            profiler.register_timer_stop(&self.name, elapsed, self.parent.as_deref());
82        }
83    }
84
85    /// Get the elapsed time without stopping the timer
86    pub fn elapsed(&self) -> Duration {
87        self.start_time.elapsed()
88    }
89
90    /// Disable auto-reporting when dropped
91    pub fn without_auto_report(mut self) -> Self {
92        self.auto_report = false;
93        self
94    }
95
96    /// Get the name of the timer
97    pub fn name(&self) -> &str {
98        &self.name
99    }
100
101    /// Get the start time
102    pub fn start_time(&self) -> Instant {
103        self.start_time
104    }
105
106    /// Get the parent timer name
107    pub fn parent(&self) -> Option<&str> {
108        self.parent.as_deref()
109    }
110
111    /// Check if the timer is running
112    pub fn is_running(&self) -> bool {
113        self.running
114    }
115}
116
117impl Drop for Timer {
118    fn drop(&mut self) {
119        if self.running && self.auto_report {
120            let elapsed = self.start_time.elapsed();
121            if let Ok(mut profiler) = Profiler::global().lock() {
122                profiler.register_timer_stop(&self.name, elapsed, self.parent.as_deref());
123            }
124        }
125    }
126}
127
128#[cfg(test)]
129mod tests {
130    use super::*;
131    use std::thread;
132    use std::time::Duration;
133
134    #[test]
135    fn test_timer_basic() {
136        let timer = Timer::start("test_operation");
137        thread::sleep(Duration::from_millis(10));
138        timer.stop();
139
140        let elapsed = timer.elapsed();
141        assert!(elapsed >= Duration::from_millis(10));
142    }
143}