debug_timer 0.1.3

Utilities for simple timings
Documentation
#[cfg(feature = "enable")]
mod real_debug_timer {
    use std::io::{stdout, Write};
    use std::time::{Duration, Instant};

    const SECOND: Duration = Duration::from_secs(1);
    const MILLISECOND: Duration = Duration::from_millis(1);
    const MICROSECOND: Duration = Duration::from_micros(1);

    pub struct DebugTimer {
        recorded_times: Vec<(&'static str, Instant)>,
    }

    fn value_and_units(duration: Duration) -> (f32, &'static str) {
        if duration < MICROSECOND {
            (duration.subsec_nanos() as f32, "ns")
        } else if duration < MILLISECOND {
            (duration.subsec_nanos() as f32 / 1000.0, "us")
        } else if duration < SECOND {
            (duration.subsec_micros() as f32 / 1000.0, "ms")
        } else {
            (duration.as_millis() as f32 / 1000.0, "s")
        }
    }

    impl DebugTimer {
        pub fn init() -> Self {
            Self {
                recorded_times: vec![("start", Instant::now())],
            }
        }

        pub fn record_time(&mut self, message: &'static str) {
            self.recorded_times.push((message, Instant::now()));
        }

        pub fn print_times(&self, message: &str) {
            let now = Instant::now();
            let (overall_val, overall_unit) = value_and_units(now - self.recorded_times[0].1);

            let mut out = stdout().lock();
            if overall_val < 10.0 {
                write!(out, "{message}{overall_val:.1}{overall_unit} (").unwrap();
            } else {
                write!(out, "{message}{overall_val:.0}{overall_unit} (").unwrap();
            }

            for (idx, times) in self.recorded_times.windows(2).enumerate() {
                let last = times[0];
                let current = times[1];

                if idx != 0 {
                    write!(out, ", ").unwrap();
                }

                let duration = current.1.duration_since(last.1);

                let (val, unit) = value_and_units(duration);
                if val < 10.0 {
                    write!(out, "{}: {val:.1}{unit}", current.0).unwrap();
                } else {
                    write!(out, "{}: {val:.0}{unit}", current.0).unwrap();
                }
            }
            writeln!(out, ")").unwrap();
        }
    }
}

mod dummy_debug_timer {
    pub struct DebugTimer;
    impl DebugTimer {
        #[inline(always)]
        pub fn init() -> Self {
            Self
        }
        #[inline(always)]
        pub fn record_time(&mut self, _message: &'static str) {}
        #[inline(always)]
        pub fn print_times(&self, _message: &str) {}
    }
}

#[cfg(feature = "enable")]
#[macro_export]
macro_rules! debug_timer {
    ($id:ident, $($cond:tt)*) => {
        let mut $id =  {
            #[cfg($($cond)*)]
            let timer = $crate::RealDebugTimer::init();
            #[cfg(not($($cond)*))]
            let timer = $crate::DummyDebugTimer::init();
            timer
        };
    };
}

#[cfg(feature = "enable")]
#[macro_export]
macro_rules! debug_timer_type {
    ($id:ident, $($cond:tt)*) => {
        #[cfg($($cond)*)]
        pub type $id = $crate::RealDebugTimer;
        #[cfg(not($($cond)*))]
        pub type $id = $crate::DummyDebugTimer;
    };
}

#[cfg(not(feature = "enable"))]
#[macro_export]
macro_rules! debug_timer {
    ($id:ident, $($cond:tt)*) => {
        let mut $id = $crate::DummyDebugTimer::init();
    };
}

#[cfg(not(feature = "enable"))]
#[macro_export]
macro_rules! debug_timer_type {
    ($id:ident, $($cond:tt)*) => {
        pub type $id = $crate::DummyDebugTimer;
    };
}

pub use dummy_debug_timer::DebugTimer as DummyDebugTimer;
#[cfg(feature = "enable")]
pub use real_debug_timer::DebugTimer as RealDebugTimer;