Skip to main content

xuko_misc/
profiling.rs

1//! Profiling
2
3use std::time::{Duration, SystemTime, SystemTimeError};
4
5/// The [`Profile`] structure stores how long it takes to do a task.
6///
7/// # Examples
8///
9/// ```
10/// use std::{time::Duration, thread::sleep};
11/// use xuko_misc::profiling::Profile;
12///
13/// let mut profile = Profile::new("sleep");
14/// sleep(Duration::from_millis(100));
15///
16/// let elapsed = profile.elapsed().unwrap();
17/// assert!(elapsed >= 100);
18///
19/// sleep(Duration::from_millis(100));
20/// // the result is saved!
21/// assert_eq!(profile.elapsed().unwrap(), elapsed);
22/// ```
23pub struct Profile {
24    name: String,
25    start: SystemTime,
26
27    time_taken: Option<Duration>,
28}
29
30impl Profile {
31    /// Create a new [`Profile`]
32    pub fn new<S: AsRef<str>>(name: S) -> Self {
33        Self {
34            name: name.as_ref().to_owned(),
35            start: SystemTime::now(),
36            time_taken: None,
37        }
38    }
39
40    /// Same as [`Self::elapsed_duration`], except maps the result with [`Duration::as_millis`]
41    pub fn elapsed(&mut self) -> Result<u128, SystemTimeError> {
42        self.elapsed_duration().map(|d| d.as_millis())
43    }
44
45    /// Return how much time has passed since the start of this [`Profile`] as a [`Duration`]
46    ///
47    /// This can only fail once, as the result will be saved in the [`Profile`] structure.
48    pub fn elapsed_duration(&mut self) -> Result<Duration, SystemTimeError> {
49        if let Some(d) = self.time_taken {
50            Ok(d)
51        } else {
52            let d = self.start.elapsed()?;
53            self.time_taken = Some(d);
54            Ok(d)
55        }
56    }
57
58    /// Get the name of this [`Profile`]
59    pub fn name(&self) -> &str {
60        &self.name
61    }
62}
63
64#[cfg(test)]
65mod tests {
66    use super::*;
67
68    #[test]
69    fn elapsed_millis() {
70        let mut profile = Profile::new("fake network request");
71
72        std::thread::sleep(Duration::from_secs_f64(0.25));
73
74        let elapsed = profile.elapsed().expect("time went backwards!");
75        assert!(elapsed >= 250);
76        println!("`{}` took {elapsed} milliseconds", profile.name());
77    }
78}