From 2793d7b9941d4dc3dcd2edc53855c8b7bebd895e Mon Sep 17 00:00:00 2001 From: David Peter Date: Thu, 20 Apr 2023 12:24:10 +0200 Subject: [PATCH] Do not export intermediate results to stdout, closes #640 --- src/benchmark/scheduler.rs | 11 +++++--- src/export/markup.rs | 1 + src/export/mod.rs | 57 ++++++++++++++++++++++++++------------ src/main.rs | 3 +- 4 files changed, 50 insertions(+), 22 deletions(-) diff --git a/src/benchmark/scheduler.rs b/src/benchmark/scheduler.rs index 734efbb60..e960494ae 100644 --- a/src/benchmark/scheduler.rs +++ b/src/benchmark/scheduler.rs @@ -44,10 +44,9 @@ impl<'a> Scheduler<'a> { self.results .push(Benchmark::new(number, cmd, self.options, &*executor).run()?); - // 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)?; + // We export results after each individual benchmark, because + // we would risk losing them if a later benchmark fails. + self.export_manager.write_results(&self.results, true)?; } Ok(()) @@ -94,4 +93,8 @@ impl<'a> Scheduler<'a> { ); } } + + pub fn final_export(&self) -> Result<()> { + self.export_manager.write_results(&self.results, false) + } } diff --git a/src/export/markup.rs b/src/export/markup.rs index 2b7c153d8..2ae6ad5f8 100644 --- a/src/export/markup.rs +++ b/src/export/markup.rs @@ -10,6 +10,7 @@ pub enum Alignment { Left, Right, } + pub trait MarkupExporter { fn table_results(&self, entries: &[BenchmarkResultWithRelativeSpeed], unit: Unit) -> String { // prepare table header strings diff --git a/src/export/mod.rs b/src/export/mod.rs index fec101609..556409c69 100644 --- a/src/export/mod.rs +++ b/src/export/mod.rs @@ -45,22 +45,31 @@ trait Exporter { fn serialize(&self, results: &[BenchmarkResult], unit: Option) -> Result>; } -struct ExporterWithFilename { +pub enum ExportTarget { + File(String), + Stdout, +} + +struct ExporterWithTarget { exporter: Box, - filename: String, + target: ExportTarget, } /// Handles the management of multiple file exporters. #[derive(Default)] pub struct ExportManager { - exporters: Vec, + exporters: Vec, + time_unit: Option, } impl ExportManager { /// Build the ExportManager that will export the results specified /// in the given ArgMatches - pub fn from_cli_arguments(matches: &ArgMatches) -> Result { - let mut export_manager = Self::default(); + pub fn from_cli_arguments(matches: &ArgMatches, time_unit: Option) -> Result { + let mut export_manager = Self { + exporters: vec![], + time_unit, + }; { let mut add_exporter = |flag, exporttype| -> Result<()> { if let Some(filename) = matches.get_one::(flag) { @@ -87,29 +96,43 @@ impl ExportManager { ExportType::Orgmode => Box::::default(), }; - self.exporters.push(ExporterWithFilename { + self.exporters.push(ExporterWithTarget { exporter, - filename: if filename == "-" { - if cfg!(windows) { - "con:".to_string() - } else { - "/dev/stdout".to_string() - } + target: if filename == "-" { + ExportTarget::Stdout } else { let _ = File::create(filename) .with_context(|| format!("Could not create export file '{}'", filename))?; - filename.to_string() + ExportTarget::File(filename.to_string()) }, }); Ok(()) } - /// Write the given results to all Exporters contained within this manager - pub fn write_results(&self, results: &[BenchmarkResult], unit: Option) -> Result<()> { + /// Write the given results to all Exporters. The 'intermediate' flag specifies + /// whether this is being called while still performing benchmarks, or if this + /// is the final call after all benchmarks have been finished. In the former case, + /// results are written to all file targets (to always have them up to date, even + /// if a benchmark fails). In the latter case, we only print to stdout targets (in + /// order not to clutter the output of hyperfine with intermediate results). + pub fn write_results(&self, results: &[BenchmarkResult], intermediate: bool) -> Result<()> { for e in &self.exporters { - let file_content = e.exporter.serialize(results, unit)?; - write_to_file(&e.filename, &file_content)?; + let content = || e.exporter.serialize(results, self.time_unit); + + match e.target { + ExportTarget::File(ref filename) => { + if intermediate { + write_to_file(filename, &content()?)? + } + } + ExportTarget::Stdout => { + if !intermediate { + println!(); + println!("{}", String::from_utf8(content()?).unwrap()); + } + } + } } Ok(()) } diff --git a/src/main.rs b/src/main.rs index 441991ada..a75d4bd07 100644 --- a/src/main.rs +++ b/src/main.rs @@ -34,13 +34,14 @@ fn run() -> Result<()> { let cli_arguments = get_cli_arguments(env::args_os()); 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)?; + 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); scheduler.run_benchmarks()?; scheduler.print_relative_speed_comparison(); + scheduler.final_export()?; Ok(()) }