//! Rendering time meter. //! //! Used to track rendering times and provide moving averages. //! //! # Examples //! //! ```rust //! // create a meter //! let mut meter = alacritty_terminal::meter::Meter::new(); //! //! // Sample something. //! { //! let _sampler = meter.sampler(); //! } //! //! // Get the moving average. The meter tracks a fixed number of samples, and //! // the average won't mean much until it's filled up at least once. //! println!("Average time: {}", meter.average()); //! ``` use std::time::{Duration, Instant}; const NUM_SAMPLES: usize = 10; /// The meter. #[derive(Default)] pub struct Meter { /// Track last 60 timestamps. times: [f64; NUM_SAMPLES], /// Average sample time in microseconds. avg: f64, /// Index of next time to update.. index: usize, } /// Sampler. /// /// Samplers record how long they are "alive" for and update the meter on drop.. pub struct Sampler<'a> { /// Reference to meter that created the sampler. meter: &'a mut Meter, /// When the sampler was created. created_at: Instant, } impl<'a> Sampler<'a> { fn new(meter: &'a mut Meter) -> Sampler<'a> { Sampler { meter, created_at: Instant::now() } } #[inline] fn alive_duration(&self) -> Duration { self.created_at.elapsed() } } impl<'a> Drop for Sampler<'a> { fn drop(&mut self) { self.meter.add_sample(self.alive_duration()); } } impl Meter { /// Create a meter. pub fn new() -> Meter { Default::default() } /// Get a sampler. pub fn sampler(&mut self) -> Sampler<'_> { Sampler::new(self) } /// Get the current average sample duration in microseconds. pub fn average(&self) -> f64 { self.avg } /// Add a sample. /// /// Used by Sampler::drop. fn add_sample(&mut self, sample: Duration) { let mut usec = 0f64; usec += f64::from(sample.subsec_nanos()) / 1e3; usec += (sample.as_secs() as f64) * 1e6; let prev = self.times[self.index]; self.times[self.index] = usec; self.avg -= prev / NUM_SAMPLES as f64; self.avg += usec / NUM_SAMPLES as f64; self.index = (self.index + 1) % NUM_SAMPLES; } }