use std::process::ExitStatus;
use crate::stats;
pub struct Execution {
pub status: ExitStatus,
pub wall_clock: f64,
pub time_user: f64,
pub time_system: f64,
pub max_rss: u64,
}
pub struct BenchmarkResult {
pub label: String,
pub measurements: Vec<Execution>,
}
impl BenchmarkResult {
pub fn times(&self, field: impl Fn(&Execution) -> f64) -> Vec<f64> {
self.measurements.iter().map(field).collect()
}
}
pub struct NormBenchmark<'a> {
pub result: &'a BenchmarkResult,
pub mean: f64,
pub ratio: f64,
pub stddev: Option<f64>,
pub is_reference: bool,
}
pub fn compute(results: &[BenchmarkResult]) -> Option<Vec<NormBenchmark<'_>>> {
let summaries: Vec<(f64, Option<f64>)> = results
.iter()
.map(|r| stats::mean_stddev(&r.times(|x| x.wall_clock)))
.collect();
let (ref_mean, ref_stddev) = *summaries.first()?;
if ref_mean == 0.0 {
return None;
}
let relative = results
.iter()
.zip(&summaries)
.enumerate()
.map(|(idx, (result, &(mean, stddev)))| {
let ratio = mean / ref_mean;
let stddev = match (stddev, ref_stddev) {
(Some(stddev), Some(ref_stddev)) => {
Some(ratio * ((stddev / mean).powi(2) + (ref_stddev / ref_mean).powi(2)).sqrt())
}
_ => None,
};
NormBenchmark {
result,
mean,
ratio,
stddev,
is_reference: idx == 0,
}
})
.collect();
Some(relative)
}