use crate::measure::{Accounting, RunStats};
#[derive(Debug, Clone)]
pub struct BenchResult {
pub command: String,
pub runs: Vec<RunStats>,
}
impl BenchResult {
pub fn mean_wall_secs(&self) -> f64 {
mean(self.runs.iter().map(|r| r.wall_time.as_secs_f64()))
}
pub fn stddev_wall_secs(&self) -> f64 {
stddev(self.runs.iter().map(|r| r.wall_time.as_secs_f64()))
}
pub fn mean_cpu_secs(&self) -> f64 {
mean(self.runs.iter().map(|r| r.cpu_time.as_secs_f64()))
}
pub fn mean_cpu_percent(&self) -> f64 {
mean(self.runs.iter().map(|r| {
let wall = r.wall_time.as_secs_f64();
if wall > 0.0 {
100.0 * r.cpu_time.as_secs_f64() / wall
} else {
0.0
}
}))
}
pub fn mean_peak_memory_bytes(&self) -> f64 {
mean(self.runs.iter().map(|r| r.peak_memory_bytes as f64))
}
pub fn mean_disk_read_bytes(&self) -> f64 {
mean(self.runs.iter().map(|r| r.disk_read_bytes as f64))
}
pub fn mean_disk_write_bytes(&self) -> f64 {
mean(self.runs.iter().map(|r| r.disk_write_bytes as f64))
}
pub fn mean_max_processes(&self) -> f64 {
mean(self.runs.iter().map(|r| r.max_processes as f64))
}
pub fn mean_max_threads(&self) -> f64 {
mean(self.runs.iter().map(|r| r.max_threads as f64))
}
pub fn accounting(&self) -> Accounting {
if self.runs.iter().all(|r| r.accounting == Accounting::Cgroup) {
Accounting::Cgroup
} else {
Accounting::Sampled
}
}
}
fn mean(values: impl Iterator<Item = f64> + Clone) -> f64 {
let (sum, count) = values.fold((0.0, 0usize), |(s, c), v| (s + v, c + 1));
if count == 0 { 0.0 } else { sum / count as f64 }
}
fn stddev(values: impl Iterator<Item = f64> + Clone) -> f64 {
let m = mean(values.clone());
let (sum_sq, count) = values.fold((0.0, 0usize), |(s, c), v| (s + (v - m).powi(2), c + 1));
if count < 2 {
0.0
} else {
(sum_sq / (count - 1) as f64).sqrt()
}
}