This commit is contained in:
Richard 2024-06-13 00:15:04 +00:00 committed by GitHub
commit a421a2ab8d
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
7 changed files with 68 additions and 14 deletions

View File

@ -1,20 +1,20 @@
use std::collections::BTreeMap;
use serde::Serialize;
use serde::{Deserialize, Serialize};
use crate::util::units::Second;
/// Set of values that will be exported.
// 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.
#[derive(Debug, Default, Clone, Serialize, PartialEq)]
#[derive(Debug, Default, Clone, Serialize, Deserialize, PartialEq)]
pub struct BenchmarkResult {
/// The full command line of the program that is being benchmarked
pub command: String,
/// 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.
#[serde(skip_serializing)]
#[serde(skip)]
pub command_with_unused_parameters: String,
/// The average run time
@ -46,6 +46,6 @@ pub struct BenchmarkResult {
pub exit_codes: Vec<Option<i32>>,
/// 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>,
}

View File

@ -22,12 +22,13 @@ impl<'a> Scheduler<'a> {
commands: &'a Commands,
options: &'a Options,
export_manager: &'a ExportManager,
results: &'a Vec<BenchmarkResult>,
) -> Self {
Self {
commands,
options,
export_manager,
results: vec![],
results: results.to_vec(),
}
}
@ -69,6 +70,14 @@ impl<'a> Scheduler<'a> {
&self.results,
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 {
SortOrder::MeanTime => {
println!("{}", "Summary".bold());
@ -78,7 +87,7 @@ impl<'a> Scheduler<'a> {
println!(
" {} ran",
fastest.result.command_with_unused_parameters.cyan()
(get_command_from_result(&fastest.result)).cyan()
);
for item in others {
@ -90,7 +99,8 @@ impl<'a> Scheduler<'a> {
} else {
"".into()
},
&item.result.command_with_unused_parameters.magenta()
// &item.result.command_with_unused_parameters.magenta()
&(get_command_from_result(&item.result)).magenta()
);
}
}
@ -108,7 +118,7 @@ impl<'a> Scheduler<'a> {
} else {
" ".into()
},
&item.result.command_with_unused_parameters,
&(get_command_from_result(item.result)),
);
}
}

View File

@ -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. \
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::new("export-markdown")
.long("export-markdown")

View File

@ -8,9 +8,9 @@ use crate::util::units::Unit;
use anyhow::Result;
#[derive(Serialize, Debug)]
struct HyperfineSummary<'a> {
results: &'a [BenchmarkResult],
#[derive(Serialize, Deserialize, Debug)]
pub struct HyperfineSummary {
pub results: Vec<BenchmarkResult>,
}
#[derive(Default)]
@ -23,7 +23,9 @@ impl Exporter for JsonExporter {
_unit: Option<Unit>,
_sort_order: SortOrder,
) -> 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 {
content.push(b'\n');
}

View File

@ -3,7 +3,7 @@ use std::io::Write;
mod asciidoc;
mod csv;
mod json;
pub mod json;
mod markdown;
mod markup;
mod orgmode;

31
src/import.rs Normal file
View 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,
}
}

View File

@ -9,6 +9,7 @@ use benchmark::scheduler::Scheduler;
use cli::get_cli_arguments;
use command::Commands;
use export::ExportManager;
use import::Importer;
use options::Options;
use anyhow::Result;
@ -19,6 +20,7 @@ pub mod cli;
pub mod command;
pub mod error;
pub mod export;
pub mod import;
pub mod options;
pub mod outlier_detection;
pub mod output;
@ -32,13 +34,15 @@ fn run() -> Result<()> {
colored::control::set_virtual_terminal(true).unwrap();
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 commands = Commands::from_cli_arguments(&cli_arguments)?;
let export_manager = ExportManager::from_cli_arguments(&cli_arguments, options.time_unit)?;
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.print_relative_speed_comparison();
scheduler.final_export()?;