Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 4 additions & 4 deletions src/benchmark/benchmark_result.rs
Original file line number Diff line number Diff line change
@@ -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
Expand Down Expand Up @@ -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>,
}
18 changes: 14 additions & 4 deletions src/benchmark/scheduler.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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(),
}
}

Expand Down Expand Up @@ -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());
Expand All @@ -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 {
Expand All @@ -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()
);
}
}
Expand All @@ -108,7 +118,7 @@ impl<'a> Scheduler<'a> {
} else {
" ".into()
},
&item.result.command_with_unused_parameters,
&(get_command_from_result(item.result)),
);
}
}
Expand Down
7 changes: 7 additions & 0 deletions src/cli.rs
Original file line number Diff line number Diff line change
Expand Up @@ -257,6 +257,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")
Expand Down
10 changes: 6 additions & 4 deletions src/export/json.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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)]
Expand All @@ -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');
}
Expand Down
2 changes: 1 addition & 1 deletion src/export/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ use std::io::Write;

mod asciidoc;
mod csv;
mod json;
pub mod json;
mod markdown;
mod markup;
mod orgmode;
Expand Down
31 changes: 31 additions & 0 deletions src/import.rs
Original file line number Diff line number Diff line change
@@ -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,
}
}
6 changes: 5 additions & 1 deletion src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -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;
Expand All @@ -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()?;
Expand Down