2018-03-24 18:30:52 -04:00
|
|
|
use std::env;
|
2018-01-13 16:50:02 +01:00
|
|
|
|
2018-05-22 22:57:51 +02:00
|
|
|
use colored::*;
|
2018-01-13 16:50:02 +01:00
|
|
|
|
2021-08-24 21:24:34 +02:00
|
|
|
pub mod app;
|
|
|
|
|
pub mod benchmark;
|
|
|
|
|
pub mod command;
|
|
|
|
|
pub mod error;
|
|
|
|
|
pub mod export;
|
2021-08-24 22:16:40 +02:00
|
|
|
pub mod min_max;
|
2021-08-24 21:24:34 +02:00
|
|
|
pub mod options;
|
|
|
|
|
pub mod outlier_detection;
|
2022-02-06 19:40:54 +01:00
|
|
|
pub mod output;
|
2021-08-24 21:24:34 +02:00
|
|
|
pub mod parameter_range;
|
2021-08-24 22:12:42 +02:00
|
|
|
pub mod relative_speed;
|
2021-08-24 21:24:34 +02:00
|
|
|
pub mod shell;
|
|
|
|
|
pub mod timer;
|
2021-08-24 22:01:26 +02:00
|
|
|
pub mod tokenize;
|
2021-08-24 21:24:34 +02:00
|
|
|
pub mod types;
|
|
|
|
|
pub mod units;
|
2018-01-14 10:48:47 +01:00
|
|
|
|
2021-08-24 21:24:34 +02:00
|
|
|
use app::get_arg_matches;
|
2022-02-06 19:37:15 +01:00
|
|
|
use benchmark::result::BenchmarkResult;
|
2021-08-24 21:24:34 +02:00
|
|
|
use benchmark::{mean_shell_spawning_time, run_benchmark};
|
2022-02-06 19:31:15 +01:00
|
|
|
use command::{build_commands, Command};
|
2022-02-06 18:22:55 +01:00
|
|
|
use export::ExportManager;
|
2022-02-06 18:20:38 +01:00
|
|
|
use options::{Options, OutputStyleOption};
|
2018-01-14 10:48:47 +01:00
|
|
|
|
2022-02-06 17:44:28 +01:00
|
|
|
use anyhow::{bail, Result};
|
2018-01-14 11:41:27 +13:00
|
|
|
|
2021-08-24 22:06:49 +02:00
|
|
|
pub fn write_benchmark_comparison(results: &[BenchmarkResult]) {
|
|
|
|
|
if results.len() < 2 {
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
2021-08-24 22:12:42 +02:00
|
|
|
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));
|
2021-08-24 22:06:49 +02:00
|
|
|
|
|
|
|
|
let fastest = &annotated_results[0];
|
|
|
|
|
let others = &annotated_results[1..];
|
|
|
|
|
|
|
|
|
|
println!("{}", "Summary".bold());
|
|
|
|
|
println!(" '{}' ran", fastest.result.command.cyan());
|
|
|
|
|
|
|
|
|
|
for item in others {
|
|
|
|
|
println!(
|
2021-11-14 10:18:28 +01:00
|
|
|
"{}{} times faster than '{}'",
|
2021-08-24 22:06:49 +02:00
|
|
|
format!("{:8.2}", item.relative_speed).bold().green(),
|
2021-11-14 10:18:28 +01:00
|
|
|
if let Some(stddev) = item.relative_speed_stddev {
|
|
|
|
|
format!(" ± {}", format!("{:.2}", stddev).green())
|
|
|
|
|
} else {
|
|
|
|
|
"".into()
|
|
|
|
|
},
|
2021-08-24 22:06:49 +02:00
|
|
|
&item.result.command.magenta()
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
} else {
|
|
|
|
|
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-06 17:44:28 +01:00
|
|
|
fn run_benchmarks_and_print_comparison(
|
2020-10-16 10:47:26 +02:00
|
|
|
commands: &[Command<'_>],
|
2022-02-06 18:20:38 +01:00
|
|
|
options: &Options,
|
2020-10-16 10:47:26 +02:00
|
|
|
export_manager: &ExportManager,
|
2022-02-06 17:44:28 +01:00
|
|
|
) -> Result<()> {
|
2018-11-21 19:55:58 +01:00
|
|
|
let shell_spawning_time =
|
2019-07-13 10:38:51 +02:00
|
|
|
mean_shell_spawning_time(&options.shell, options.output_style, options.show_output)?;
|
2018-01-14 12:03:34 +01:00
|
|
|
|
2018-03-18 15:13:24 -04:00
|
|
|
let mut timing_results = vec![];
|
|
|
|
|
|
2019-10-07 08:05:25 +05:45
|
|
|
if let Some(preparation_command) = &options.preparation_command {
|
2019-10-13 14:46:00 +02:00
|
|
|
if preparation_command.len() > 1 && commands.len() != preparation_command.len() {
|
2022-02-06 17:44:28 +01:00
|
|
|
bail!(
|
2019-10-13 14:46:00 +02:00
|
|
|
"The '--prepare' option has to be provided just once or N times, where N is the \
|
2022-02-06 17:44:28 +01:00
|
|
|
number of benchmark commands."
|
2019-10-07 08:05:25 +05:45
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2018-01-14 12:03:34 +01:00
|
|
|
// Run the benchmarks
|
2018-01-14 13:34:22 +01:00
|
|
|
for (num, cmd) in commands.iter().enumerate() {
|
2018-03-18 15:13:24 -04:00
|
|
|
timing_results.push(run_benchmark(num, cmd, shell_spawning_time, options)?);
|
2020-10-17 15:23:45 +02:00
|
|
|
|
|
|
|
|
// Export (intermediate) results
|
2022-02-06 17:44:28 +01:00
|
|
|
export_manager.write_results(&timing_results, options.time_unit)?;
|
2018-01-14 12:03:34 +01:00
|
|
|
}
|
|
|
|
|
|
2020-10-16 10:47:26 +02:00
|
|
|
// Print relative speed comparison
|
|
|
|
|
if options.output_style != OutputStyleOption::Disabled {
|
|
|
|
|
write_benchmark_comparison(&timing_results);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Ok(())
|
2018-01-14 12:03:34 +01:00
|
|
|
}
|
|
|
|
|
|
2022-02-06 17:44:28 +01:00
|
|
|
fn run() -> Result<()> {
|
2022-02-06 18:19:37 +01:00
|
|
|
// Enabled ANSI colors on Windows 10
|
|
|
|
|
#[cfg(windows)]
|
|
|
|
|
colored::control::set_virtual_terminal(true).unwrap();
|
|
|
|
|
|
2018-03-24 18:30:52 -04:00
|
|
|
let matches = get_arg_matches(env::args_os());
|
2022-02-06 18:20:38 +01:00
|
|
|
let options = Options::from_cli_arguments(&matches)?;
|
2022-02-06 17:44:28 +01:00
|
|
|
let commands = build_commands(&matches)?;
|
2022-02-06 18:22:55 +01:00
|
|
|
let export_manager = ExportManager::from_cli_arguments(&matches)?;
|
2018-03-24 18:30:52 -04:00
|
|
|
|
2022-02-06 17:44:28 +01:00
|
|
|
run_benchmarks_and_print_comparison(&commands, &options, &export_manager)
|
|
|
|
|
}
|
2018-03-24 18:30:52 -04:00
|
|
|
|
2022-02-06 17:44:28 +01:00
|
|
|
fn main() {
|
|
|
|
|
match run() {
|
2020-10-16 10:47:26 +02:00
|
|
|
Ok(_) => {}
|
2022-02-06 17:44:28 +01:00
|
|
|
Err(e) => {
|
|
|
|
|
eprintln!("{} {:#}", "Error:".red(), e);
|
|
|
|
|
std::process::exit(1);
|
|
|
|
|
}
|
2018-03-24 18:30:52 -04:00
|
|
|
}
|
|
|
|
|
}
|