use crate::profiling::profiler::Profiler;
use std::time::{Duration, Instant};
pub struct Timer {
name: String,
start_time: Instant,
running: bool,
auto_report: bool,
parent: Option<String>,
}
impl Timer {
pub fn start(name: &str) -> Self {
let timer = Self {
name: name.to_string(),
start_time: Instant::now(),
running: true,
auto_report: true,
parent: None,
};
if let Ok(mut profiler) = Profiler::global().lock() {
profiler.register_timer_start(&timer);
}
timer
}
pub fn start_with_parent(name: &str, parent: &str) -> Self {
let timer = Self {
name: name.to_string(),
start_time: Instant::now(),
running: true,
auto_report: true,
parent: Some(parent.to_string()),
};
if let Ok(mut profiler) = Profiler::global().lock() {
profiler.register_timer_start(&timer);
}
timer
}
pub fn time_function<F, R>(name: &str, f: F) -> R
where
F: FnOnce() -> R,
{
let timer = Self::start(name);
let result = f();
timer.stop();
result
}
pub fn time_function_with_parent<F, R>(name: &str, parent: &str, f: F) -> R
where
F: FnOnce() -> R,
{
let timer = Self::start_with_parent(name, parent);
let result = f();
timer.stop();
result
}
pub fn stop(&self) {
if !self.running {
return;
}
let elapsed = self.start_time.elapsed();
if let Ok(mut profiler) = Profiler::global().lock() {
profiler.register_timer_stop(&self.name, elapsed, self.parent.as_deref());
}
}
pub fn elapsed(&self) -> Duration {
self.start_time.elapsed()
}
pub fn without_auto_report(mut self) -> Self {
self.auto_report = false;
self
}
pub fn name(&self) -> &str {
&self.name
}
pub fn start_time(&self) -> Instant {
self.start_time
}
pub fn parent(&self) -> Option<&str> {
self.parent.as_deref()
}
pub fn is_running(&self) -> bool {
self.running
}
}
impl Drop for Timer {
fn drop(&mut self) {
if self.running && self.auto_report {
let elapsed = self.start_time.elapsed();
if let Ok(mut profiler) = Profiler::global().lock() {
profiler.register_timer_stop(&self.name, elapsed, self.parent.as_deref());
}
}
}
}
#[cfg(test)]
mod tests {
use super::*;
use std::thread;
use std::time::Duration;
#[test]
fn test_timer_basic() {
let timer = Timer::start("test_operation");
thread::sleep(Duration::from_millis(10));
timer.stop();
let elapsed = timer.elapsed();
assert!(elapsed >= Duration::from_millis(10));
}
}