mirror of
https://github.com/sharkdp/hyperfine.git
synced 2026-11-02 09:01:25 +00:00
Move relative-speed computation to separate module
This commit is contained in:
1 parent
d5a2590b98
commit
76dd9d40f0
4 files changed
+100
-100
No files matched your search
@@ -3,7 +3,7 @@ use std::io::{Error, ErrorKind, Result};
|
|||||||
use super::Exporter;
|
use super::Exporter;
|
||||||
use crate::benchmark_result::BenchmarkResult;
|
use crate::benchmark_result::BenchmarkResult;
|
||||||
use crate::format::format_duration_value;
|
use crate::format::format_duration_value;
|
||||||
use crate::internal::{compute_relative_speed, BenchmarkResultWithRelativeSpeed};
|
use crate::relative_speed::{self, BenchmarkResultWithRelativeSpeed};
|
||||||
use crate::units::Unit;
|
use crate::units::Unit;
|
||||||
|
|
||||||
#[derive(Default)]
|
#[derive(Default)]
|
||||||
@@ -22,7 +22,7 @@ impl Exporter for MarkdownExporter {
|
|||||||
Unit::Second
|
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);
|
let mut destination = start_table(unit);
|
||||||
|
|
||||||
for result in annotated_results {
|
for result in annotated_results {
|
||||||
|
|||||||
+1
-96
@@ -1,8 +1,6 @@
|
|||||||
use std::cmp::Ordering;
|
|
||||||
use std::iter::Iterator;
|
use std::iter::Iterator;
|
||||||
|
|
||||||
use crate::benchmark_result::BenchmarkResult;
|
use crate::units::Second;
|
||||||
use crate::units::{Scalar, Second};
|
|
||||||
|
|
||||||
/// Threshold for warning about fast execution time
|
/// Threshold for warning about fast execution time
|
||||||
pub const MIN_EXECUTION_TIME: Second = 5e-3;
|
pub const MIN_EXECUTION_TIME: Second = 5e-3;
|
||||||
@@ -23,54 +21,6 @@ pub fn min(vals: &[f64]) -> f64 {
|
|||||||
.unwrap()
|
.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<Vec<BenchmarkResultWithRelativeSpeed>> {
|
|
||||||
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]
|
#[test]
|
||||||
fn test_max() {
|
fn test_max() {
|
||||||
let assert_float_eq = |a: f64, b: f64| {
|
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]));
|
||||||
assert_float_eq(1.0, max(&[-1.0, 1.0, 0.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());
|
|
||||||
}
|
|
||||||
+3
-2
@@ -19,6 +19,7 @@ pub mod options;
|
|||||||
pub mod outlier_detection;
|
pub mod outlier_detection;
|
||||||
pub mod parameter_range;
|
pub mod parameter_range;
|
||||||
pub mod progress_bar;
|
pub mod progress_bar;
|
||||||
|
pub mod relative_speed;
|
||||||
pub mod shell;
|
pub mod shell;
|
||||||
pub mod timer;
|
pub mod timer;
|
||||||
pub mod tokenize;
|
pub mod tokenize;
|
||||||
@@ -49,8 +50,8 @@ pub fn write_benchmark_comparison(results: &[BenchmarkResult]) {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if let Some(mut annotated_results) = internal::compute_relative_speed(results) {
|
if let Some(mut annotated_results) = relative_speed::compute(results) {
|
||||||
annotated_results.sort_by(|l, r| internal::compare_mean_time(l.result, r.result));
|
annotated_results.sort_by(|l, r| relative_speed::compare_mean_time(l.result, r.result));
|
||||||
|
|
||||||
let fastest = &annotated_results[0];
|
let fastest = &annotated_results[0];
|
||||||
let others = &annotated_results[1..];
|
let others = &annotated_results[1..];
|
||||||
|
|||||||
@@ -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<Vec<BenchmarkResultWithRelativeSpeed>> {
|
||||||
|
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());
|
||||||
|
}
|
||||||
Reference in new issue
Block a user