Skip to content

Commit

Permalink
Always compute relative speed comprison for export, closes #642
Browse files Browse the repository at this point in the history
  • Loading branch information
sharkdp committed Apr 20, 2023
1 parent 926b8d0 commit 9859eca
Show file tree
Hide file tree
Showing 3 changed files with 63 additions and 39 deletions.
91 changes: 60 additions & 31 deletions src/benchmark/relative_speed.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,43 +15,72 @@ 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<Vec<BenchmarkResultWithRelativeSpeed>> {
let fastest: &BenchmarkResult = results
fn fastest_of(results: &[BenchmarkResult]) -> &BenchmarkResult {
results
.iter()
.min_by(|&l, &r| compare_mean_time(l, r))
.expect("at least one benchmark result");
.expect("at least one benchmark result")
}

fn compute_relative_speeds<'a>(
results: &'a [BenchmarkResult],
fastest: &'a BenchmarkResult,
) -> Vec<BenchmarkResultWithRelativeSpeed<'a>> {
results
.iter()
.map(|result| {
let is_fastest = result == fastest;

if result.mean == 0.0 {
return BenchmarkResultWithRelativeSpeed {
result,
relative_speed: if is_fastest { 1.0 } else { f64::INFINITY },
relative_speed_stddev: None,
is_fastest,
};
}

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 = match (result.stddev, fastest.stddev) {
(Some(result_stddev), Some(fastest_stddev)) => Some(
ratio
* ((result_stddev / result.mean).powi(2)
+ (fastest_stddev / fastest.mean).powi(2))
.sqrt(),
),
_ => None,
};

BenchmarkResultWithRelativeSpeed {
result,
relative_speed: ratio,
relative_speed_stddev: ratio_stddev,
is_fastest,
}
})
.collect()
}

pub fn compute_with_check(
results: &[BenchmarkResult],
) -> Option<Vec<BenchmarkResultWithRelativeSpeed>> {
let fastest = fastest_of(results);

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 = match (result.stddev, fastest.stddev) {
(Some(result_stddev), Some(fastest_stddev)) => Some(
ratio
* ((result_stddev / result.mean).powi(2)
+ (fastest_stddev / fastest.mean).powi(2))
.sqrt(),
),
_ => None,
};
Some(compute_relative_speeds(results, fastest))
}

BenchmarkResultWithRelativeSpeed {
result,
relative_speed: ratio,
relative_speed_stddev: ratio_stddev,
is_fastest: result == fastest,
}
})
.collect(),
)
/// Same as compute_with_check, potentially resulting in relative speeds of infinity
pub fn compute(results: &[BenchmarkResult]) -> Vec<BenchmarkResultWithRelativeSpeed> {
let fastest = fastest_of(results);

compute_relative_speeds(results, fastest)
}

#[cfg(test)]
Expand Down Expand Up @@ -83,7 +112,7 @@ fn test_compute_relative_speed() {
create_result("cmd3", 5.0),
];

let annotated_results = compute(&results).unwrap();
let annotated_results = compute_with_check(&results).unwrap();

assert_relative_eq!(1.5, annotated_results[0].relative_speed);
assert_relative_eq!(1.0, annotated_results[1].relative_speed);
Expand All @@ -94,7 +123,7 @@ fn test_compute_relative_speed() {
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);
let annotated_results = compute_with_check(&results);

assert!(annotated_results.is_none());
}
2 changes: 1 addition & 1 deletion src/benchmark/scheduler.rs
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,7 @@ impl<'a> Scheduler<'a> {
return;
}

if let Some(mut annotated_results) = relative_speed::compute(&self.results) {
if let Some(mut annotated_results) = relative_speed::compute_with_check(&self.results) {
annotated_results.sort_by(|l, r| relative_speed::compare_mean_time(l.result, r.result));

let fastest = &annotated_results[0];
Expand Down
9 changes: 2 additions & 7 deletions src/export/markup.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ use crate::output::format::format_duration_value;
use crate::util::units::Unit;

use super::Exporter;
use anyhow::{anyhow, Result};
use anyhow::Result;

pub enum Alignment {
Left,
Expand Down Expand Up @@ -106,13 +106,8 @@ impl<T: MarkupExporter> Exporter for T {
fn serialize(&self, results: &[BenchmarkResult], unit: Option<Unit>) -> Result<Vec<u8>> {
let unit = unit.unwrap_or_else(|| determine_unit_from_results(results));
let entries = relative_speed::compute(results);
if entries.is_none() {
return Err(anyhow!(
"Relative speed comparison is not available for markup exporter."
));
}

let table = self.table_results(&entries.unwrap(), unit);
let table = self.table_results(&entries, unit);
Ok(table.as_bytes().to_vec())
}
}
Expand Down

0 comments on commit 9859eca

Please sign in to comment.