use error::Error;
use runner::Counter;
use event::Printable;
use std::fmt::{self, Display};
use separator::Separatable;
pub struct RSDPrinter<T: Counter + Printable + Display> {
counter: T,
values: Vec<u64>,
}
impl<T> Counter for RSDPrinter<T>
where
T: Counter + Printable + Display,
{
fn attach(&mut self, pid: u32) -> Result<(), Error> {
self.counter.attach(pid)
}
fn start(&mut self) -> Result<(), Error> {
self.counter.start()
}
fn stop(&mut self) -> Result<(), Error> {
self.counter.stop()
}
fn set(&mut self, value: u64) -> Result<u64, Error> {
self.counter.set(value).and_then(|v| {
self.values.push(v);
Ok(v)
})
}
}
impl<T> Display for RSDPrinter<T>
where
T: Counter + Printable + Display,
{
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
let rsd = if self.values.len() > 1 {
format!("±{:<5}", format!("{:.1}%", self.rsd()))
} else {
String::from(" ")
};
write!(
f,
"{:>30}: {:>14} {}",
self.counter.name(),
self.value().separated_string(),
rsd,
)
}
}
impl<T> Printable for RSDPrinter<T>
where
T: Counter + Printable + Display,
{
fn name(&self) -> &str {
self.counter.name()
}
fn value(&self) -> u64 {
self.mean()
}
}
impl<T> RSDPrinter<T>
where
T: Counter + Printable + Display,
{
pub fn new(counter: T) -> Self {
RSDPrinter {
counter,
values: Vec::new(),
}
}
pub fn rsd(&self) -> f64 {
if self.values.len() < 2 {
return 0.0;
}
(self.stddev() * f64::from(100)) / self.mean() as f64
}
fn mean(&self) -> u64 {
if self.values.is_empty() {
return 0;
}
self.values.iter().sum::<u64>() / self.values.len() as u64
}
fn variance(&self) -> f64 {
if self.values.len() < 2 {
return 0.0;
}
let mean = self.mean() as f64;
let total = self.values.iter().fold(0.0, |acc, v| {
let v = *v as f64;
let x = v - mean;
acc + x * x
});
let divisor = (self.values.len() - 1) as f64;
total / divisor
}
fn stddev(&self) -> f64 {
self.variance().sqrt()
}
}
#[cfg(test)]
mod tests {
use super::*;
mod mock_event;
use self::mock_event::MockEvent;
#[test]
fn stats() {
let mut values = vec![0, 10, 20, 30, 40];
let mut p = RSDPrinter::new(MockEvent::new("mock", &values.clone()));
values.reverse();
for v in values.iter() {
p.set(0).unwrap(); assert_eq!(p.counter.value(), *v);
}
assert_eq!(p.value(), 20);
assert_eq!(p.variance(), 250.0);
assert_eq!(p.stddev() as f32, 15.811388);
assert_eq!(p.rsd() as f32, 79.0569415);
}
#[test]
fn div_zero() {
let values = vec![];
let p = RSDPrinter::new(MockEvent::new("mock", &values));
assert_eq!(p.value(), 0);
assert_eq!(p.variance(), 0.0);
assert_eq!(p.stddev(), 0.0);
assert_eq!(p.rsd(), 0.0);
}
#[test]
fn div_zero_one_val() {
let values = vec![42];
let p = RSDPrinter::new(MockEvent::new("mock", &values));
assert_eq!(p.value(), 0);
assert_eq!(p.variance(), 0.0);
assert_eq!(p.stddev(), 0.0);
assert_eq!(p.rsd(), 0.0);
}
}