use crate::{Clock, ExponentiallyDecayingReservoir, Meter, Reservoir, Snapshot};
use std::sync::Arc;
use std::time::{Duration, Instant};
pub struct Timer {
meter: Meter,
reservoir: Box<dyn Reservoir>,
clock: Arc<dyn Clock>,
}
impl Default for Timer {
#[inline]
fn default() -> Timer {
Timer::new(ExponentiallyDecayingReservoir::new())
}
}
impl Timer {
pub fn new<R>(reservoir: R) -> Timer
where
R: Reservoir,
{
Timer {
meter: Meter::new(),
reservoir: Box::new(reservoir),
clock: crate::SYSTEM_CLOCK.clone(),
}
}
pub fn new_with<R>(reservoir: R, clock: Arc<dyn Clock>) -> Self
where
R: Reservoir,
{
Timer {
meter: Meter::new_with(clock.clone()),
reservoir: Box::new(reservoir),
clock,
}
}
#[inline]
pub fn update(&self, duration: Duration) {
self.meter.mark(1);
let nanos = duration.as_nanos() as i64;
self.reservoir.update(nanos);
}
#[inline]
pub fn time(&self) -> Time<'_> {
Time {
timer: self,
start: self.clock.now(),
}
}
#[inline]
pub fn count(&self) -> i64 {
self.meter.count()
}
#[inline]
pub fn one_minute_rate(&self) -> f64 {
self.meter.one_minute_rate()
}
#[inline]
pub fn five_minute_rate(&self) -> f64 {
self.meter.five_minute_rate()
}
#[inline]
pub fn fifteen_minute_rate(&self) -> f64 {
self.meter.fifteen_minute_rate()
}
#[inline]
pub fn mean_rate(&self) -> f64 {
self.meter.mean_rate()
}
#[inline]
pub fn snapshot(&self) -> Box<dyn Snapshot> {
self.reservoir.snapshot()
}
}
pub struct Time<'a> {
timer: &'a Timer,
start: Instant,
}
impl Drop for Time<'_> {
#[inline]
fn drop(&mut self) {
self.timer.update(self.timer.clock.now() - self.start);
}
}
#[cfg(test)]
mod test {
use crate::Timer;
use std::thread;
use std::time::Duration;
#[test]
#[allow(clippy::float_cmp)]
fn basic() {
let timer = Timer::default();
for _ in 0..15 {
timer.update(Duration::from_nanos(0));
}
for _ in 0..5 {
timer.update(Duration::from_nanos(5));
}
assert_eq!(timer.count(), 20);
assert!(timer.mean_rate() > 0.);
assert_eq!(timer.snapshot().value(0.8), 5.)
}
#[test]
fn time() {
let timer = Timer::default();
let guard = timer.time();
thread::sleep(Duration::from_millis(10));
drop(guard);
assert_eq!(timer.count(), 1);
assert!(timer.snapshot().max() >= 10_000_000);
}
}