mirror of
https://github.com/sharkdp/hyperfine.git
synced 2024-09-11 14:07:02 +03:00
Compare commits
11 Commits
faf7851e89
...
a421a2ab8d
Author | SHA1 | Date | |
---|---|---|---|
|
a421a2ab8d | ||
|
981db9d102 | ||
|
ef1263279d | ||
|
539995aad1 | ||
|
c8bfd59d81 | ||
|
610c8c4a8a | ||
|
0033f23006 | ||
|
b90fa23237 | ||
|
6746cf120d | ||
|
1cb474f452 | ||
|
8c145f994d |
@ -1,20 +1,20 @@
|
|||||||
use std::collections::BTreeMap;
|
use std::collections::BTreeMap;
|
||||||
|
|
||||||
use serde::Serialize;
|
use serde::{Deserialize, Serialize};
|
||||||
|
|
||||||
use crate::util::units::Second;
|
use crate::util::units::Second;
|
||||||
|
|
||||||
/// Set of values that will be exported.
|
/// Set of values that will be exported.
|
||||||
// NOTE: `serde` is used for JSON serialization, but not for CSV serialization due to the
|
// NOTE: `serde` is used for JSON serialization, but not for CSV serialization due to the
|
||||||
// `parameters` map. Update `src/hyperfine/export/csv.rs` with new fields, as appropriate.
|
// `parameters` map. Update `src/hyperfine/export/csv.rs` with new fields, as appropriate.
|
||||||
#[derive(Debug, Default, Clone, Serialize, PartialEq)]
|
#[derive(Debug, Default, Clone, Serialize, Deserialize, PartialEq)]
|
||||||
pub struct BenchmarkResult {
|
pub struct BenchmarkResult {
|
||||||
/// The full command line of the program that is being benchmarked
|
/// The full command line of the program that is being benchmarked
|
||||||
pub command: String,
|
pub command: String,
|
||||||
|
|
||||||
/// The full command line of the program that is being benchmarked, possibly including a list of
|
/// The full command line of the program that is being benchmarked, possibly including a list of
|
||||||
/// parameters that were not used in the command line template.
|
/// parameters that were not used in the command line template.
|
||||||
#[serde(skip_serializing)]
|
#[serde(skip)]
|
||||||
pub command_with_unused_parameters: String,
|
pub command_with_unused_parameters: String,
|
||||||
|
|
||||||
/// The average run time
|
/// The average run time
|
||||||
@ -46,6 +46,6 @@ pub struct BenchmarkResult {
|
|||||||
pub exit_codes: Vec<Option<i32>>,
|
pub exit_codes: Vec<Option<i32>>,
|
||||||
|
|
||||||
/// Parameter values for this benchmark
|
/// Parameter values for this benchmark
|
||||||
#[serde(skip_serializing_if = "BTreeMap::is_empty")]
|
#[serde(default, skip_serializing_if = "BTreeMap::is_empty")]
|
||||||
pub parameters: BTreeMap<String, String>,
|
pub parameters: BTreeMap<String, String>,
|
||||||
}
|
}
|
||||||
|
@ -54,7 +54,7 @@ fn run_command_and_measure_common(
|
|||||||
);
|
);
|
||||||
|
|
||||||
let result = execute_and_measure(command)
|
let result = execute_and_measure(command)
|
||||||
.with_context(|| format!("Failed to run command '{}'", command_name))?;
|
.with_context(|| format!("Failed to run command '{command_name}'"))?;
|
||||||
|
|
||||||
if command_failure_action == CmdFailureAction::RaiseError && !result.status.success() {
|
if command_failure_action == CmdFailureAction::RaiseError && !result.status.success() {
|
||||||
bail!(
|
bail!(
|
||||||
@ -62,7 +62,7 @@ fn run_command_and_measure_common(
|
|||||||
Alternatively, use the '--show-output' option to debug what went wrong.",
|
Alternatively, use the '--show-output' option to debug what went wrong.",
|
||||||
result.status.code().map_or(
|
result.status.code().map_or(
|
||||||
"The process has been terminated by a signal".into(),
|
"The process has been terminated by a signal".into(),
|
||||||
|c| format!("Command terminated with non-zero exit code: {}", c)
|
|c| format!("Command terminated with non-zero exit code: {c}")
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -312,7 +312,7 @@ impl<'a> Benchmark<'a> {
|
|||||||
let (mean_str, time_unit) = format_duration_unit(t_mean, self.options.time_unit);
|
let (mean_str, time_unit) = format_duration_unit(t_mean, self.options.time_unit);
|
||||||
let min_str = format_duration(t_min, Some(time_unit));
|
let min_str = format_duration(t_min, Some(time_unit));
|
||||||
let max_str = format_duration(t_max, Some(time_unit));
|
let max_str = format_duration(t_max, Some(time_unit));
|
||||||
let num_str = format!("{} runs", t_num);
|
let num_str = format!("{t_num} runs");
|
||||||
|
|
||||||
let user_str = format_duration(user_mean, Some(time_unit));
|
let user_str = format_duration(user_mean, Some(time_unit));
|
||||||
let system_str = format_duration(system_mean, Some(time_unit));
|
let system_str = format_duration(system_mean, Some(time_unit));
|
||||||
|
@ -22,12 +22,13 @@ impl<'a> Scheduler<'a> {
|
|||||||
commands: &'a Commands,
|
commands: &'a Commands,
|
||||||
options: &'a Options,
|
options: &'a Options,
|
||||||
export_manager: &'a ExportManager,
|
export_manager: &'a ExportManager,
|
||||||
|
results: &'a Vec<BenchmarkResult>,
|
||||||
) -> Self {
|
) -> Self {
|
||||||
Self {
|
Self {
|
||||||
commands,
|
commands,
|
||||||
options,
|
options,
|
||||||
export_manager,
|
export_manager,
|
||||||
results: vec![],
|
results: results.to_vec(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -69,6 +70,14 @@ impl<'a> Scheduler<'a> {
|
|||||||
&self.results,
|
&self.results,
|
||||||
self.options.sort_order_speed_comparison,
|
self.options.sort_order_speed_comparison,
|
||||||
) {
|
) {
|
||||||
|
fn get_command_from_result<'b>(result: &'b BenchmarkResult) -> &'b str {
|
||||||
|
if !result.command_with_unused_parameters.is_empty() {
|
||||||
|
&result.command_with_unused_parameters
|
||||||
|
} else {
|
||||||
|
&result.command
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
match self.options.sort_order_speed_comparison {
|
match self.options.sort_order_speed_comparison {
|
||||||
SortOrder::MeanTime => {
|
SortOrder::MeanTime => {
|
||||||
println!("{}", "Summary".bold());
|
println!("{}", "Summary".bold());
|
||||||
@ -78,7 +87,7 @@ impl<'a> Scheduler<'a> {
|
|||||||
|
|
||||||
println!(
|
println!(
|
||||||
" {} ran",
|
" {} ran",
|
||||||
fastest.result.command_with_unused_parameters.cyan()
|
(get_command_from_result(&fastest.result)).cyan()
|
||||||
);
|
);
|
||||||
|
|
||||||
for item in others {
|
for item in others {
|
||||||
@ -86,11 +95,12 @@ impl<'a> Scheduler<'a> {
|
|||||||
"{}{} times faster than {}",
|
"{}{} times faster than {}",
|
||||||
format!("{:8.2}", item.relative_speed).bold().green(),
|
format!("{:8.2}", item.relative_speed).bold().green(),
|
||||||
if let Some(stddev) = item.relative_speed_stddev {
|
if let Some(stddev) = item.relative_speed_stddev {
|
||||||
format!(" ± {}", format!("{:.2}", stddev).green())
|
format!(" ± {}", format!("{stddev:.2}").green())
|
||||||
} else {
|
} else {
|
||||||
"".into()
|
"".into()
|
||||||
},
|
},
|
||||||
&item.result.command_with_unused_parameters.magenta()
|
// &item.result.command_with_unused_parameters.magenta()
|
||||||
|
&(get_command_from_result(&item.result)).magenta()
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -104,11 +114,11 @@ impl<'a> Scheduler<'a> {
|
|||||||
if item.is_fastest {
|
if item.is_fastest {
|
||||||
" ".into()
|
" ".into()
|
||||||
} else if let Some(stddev) = item.relative_speed_stddev {
|
} else if let Some(stddev) = item.relative_speed_stddev {
|
||||||
format!(" ± {}", format!("{:5.2}", stddev).green())
|
format!(" ± {}", format!("{stddev:5.2}").green())
|
||||||
} else {
|
} else {
|
||||||
" ".into()
|
" ".into()
|
||||||
},
|
},
|
||||||
&item.result.command_with_unused_parameters,
|
&(get_command_from_result(item.result)),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -283,6 +283,13 @@ fn build_command() -> Command {
|
|||||||
.help("Export the timing summary statistics and timings of individual runs as JSON to the given FILE. \
|
.help("Export the timing summary statistics and timings of individual runs as JSON to the given FILE. \
|
||||||
The output time unit is always seconds"),
|
The output time unit is always seconds"),
|
||||||
)
|
)
|
||||||
|
.arg(
|
||||||
|
Arg::new("import-json")
|
||||||
|
.long("import-json")
|
||||||
|
.action(ArgAction::Set)
|
||||||
|
.value_name("FILE")
|
||||||
|
.help("Import the timing summary statistics and timings of individual runs from a JSON FILE.")
|
||||||
|
)
|
||||||
.arg(
|
.arg(
|
||||||
Arg::new("export-markdown")
|
Arg::new("export-markdown")
|
||||||
.long("export-markdown")
|
.long("export-markdown")
|
||||||
|
@ -62,13 +62,13 @@ impl<'a> Command<'a> {
|
|||||||
let parameters = self
|
let parameters = self
|
||||||
.get_unused_parameters()
|
.get_unused_parameters()
|
||||||
.fold(String::new(), |output, (parameter, value)| {
|
.fold(String::new(), |output, (parameter, value)| {
|
||||||
output + &format!("{} = {}, ", parameter, value)
|
output + &format!("{parameter} = {value}, ")
|
||||||
});
|
});
|
||||||
let parameters = parameters.trim_end_matches(", ");
|
let parameters = parameters.trim_end_matches(", ");
|
||||||
let parameters = if parameters.is_empty() {
|
let parameters = if parameters.is_empty() {
|
||||||
"".into()
|
"".into()
|
||||||
} else {
|
} else {
|
||||||
format!(" ({})", parameters)
|
format!(" ({parameters})")
|
||||||
};
|
};
|
||||||
|
|
||||||
format!("{}{}", self.get_name(), parameters)
|
format!("{}{}", self.get_name(), parameters)
|
||||||
@ -81,7 +81,7 @@ impl<'a> Command<'a> {
|
|||||||
pub fn get_command(&self) -> Result<std::process::Command> {
|
pub fn get_command(&self) -> Result<std::process::Command> {
|
||||||
let command_line = self.get_command_line();
|
let command_line = self.get_command_line();
|
||||||
let mut tokens = shell_words::split(&command_line)
|
let mut tokens = shell_words::split(&command_line)
|
||||||
.with_context(|| format!("Failed to parse command '{}'", command_line))?
|
.with_context(|| format!("Failed to parse command '{command_line}'"))?
|
||||||
.into_iter();
|
.into_iter();
|
||||||
|
|
||||||
if let Some(program_name) = tokens.next() {
|
if let Some(program_name) = tokens.next() {
|
||||||
@ -100,17 +100,14 @@ impl<'a> Command<'a> {
|
|||||||
pub fn get_unused_parameters(&self) -> impl Iterator<Item = &(&'a str, ParameterValue)> {
|
pub fn get_unused_parameters(&self) -> impl Iterator<Item = &(&'a str, ParameterValue)> {
|
||||||
self.parameters
|
self.parameters
|
||||||
.iter()
|
.iter()
|
||||||
.filter(move |(parameter, _)| !self.expression.contains(&format!("{{{}}}", parameter)))
|
.filter(move |(parameter, _)| !self.expression.contains(&format!("{{{parameter}}}")))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn replace_parameters_in(&self, original: &str) -> String {
|
fn replace_parameters_in(&self, original: &str) -> String {
|
||||||
let mut result = String::new();
|
let mut result = String::new();
|
||||||
let mut replacements = BTreeMap::<String, String>::new();
|
let mut replacements = BTreeMap::<String, String>::new();
|
||||||
for (param_name, param_value) in &self.parameters {
|
for (param_name, param_value) in &self.parameters {
|
||||||
replacements.insert(
|
replacements.insert(format!("{{{param_name}}}"), param_value.to_string());
|
||||||
format!("{{{param_name}}}", param_name = param_name),
|
|
||||||
param_value.to_string(),
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
let mut remaining = original;
|
let mut remaining = original;
|
||||||
// Manually replace consecutive occurrences to avoid double-replacing: e.g.,
|
// Manually replace consecutive occurrences to avoid double-replacing: e.g.,
|
||||||
|
@ -32,7 +32,7 @@ impl MarkupExporter for AsciidocExporter {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn command(&self, cmd: &str) -> String {
|
fn command(&self, cmd: &str) -> String {
|
||||||
format!("`{}`", cmd)
|
format!("`{cmd}`")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -71,8 +71,7 @@ fn test_asciidoc_exporter_table_header() {
|
|||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
fn cfg_test_table_header(unit_short_name: &str) -> String {
|
fn cfg_test_table_header(unit_short_name: &str) -> String {
|
||||||
format!(
|
format!(
|
||||||
"[cols=\"<,>,>,>,>\"]\n|===\n| Command \n| Mean [{unit}] \n| Min [{unit}] \n| Max [{unit}] \n| Relative \n",
|
"[cols=\"<,>,>,>,>\"]\n|===\n| Command \n| Mean [{unit_short_name}] \n| Min [{unit_short_name}] \n| Max [{unit_short_name}] \n| Relative \n"
|
||||||
unit = unit_short_name
|
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -31,7 +31,7 @@ impl Exporter for CsvExporter {
|
|||||||
.collect();
|
.collect();
|
||||||
if let Some(res) = results.first() {
|
if let Some(res) = results.first() {
|
||||||
for param_name in res.parameters.keys() {
|
for param_name in res.parameters.keys() {
|
||||||
headers.push(Cow::Owned(format!("parameter_{}", param_name).into_bytes()));
|
headers.push(Cow::Owned(format!("parameter_{param_name}").into_bytes()));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
writer.write_record(headers)?;
|
writer.write_record(headers)?;
|
||||||
|
@ -8,9 +8,9 @@ use crate::util::units::Unit;
|
|||||||
|
|
||||||
use anyhow::Result;
|
use anyhow::Result;
|
||||||
|
|
||||||
#[derive(Serialize, Debug)]
|
#[derive(Serialize, Deserialize, Debug)]
|
||||||
struct HyperfineSummary<'a> {
|
pub struct HyperfineSummary {
|
||||||
results: &'a [BenchmarkResult],
|
pub results: Vec<BenchmarkResult>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Default)]
|
#[derive(Default)]
|
||||||
@ -23,7 +23,9 @@ impl Exporter for JsonExporter {
|
|||||||
_unit: Option<Unit>,
|
_unit: Option<Unit>,
|
||||||
_sort_order: SortOrder,
|
_sort_order: SortOrder,
|
||||||
) -> Result<Vec<u8>> {
|
) -> Result<Vec<u8>> {
|
||||||
let mut output = to_vec_pretty(&HyperfineSummary { results });
|
let mut output = to_vec_pretty(&HyperfineSummary {
|
||||||
|
results: results.to_vec(),
|
||||||
|
});
|
||||||
if let Ok(ref mut content) = output {
|
if let Ok(ref mut content) = output {
|
||||||
content.push(b'\n');
|
content.push(b'\n');
|
||||||
}
|
}
|
||||||
|
@ -24,7 +24,7 @@ impl MarkupExporter for MarkdownExporter {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn command(&self, cmd: &str) -> String {
|
fn command(&self, cmd: &str) -> String {
|
||||||
format!("`{}`", cmd)
|
format!("`{cmd}`")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -53,8 +53,7 @@ fn test_markdown_formatter_table_divider() {
|
|||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
fn cfg_test_table_header(unit_short_name: String) -> String {
|
fn cfg_test_table_header(unit_short_name: String) -> String {
|
||||||
format!(
|
format!(
|
||||||
"| Command | Mean [{unit}] | Min [{unit}] | Max [{unit}] | Relative |\n|:---|---:|---:|---:|---:|\n",
|
"| Command | Mean [{unit_short_name}] | Min [{unit_short_name}] | Max [{unit_short_name}] | Relative |\n|:---|---:|---:|---:|---:|\n"
|
||||||
unit = unit_short_name
|
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -32,9 +32,9 @@ pub trait MarkupExporter {
|
|||||||
// emit table header data
|
// emit table header data
|
||||||
table.push_str(&self.table_row(&[
|
table.push_str(&self.table_row(&[
|
||||||
"Command",
|
"Command",
|
||||||
&format!("Mean {}", notation),
|
&format!("Mean {notation}"),
|
||||||
&format!("Min {}", notation),
|
&format!("Min {notation}"),
|
||||||
&format!("Max {}", notation),
|
&format!("Max {notation}"),
|
||||||
"Relative",
|
"Relative",
|
||||||
]));
|
]));
|
||||||
|
|
||||||
@ -59,7 +59,7 @@ pub trait MarkupExporter {
|
|||||||
let rel_stddev_str = if entry.is_fastest {
|
let rel_stddev_str = if entry.is_fastest {
|
||||||
"".into()
|
"".into()
|
||||||
} else if let Some(stddev) = entry.relative_speed_stddev {
|
} else if let Some(stddev) = entry.relative_speed_stddev {
|
||||||
format!(" ± {:.2}", stddev)
|
format!(" ± {stddev:.2}")
|
||||||
} else {
|
} else {
|
||||||
"".into()
|
"".into()
|
||||||
};
|
};
|
||||||
@ -67,10 +67,10 @@ pub trait MarkupExporter {
|
|||||||
// prepare table row entries
|
// prepare table row entries
|
||||||
table.push_str(&self.table_row(&[
|
table.push_str(&self.table_row(&[
|
||||||
&self.command(&cmd_str),
|
&self.command(&cmd_str),
|
||||||
&format!("{}{}", mean_str, stddev_str),
|
&format!("{mean_str}{stddev_str}"),
|
||||||
&min_str,
|
&min_str,
|
||||||
&max_str,
|
&max_str,
|
||||||
&format!("{}{}", rel_str, rel_stddev_str),
|
&format!("{rel_str}{rel_stddev_str}"),
|
||||||
]))
|
]))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -3,7 +3,7 @@ use std::io::Write;
|
|||||||
|
|
||||||
mod asciidoc;
|
mod asciidoc;
|
||||||
mod csv;
|
mod csv;
|
||||||
mod json;
|
pub mod json;
|
||||||
mod markdown;
|
mod markdown;
|
||||||
mod markup;
|
mod markup;
|
||||||
mod orgmode;
|
mod orgmode;
|
||||||
@ -108,7 +108,7 @@ impl ExportManager {
|
|||||||
ExportTarget::Stdout
|
ExportTarget::Stdout
|
||||||
} else {
|
} else {
|
||||||
let _ = File::create(filename)
|
let _ = File::create(filename)
|
||||||
.with_context(|| format!("Could not create export file '{}'", filename))?;
|
.with_context(|| format!("Could not create export file '{filename}'"))?;
|
||||||
ExportTarget::File(filename.to_string())
|
ExportTarget::File(filename.to_string())
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
@ -153,5 +153,5 @@ impl ExportManager {
|
|||||||
fn write_to_file(filename: &str, content: &[u8]) -> Result<()> {
|
fn write_to_file(filename: &str, content: &[u8]) -> Result<()> {
|
||||||
let mut file = OpenOptions::new().write(true).open(filename)?;
|
let mut file = OpenOptions::new().write(true).open(filename)?;
|
||||||
file.write_all(content)
|
file.write_all(content)
|
||||||
.with_context(|| format!("Failed to export results to '{}'", filename))
|
.with_context(|| format!("Failed to export results to '{filename}'"))
|
||||||
}
|
}
|
||||||
|
@ -18,7 +18,7 @@ impl MarkupExporter for OrgmodeExporter {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn command(&self, cmd: &str) -> String {
|
fn command(&self, cmd: &str) -> String {
|
||||||
format!("={}=", cmd)
|
format!("={cmd}=")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -58,8 +58,7 @@ fn test_orgmode_formatter_table_line() {
|
|||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
fn cfg_test_table_header(unit_short_name: String) -> String {
|
fn cfg_test_table_header(unit_short_name: String) -> String {
|
||||||
format!(
|
format!(
|
||||||
"| Command | Mean [{unit}] | Min [{unit}] | Max [{unit}] | Relative |\n|--+--+--+--+--|\n",
|
"| Command | Mean [{unit_short_name}] | Min [{unit_short_name}] | Max [{unit_short_name}] | Relative |\n|--+--+--+--+--|\n"
|
||||||
unit = unit_short_name
|
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
31
src/import.rs
Normal file
31
src/import.rs
Normal file
@ -0,0 +1,31 @@
|
|||||||
|
use crate::{benchmark::benchmark_result::BenchmarkResult, export::json::HyperfineSummary};
|
||||||
|
use clap::ArgMatches;
|
||||||
|
use std::fs;
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||||
|
pub struct Importer {}
|
||||||
|
|
||||||
|
impl Importer {
|
||||||
|
pub fn from_cli_arguments(matches: &ArgMatches) -> Option<Vec<BenchmarkResult>> {
|
||||||
|
match matches.get_one::<String>("import-json") {
|
||||||
|
Some(file_name) => read_summary_from_file(file_name),
|
||||||
|
None => None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn read_summary_from_file(file_name: &str) -> Option<Vec<BenchmarkResult>> {
|
||||||
|
let file_content = match fs::read_to_string(file_name) {
|
||||||
|
Ok(content) => content,
|
||||||
|
Err(_) => {
|
||||||
|
eprintln!("Unable to load previous run from file {}", file_name);
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
let hyperfine_summary = serde_json::from_str::<HyperfineSummary>(&file_content);
|
||||||
|
match hyperfine_summary {
|
||||||
|
Ok(summary) => Some(summary.results),
|
||||||
|
Err(_) => None,
|
||||||
|
}
|
||||||
|
}
|
@ -9,6 +9,7 @@ use benchmark::scheduler::Scheduler;
|
|||||||
use cli::get_cli_arguments;
|
use cli::get_cli_arguments;
|
||||||
use command::Commands;
|
use command::Commands;
|
||||||
use export::ExportManager;
|
use export::ExportManager;
|
||||||
|
use import::Importer;
|
||||||
use options::Options;
|
use options::Options;
|
||||||
|
|
||||||
use anyhow::Result;
|
use anyhow::Result;
|
||||||
@ -19,6 +20,7 @@ pub mod cli;
|
|||||||
pub mod command;
|
pub mod command;
|
||||||
pub mod error;
|
pub mod error;
|
||||||
pub mod export;
|
pub mod export;
|
||||||
|
pub mod import;
|
||||||
pub mod options;
|
pub mod options;
|
||||||
pub mod outlier_detection;
|
pub mod outlier_detection;
|
||||||
pub mod output;
|
pub mod output;
|
||||||
@ -32,13 +34,15 @@ fn run() -> Result<()> {
|
|||||||
colored::control::set_virtual_terminal(true).unwrap();
|
colored::control::set_virtual_terminal(true).unwrap();
|
||||||
|
|
||||||
let cli_arguments = get_cli_arguments(env::args_os());
|
let cli_arguments = get_cli_arguments(env::args_os());
|
||||||
|
let previous_results = Importer::from_cli_arguments(&cli_arguments).unwrap_or(Vec::new());
|
||||||
|
|
||||||
let options = Options::from_cli_arguments(&cli_arguments)?;
|
let options = Options::from_cli_arguments(&cli_arguments)?;
|
||||||
let commands = Commands::from_cli_arguments(&cli_arguments)?;
|
let commands = Commands::from_cli_arguments(&cli_arguments)?;
|
||||||
let export_manager = ExportManager::from_cli_arguments(&cli_arguments, options.time_unit)?;
|
let export_manager = ExportManager::from_cli_arguments(&cli_arguments, options.time_unit)?;
|
||||||
|
|
||||||
options.validate_against_command_list(&commands)?;
|
options.validate_against_command_list(&commands)?;
|
||||||
|
|
||||||
let mut scheduler = Scheduler::new(&commands, &options, &export_manager);
|
let mut scheduler = Scheduler::new(&commands, &options, &export_manager, &previous_results);
|
||||||
scheduler.run_benchmarks()?;
|
scheduler.run_benchmarks()?;
|
||||||
scheduler.print_relative_speed_comparison();
|
scheduler.print_relative_speed_comparison();
|
||||||
scheduler.final_export()?;
|
scheduler.final_export()?;
|
||||||
|
@ -38,7 +38,7 @@ impl Default for Shell {
|
|||||||
impl fmt::Display for Shell {
|
impl fmt::Display for Shell {
|
||||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||||
match self {
|
match self {
|
||||||
Shell::Default(cmd) => write!(f, "{}", cmd),
|
Shell::Default(cmd) => write!(f, "{cmd}"),
|
||||||
Shell::Custom(cmdline) => write!(f, "{}", shell_words::join(cmdline)),
|
Shell::Custom(cmdline) => write!(f, "{}", shell_words::join(cmdline)),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -457,7 +457,7 @@ impl Options {
|
|||||||
fn test_default_shell() {
|
fn test_default_shell() {
|
||||||
let shell = Shell::default();
|
let shell = Shell::default();
|
||||||
|
|
||||||
let s = format!("{}", shell);
|
let s = format!("{shell}");
|
||||||
assert_eq!(&s, DEFAULT_SHELL);
|
assert_eq!(&s, DEFAULT_SHELL);
|
||||||
|
|
||||||
let cmd = shell.command();
|
let cmd = shell.command();
|
||||||
@ -468,7 +468,7 @@ fn test_default_shell() {
|
|||||||
fn test_can_parse_shell_command_line_from_str() {
|
fn test_can_parse_shell_command_line_from_str() {
|
||||||
let shell = Shell::parse_from_str("shell -x 'aaa bbb'").unwrap();
|
let shell = Shell::parse_from_str("shell -x 'aaa bbb'").unwrap();
|
||||||
|
|
||||||
let s = format!("{}", shell);
|
let s = format!("{shell}");
|
||||||
assert_eq!(&s, "shell -x 'aaa bbb'");
|
assert_eq!(&s, "shell -x 'aaa bbb'");
|
||||||
|
|
||||||
let cmd = shell.command();
|
let cmd = shell.command();
|
||||||
|
@ -16,7 +16,7 @@ impl Display for ParameterValue {
|
|||||||
ParameterValue::Text(ref value) => value.clone(),
|
ParameterValue::Text(ref value) => value.clone(),
|
||||||
ParameterValue::Numeric(value) => value.to_string(),
|
ParameterValue::Numeric(value) => value.to_string(),
|
||||||
};
|
};
|
||||||
write!(f, "{}", str)
|
write!(f, "{str}")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -26,7 +26,7 @@ impl Unit {
|
|||||||
/// Returns the Second value formatted for the Unit.
|
/// Returns the Second value formatted for the Unit.
|
||||||
pub fn format(self, value: Second) -> String {
|
pub fn format(self, value: Second) -> String {
|
||||||
match self {
|
match self {
|
||||||
Unit::Second => format!("{:.3}", value),
|
Unit::Second => format!("{value:.3}"),
|
||||||
Unit::MilliSecond => format!("{:.1}", value * 1e3),
|
Unit::MilliSecond => format!("{:.1}", value * 1e3),
|
||||||
Unit::MicroSecond => format!("{:.1}", value * 1e6),
|
Unit::MicroSecond => format!("{:.1}", value * 1e6),
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user