2018-03-22 21:53:36 -04:00
|
|
|
use colored::*;
|
2018-01-14 20:14:10 +01:00
|
|
|
use indicatif::{ProgressBar, ProgressStyle};
|
|
|
|
|
|
2019-05-07 11:55:38 +02:00
|
|
|
use crate::hyperfine::types::{BenchmarkResult, OutputStyleOption};
|
2019-06-08 11:47:50 +02:00
|
|
|
use crate::hyperfine::units::{Scalar, Second};
|
2018-03-22 21:53:36 -04:00
|
|
|
|
|
|
|
|
use std::cmp::Ordering;
|
|
|
|
|
use std::iter::Iterator;
|
2018-01-14 20:14:10 +01:00
|
|
|
|
|
|
|
|
/// Threshold for warning about fast execution time
|
|
|
|
|
pub const MIN_EXECUTION_TIME: Second = 5e-3;
|
|
|
|
|
|
|
|
|
|
/// Return a pre-configured progress bar
|
2019-07-13 10:38:51 +02:00
|
|
|
pub fn get_progress_bar(length: u64, msg: &str, option: OutputStyleOption) -> ProgressBar {
|
|
|
|
|
let progressbar_style = match option {
|
2018-09-15 10:11:35 -07:00
|
|
|
OutputStyleOption::Basic | OutputStyleOption::Color => ProgressStyle::default_bar(),
|
2018-02-13 21:00:22 -05:00
|
|
|
_ => ProgressStyle::default_spinner()
|
2018-02-02 12:07:35 +01:00
|
|
|
.tick_chars("⠋⠙⠹⠸⠼⠴⠦⠧⠇⠏")
|
2018-09-28 21:19:54 +02:00
|
|
|
.template(" {spinner} {msg:<30} {wide_bar} ETA {eta_precise}"),
|
2018-01-28 08:35:52 -05:00
|
|
|
};
|
2018-01-14 20:14:10 +01:00
|
|
|
|
2019-07-13 10:38:51 +02:00
|
|
|
let progress_bar = match option {
|
2018-09-15 10:11:35 -07:00
|
|
|
OutputStyleOption::Basic | OutputStyleOption::Color => ProgressBar::hidden(),
|
2018-02-13 21:00:22 -05:00
|
|
|
_ => ProgressBar::new(length),
|
2018-01-28 08:35:52 -05:00
|
|
|
};
|
2018-01-18 20:16:36 +01:00
|
|
|
progress_bar.set_style(progressbar_style.clone());
|
|
|
|
|
progress_bar.enable_steady_tick(80);
|
|
|
|
|
progress_bar.set_message(msg);
|
2018-01-14 20:14:10 +01:00
|
|
|
|
2018-01-18 20:16:36 +01:00
|
|
|
progress_bar
|
2018-01-14 20:14:10 +01:00
|
|
|
}
|
|
|
|
|
|
2018-01-14 21:43:29 +01:00
|
|
|
/// A max function for f64's without NaNs
|
|
|
|
|
pub fn max(vals: &[f64]) -> f64 {
|
2018-05-22 22:57:51 +02:00
|
|
|
*vals
|
|
|
|
|
.iter()
|
2018-01-14 21:43:29 +01:00
|
|
|
.max_by(|a, b| a.partial_cmp(b).unwrap())
|
|
|
|
|
.unwrap()
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// A min function for f64's without NaNs
|
|
|
|
|
pub fn min(vals: &[f64]) -> f64 {
|
2018-05-22 22:57:51 +02:00
|
|
|
*vals
|
|
|
|
|
.iter()
|
2018-01-14 21:43:29 +01:00
|
|
|
.min_by(|a, b| a.partial_cmp(b).unwrap())
|
|
|
|
|
.unwrap()
|
|
|
|
|
}
|
2018-01-18 18:58:51 +01:00
|
|
|
|
2019-06-08 11:47:50 +02:00
|
|
|
pub struct BenchmarkResultWithRelativeSpeed<'a> {
|
2019-06-08 12:04:26 +02:00
|
|
|
pub result: &'a BenchmarkResult,
|
|
|
|
|
pub relative_speed: Scalar,
|
|
|
|
|
pub relative_speed_stddev: Scalar,
|
2019-06-08 11:47:50 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fn compare_mean_time(l: &BenchmarkResult, r: &BenchmarkResult) -> Ordering {
|
|
|
|
|
l.mean.partial_cmp(&r.mean).unwrap_or(Ordering::Equal)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
pub fn compute_relative_speed<'a>(
|
2019-07-13 10:29:05 +02:00
|
|
|
results: &'a [BenchmarkResult],
|
2019-06-08 11:47:50 +02:00
|
|
|
) -> Vec<BenchmarkResultWithRelativeSpeed<'a>> {
|
|
|
|
|
let fastest: &BenchmarkResult = results
|
|
|
|
|
.iter()
|
|
|
|
|
.min_by(|&l, &r| compare_mean_time(l, r))
|
|
|
|
|
.expect("at least one benchmark result");
|
|
|
|
|
|
|
|
|
|
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
|
2019-06-08 12:04:26 +02:00
|
|
|
* ((result.stddev / result.mean).powi(2) + (fastest.stddev / fastest.mean).powi(2))
|
|
|
|
|
.sqrt();
|
2019-06-08 11:47:50 +02:00
|
|
|
|
|
|
|
|
BenchmarkResultWithRelativeSpeed {
|
|
|
|
|
result,
|
|
|
|
|
relative_speed: ratio,
|
|
|
|
|
relative_speed_stddev: ratio_stddev,
|
|
|
|
|
}
|
|
|
|
|
})
|
|
|
|
|
.collect()
|
|
|
|
|
}
|
|
|
|
|
|
2019-07-13 10:29:05 +02:00
|
|
|
pub fn write_benchmark_comparison(results: &[BenchmarkResult]) {
|
2018-03-22 21:53:36 -04:00
|
|
|
if results.len() < 2 {
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
2019-06-08 11:47:50 +02:00
|
|
|
let mut annotated_results = compute_relative_speed(&results);
|
|
|
|
|
annotated_results.sort_by(|l, r| compare_mean_time(l.result, r.result));
|
2018-03-22 21:53:36 -04:00
|
|
|
|
2019-06-08 11:47:50 +02:00
|
|
|
let fastest = &annotated_results[0];
|
|
|
|
|
let others = &annotated_results[1..];
|
2018-03-22 21:53:36 -04:00
|
|
|
|
2018-09-15 10:11:35 -07:00
|
|
|
println!("{}", "Summary".bold());
|
2019-06-08 11:47:50 +02:00
|
|
|
println!(" '{}' ran", fastest.result.command.cyan());
|
2018-03-22 21:53:36 -04:00
|
|
|
|
2019-06-08 11:47:50 +02:00
|
|
|
for item in others {
|
2018-03-22 21:53:36 -04:00
|
|
|
println!(
|
2018-09-15 21:35:38 +03:00
|
|
|
"{} ± {} times faster than '{}'",
|
2019-06-08 11:47:50 +02:00
|
|
|
format!("{:8.2}", item.relative_speed).bold().green(),
|
|
|
|
|
format!("{:.2}", item.relative_speed_stddev).green(),
|
|
|
|
|
&item.result.command.magenta()
|
2018-03-22 21:53:36 -04:00
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2018-01-18 18:58:51 +01:00
|
|
|
#[test]
|
|
|
|
|
fn test_max() {
|
|
|
|
|
assert_eq!(1.0, max(&[1.0]));
|
|
|
|
|
assert_eq!(-1.0, max(&[-1.0]));
|
|
|
|
|
assert_eq!(-1.0, max(&[-2.0, -1.0]));
|
|
|
|
|
assert_eq!(1.0, max(&[-1.0, 1.0]));
|
|
|
|
|
assert_eq!(1.0, max(&[-1.0, 1.0, 0.0]));
|
|
|
|
|
}
|
2019-06-08 11:47:50 +02:00
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
|
fn test_compute_relative_speed() {
|
|
|
|
|
use approx::assert_relative_eq;
|
|
|
|
|
|
2019-06-08 12:04:26 +02:00
|
|
|
let create_result = |name: &str, mean| BenchmarkResult {
|
|
|
|
|
command: name.into(),
|
2019-07-13 10:06:25 +02:00
|
|
|
mean,
|
2019-06-08 12:04:26 +02:00
|
|
|
stddev: 1.0,
|
2019-06-08 13:04:39 +02:00
|
|
|
median: mean,
|
2019-06-08 12:04:26 +02:00
|
|
|
user: mean,
|
|
|
|
|
system: 0.0,
|
|
|
|
|
min: mean,
|
|
|
|
|
max: mean,
|
|
|
|
|
times: None,
|
|
|
|
|
parameter: None,
|
2019-06-08 11:47:50 +02:00
|
|
|
};
|
|
|
|
|
|
|
|
|
|
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);
|
|
|
|
|
|
|
|
|
|
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);
|
|
|
|
|
}
|