blob: 0b091ab1d034309cdbb5d5fcfcea4640d4bdfe62 [file] [log] [blame]
// Copyright 2016 Joe Wilm, The Alacritty Project Contributors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
//! Rendering time meter
//!
//! Used to track rendering times and provide moving averages.
//!
//! # Examples
//!
//! ```rust
//! // create a meter
//! let mut meter = alacritty::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::{Instant, Duration};
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: 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) {
// Work around borrowck
let duration = self.alive_duration();
self.meter.add_sample(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 += (sample.subsec_nanos() as f64) / 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;
}
}