2022-02-20 13:44:34 +01:00
|
|
|
use colored::*;
|
|
|
|
|
|
|
|
|
|
use super::benchmark_result::BenchmarkResult;
|
2022-02-21 08:46:10 +01:00
|
|
|
use super::{relative_speed, Benchmark};
|
2022-02-20 13:44:34 +01:00
|
|
|
|
2022-02-07 21:03:23 +01:00
|
|
|
use crate::command::Commands;
|
|
|
|
|
use crate::export::ExportManager;
|
2022-02-21 08:46:10 +01:00
|
|
|
use crate::options::{Options, OutputStyleOption};
|
2022-02-07 21:03:23 +01:00
|
|
|
|
2022-02-21 08:46:10 +01:00
|
|
|
use anyhow::Result;
|
2022-02-20 13:44:34 +01:00
|
|
|
|
2022-02-20 14:04:37 +01:00
|
|
|
pub struct Scheduler<'a> {
|
|
|
|
|
commands: &'a Commands<'a>,
|
|
|
|
|
options: &'a Options,
|
|
|
|
|
export_manager: &'a ExportManager,
|
|
|
|
|
results: Vec<BenchmarkResult>,
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
impl<'a> Scheduler<'a> {
|
|
|
|
|
pub fn new(
|
|
|
|
|
commands: &'a Commands,
|
|
|
|
|
options: &'a Options,
|
|
|
|
|
export_manager: &'a ExportManager,
|
|
|
|
|
) -> Self {
|
|
|
|
|
Self {
|
|
|
|
|
commands,
|
|
|
|
|
options,
|
|
|
|
|
export_manager,
|
|
|
|
|
results: vec![],
|
2022-02-20 13:44:34 +01:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2022-02-20 14:04:37 +01:00
|
|
|
pub fn run_benchmarks(&mut self) -> Result<()> {
|
2022-02-21 08:46:10 +01:00
|
|
|
let shell_spawning_time = super::mean_shell_spawning_time(
|
|
|
|
|
// TODO
|
2022-02-20 14:04:37 +01:00
|
|
|
&self.options.shell,
|
|
|
|
|
self.options.output_style,
|
|
|
|
|
self.options.command_output_policy,
|
|
|
|
|
)?;
|
2022-02-20 13:44:34 +01:00
|
|
|
|
2022-02-21 08:46:10 +01:00
|
|
|
for (number, cmd) in self.commands.iter().enumerate() {
|
2022-02-20 14:04:37 +01:00
|
|
|
self.results
|
2022-02-21 08:46:10 +01:00
|
|
|
.push(Benchmark::new(number, cmd, self.options, &shell_spawning_time).run()?);
|
2022-02-20 14:04:37 +01:00
|
|
|
|
|
|
|
|
// We export (all results so far) after each individual benchmark, because
|
|
|
|
|
// we would risk losing all results if a later benchmark fails.
|
|
|
|
|
self.export_manager
|
|
|
|
|
.write_results(&self.results, self.options.time_unit)?;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Ok(())
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
pub fn print_relative_speed_comparison(&self) {
|
|
|
|
|
if self.options.output_style == OutputStyleOption::Disabled {
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if self.results.len() < 2 {
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if let Some(mut annotated_results) = relative_speed::compute(&self.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..];
|
|
|
|
|
|
|
|
|
|
println!("{}", "Summary".bold());
|
|
|
|
|
println!(" '{}' ran", fastest.result.command.cyan());
|
|
|
|
|
|
|
|
|
|
for item in others {
|
|
|
|
|
println!(
|
|
|
|
|
"{}{} times faster than '{}'",
|
|
|
|
|
format!("{:8.2}", item.relative_speed).bold().green(),
|
|
|
|
|
if let Some(stddev) = item.relative_speed_stddev {
|
|
|
|
|
format!(" ± {}", format!("{:.2}", stddev).green())
|
|
|
|
|
} else {
|
|
|
|
|
"".into()
|
|
|
|
|
},
|
|
|
|
|
&item.result.command.magenta()
|
|
|
|
|
);
|
|
|
|
|
}
|
2022-02-20 13:44:34 +01:00
|
|
|
} else {
|
2022-02-20 14:04:37 +01:00
|
|
|
eprintln!(
|
|
|
|
|
"{}: The benchmark comparison could not be computed as some benchmark times are zero. \
|
|
|
|
|
This could be caused by background interference during the initial calibration phase \
|
|
|
|
|
of hyperfine, in combination with very fast commands (faster than a few milliseconds). \
|
|
|
|
|
Try to re-run the benchmark on a quiet system. If it does not help, you command is \
|
|
|
|
|
most likely too fast to be accurately benchmarked by hyperfine.",
|
|
|
|
|
"Note".bold().red()
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
}
|
2022-02-20 13:44:34 +01:00
|
|
|
}
|