From 76dd9d40f09eb43f91e3f16f3a475d65e7e27d4c Mon Sep 17 00:00:00 2001 From: David Peter Date: Tue, 24 Aug 2021 22:12:42 +0200 Subject: [PATCH] Move relative-speed computation to separate module --- src/export/markdown.rs | 4 +- src/internal.rs | 97 +----------------------------------------- src/main.rs | 5 ++- src/relative_speed.rs | 94 ++++++++++++++++++++++++++++++++++++++++ 4 files changed, 100 insertions(+), 100 deletions(-) create mode 100644 src/relative_speed.rs diff --git a/src/export/markdown.rs b/src/export/markdown.rs index e466ce3..1fa7b78 100644 --- a/src/export/markdown.rs +++ b/src/export/markdown.rs @@ -3,7 +3,7 @@ use std::io::{Error, ErrorKind, Result}; use super::Exporter; use crate::benchmark_result::BenchmarkResult; use crate::format::format_duration_value; -use crate::internal::{compute_relative_speed, BenchmarkResultWithRelativeSpeed}; +use crate::relative_speed::{self, BenchmarkResultWithRelativeSpeed}; use crate::units::Unit; #[derive(Default)] @@ -22,7 +22,7 @@ impl Exporter for MarkdownExporter { Unit::Second }; - if let Some(annotated_results) = compute_relative_speed(results) { + if let Some(annotated_results) = relative_speed::compute(results) { let mut destination = start_table(unit); for result in annotated_results { diff --git a/src/internal.rs b/src/internal.rs index 1367f5a..34c594d 100644 --- a/src/internal.rs +++ b/src/internal.rs @@ -1,8 +1,6 @@ -use std::cmp::Ordering; use std::iter::Iterator; -use crate::benchmark_result::BenchmarkResult; -use crate::units::{Scalar, Second}; +use crate::units::Second; /// Threshold for warning about fast execution time pub const MIN_EXECUTION_TIME: Second = 5e-3; @@ -23,54 +21,6 @@ pub fn min(vals: &[f64]) -> f64 { .unwrap() } -#[derive(Debug)] -pub struct BenchmarkResultWithRelativeSpeed<'a> { - pub result: &'a BenchmarkResult, - pub relative_speed: Scalar, - pub relative_speed_stddev: Scalar, - pub is_fastest: bool, -} - -pub fn compare_mean_time(l: &BenchmarkResult, r: &BenchmarkResult) -> Ordering { - l.mean.partial_cmp(&r.mean).unwrap_or(Ordering::Equal) -} - -pub fn compute_relative_speed( - results: &[BenchmarkResult], -) -> Option> { - let fastest: &BenchmarkResult = results - .iter() - .min_by(|&l, &r| compare_mean_time(l, r)) - .expect("at least one benchmark result"); - - if fastest.mean == 0.0 { - return None; - } - - Some( - results - .iter() - .map(|result| { - let ratio = result.mean / fastest.mean; - - // https://en.wikipedia.org/wiki/Propagation_of_uncertainty#Example_formulas - // Covariance asssumed to be 0, i.e. variables are assumed to be independent - let ratio_stddev = ratio - * ((result.stddev / result.mean).powi(2) - + (fastest.stddev / fastest.mean).powi(2)) - .sqrt(); - - BenchmarkResultWithRelativeSpeed { - result, - relative_speed: ratio, - relative_speed_stddev: ratio_stddev, - is_fastest: result == fastest, - } - }) - .collect(), - ) -} - #[test] fn test_max() { let assert_float_eq = |a: f64, b: f64| { @@ -83,48 +33,3 @@ fn test_max() { assert_float_eq(1.0, max(&[-1.0, 1.0])); assert_float_eq(1.0, max(&[-1.0, 1.0, 0.0])); } - -#[cfg(test)] -fn create_result(name: &str, mean: Scalar) -> BenchmarkResult { - use std::collections::BTreeMap; - - BenchmarkResult { - command: name.into(), - mean, - stddev: 1.0, - median: mean, - user: mean, - system: 0.0, - min: mean, - max: mean, - times: None, - exit_codes: Vec::new(), - parameters: BTreeMap::new(), - } -} - -#[test] -fn test_compute_relative_speed() { - use approx::assert_relative_eq; - - let results = vec![ - create_result("cmd1", 3.0), - create_result("cmd2", 2.0), - create_result("cmd3", 5.0), - ]; - - let annotated_results = compute_relative_speed(&results).unwrap(); - - assert_relative_eq!(1.5, annotated_results[0].relative_speed); - assert_relative_eq!(1.0, annotated_results[1].relative_speed); - assert_relative_eq!(2.5, annotated_results[2].relative_speed); -} - -#[test] -fn test_compute_relative_speed_for_zero_times() { - let results = vec![create_result("cmd1", 1.0), create_result("cmd2", 0.0)]; - - let annotated_results = compute_relative_speed(&results); - - assert!(annotated_results.is_none()); -} diff --git a/src/main.rs b/src/main.rs index f1a85f2..7ab6e49 100644 --- a/src/main.rs +++ b/src/main.rs @@ -19,6 +19,7 @@ pub mod options; pub mod outlier_detection; pub mod parameter_range; pub mod progress_bar; +pub mod relative_speed; pub mod shell; pub mod timer; pub mod tokenize; @@ -49,8 +50,8 @@ pub fn write_benchmark_comparison(results: &[BenchmarkResult]) { return; } - if let Some(mut annotated_results) = internal::compute_relative_speed(results) { - annotated_results.sort_by(|l, r| internal::compare_mean_time(l.result, r.result)); + if let Some(mut annotated_results) = relative_speed::compute(results) { + annotated_results.sort_by(|l, r| relative_speed::compare_mean_time(l.result, r.result)); let fastest = &annotated_results[0]; let others = &annotated_results[1..]; diff --git a/src/relative_speed.rs b/src/relative_speed.rs new file mode 100644 index 0000000..a87b8f5 --- /dev/null +++ b/src/relative_speed.rs @@ -0,0 +1,94 @@ +use std::cmp::Ordering; + +use crate::{benchmark_result::BenchmarkResult, units::Scalar}; + +#[derive(Debug)] +pub struct BenchmarkResultWithRelativeSpeed<'a> { + pub result: &'a BenchmarkResult, + pub relative_speed: Scalar, + pub relative_speed_stddev: Scalar, + pub is_fastest: bool, +} + +pub fn compare_mean_time(l: &BenchmarkResult, r: &BenchmarkResult) -> Ordering { + l.mean.partial_cmp(&r.mean).unwrap_or(Ordering::Equal) +} + +pub fn compute(results: &[BenchmarkResult]) -> Option> { + let fastest: &BenchmarkResult = results + .iter() + .min_by(|&l, &r| compare_mean_time(l, r)) + .expect("at least one benchmark result"); + + if fastest.mean == 0.0 { + return None; + } + + Some( + results + .iter() + .map(|result| { + let ratio = result.mean / fastest.mean; + + // https://en.wikipedia.org/wiki/Propagation_of_uncertainty#Example_formulas + // Covariance asssumed to be 0, i.e. variables are assumed to be independent + let ratio_stddev = ratio + * ((result.stddev / result.mean).powi(2) + + (fastest.stddev / fastest.mean).powi(2)) + .sqrt(); + + BenchmarkResultWithRelativeSpeed { + result, + relative_speed: ratio, + relative_speed_stddev: ratio_stddev, + is_fastest: result == fastest, + } + }) + .collect(), + ) +} + +#[cfg(test)] +fn create_result(name: &str, mean: Scalar) -> BenchmarkResult { + use std::collections::BTreeMap; + + BenchmarkResult { + command: name.into(), + mean, + stddev: 1.0, + median: mean, + user: mean, + system: 0.0, + min: mean, + max: mean, + times: None, + exit_codes: Vec::new(), + parameters: BTreeMap::new(), + } +} + +#[test] +fn test_compute_relative_speed() { + use approx::assert_relative_eq; + + let results = vec![ + create_result("cmd1", 3.0), + create_result("cmd2", 2.0), + create_result("cmd3", 5.0), + ]; + + let annotated_results = compute(&results).unwrap(); + + assert_relative_eq!(1.5, annotated_results[0].relative_speed); + assert_relative_eq!(1.0, annotated_results[1].relative_speed); + assert_relative_eq!(2.5, annotated_results[2].relative_speed); +} + +#[test] +fn test_compute_relative_speed_for_zero_times() { + let results = vec![create_result("cmd1", 1.0), create_result("cmd2", 0.0)]; + + let annotated_results = compute(&results); + + assert!(annotated_results.is_none()); +}