mirror of
https://github.com/sharkdp/hyperfine.git
synced 2026-11-01 17:00:18 +00:00
Add export manager and CSV export capability
This commit is contained in:
1 parent
ab4dbe998e
commit
a91912f322
7 files changed
+260
-3
No files matched your search
@@ -11,6 +11,7 @@ use hyperfine::outlier_detection::{modified_zscores, OUTLIER_THRESHOLD};
|
||||
use hyperfine::timer::{TimerStart, TimerStop};
|
||||
use hyperfine::timer::wallclocktimer::WallClockTimer;
|
||||
use hyperfine::shell::execute_and_time;
|
||||
use hyperfine::export::{ExportEntry, ExportManager};
|
||||
|
||||
/// Results from timing a single shell command
|
||||
#[derive(Debug, Default, Copy, Clone)]
|
||||
@@ -136,6 +137,7 @@ pub fn run_benchmark(
|
||||
cmd: &str,
|
||||
shell_spawning_time: TimingResult,
|
||||
options: &HyperfineOptions,
|
||||
exporter: &mut Option<Box<ExportManager>>,
|
||||
) -> io::Result<()> {
|
||||
println!(
|
||||
"{}{}: {}",
|
||||
@@ -265,6 +267,11 @@ pub fn run_benchmark(
|
||||
// Warnings
|
||||
let mut warnings = vec![];
|
||||
|
||||
if let &mut Some(ref mut mgr) = exporter {
|
||||
let entry = ExportEntry::new(cmd.to_string(), t_mean, t_stddev, user_mean, system_mean);
|
||||
mgr.add_result(entry);
|
||||
}
|
||||
|
||||
// Check execution time
|
||||
if times_real.iter().any(|&t| t < MIN_EXECUTION_TIME) {
|
||||
warnings.push(Warnings::FastExecutionTime);
|
||||
|
||||
@@ -0,0 +1,32 @@
|
||||
use super::{ExportEntry, ResultExporter};
|
||||
|
||||
use csv::WriterBuilder;
|
||||
use std::io::Result;
|
||||
|
||||
pub struct CsvExporter {
|
||||
results: Vec<ExportEntry>,
|
||||
out_file: String,
|
||||
}
|
||||
|
||||
impl ResultExporter for CsvExporter {
|
||||
fn add_entry(&mut self, entry: ExportEntry) {
|
||||
self.results.push(entry);
|
||||
}
|
||||
|
||||
fn write(&self) -> Result<()> {
|
||||
let mut writer = WriterBuilder::new().from_path(&self.out_file)?;
|
||||
for res in &self.results {
|
||||
writer.serialize(res)?;
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
impl CsvExporter {
|
||||
pub fn new(file_name: String) -> Self {
|
||||
CsvExporter {
|
||||
results: Vec::new(),
|
||||
out_file: file_name,
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,96 @@
|
||||
mod csv;
|
||||
|
||||
use self::csv::CsvExporter;
|
||||
|
||||
use std::io::Result;
|
||||
|
||||
/// The ExportEntry is the main set of values that will
|
||||
/// be exported to files when requested.
|
||||
#[derive(Debug, Default, Clone, Serialize)]
|
||||
pub struct ExportEntry {
|
||||
/// The command that was run
|
||||
command: String,
|
||||
/// The mean run time
|
||||
mean: f64,
|
||||
/// The standard deviation of all run times
|
||||
stddev: f64,
|
||||
/// Time spend in user space
|
||||
user: f64,
|
||||
/// Time spent in system space
|
||||
system: f64,
|
||||
}
|
||||
|
||||
impl ExportEntry {
|
||||
/// Create a new ExportEntry with the given values
|
||||
pub fn new(command: String, mean: f64, stddev: f64, user: f64, system: f64) -> Self {
|
||||
ExportEntry {
|
||||
command,
|
||||
mean,
|
||||
stddev,
|
||||
user,
|
||||
system,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// The ResultExportType enum is used to denote the desired form
|
||||
/// of exporter to use for a given file.
|
||||
pub enum ResultExportType {
|
||||
/// Export to a csv file with the provided name
|
||||
Csv(String),
|
||||
}
|
||||
|
||||
/// A ResultExporter is responsible for writing all results to the
|
||||
/// appropriate file
|
||||
pub trait ResultExporter {
|
||||
/// Add an additional entry to the exporter for writing
|
||||
fn add_entry(&mut self, entry: ExportEntry);
|
||||
/// Write all entries to the target destination
|
||||
fn write(&self) -> Result<()>;
|
||||
}
|
||||
|
||||
/// The ExportManager handles coordination of multiple ResultExporters
|
||||
pub trait ExportManager {
|
||||
/// Add a new exporter to this manager for the given type
|
||||
fn add_exporter(&mut self, for_type: &ResultExportType);
|
||||
|
||||
/// Add a new result to all exporters contained in the manager
|
||||
fn add_result(&mut self, result: ExportEntry);
|
||||
|
||||
/// Trigger writes from all exporters
|
||||
fn write_results(&self) -> Result<()>;
|
||||
}
|
||||
|
||||
/// Create a new ExportManager
|
||||
pub fn create_export_manager() -> Box<ExportManager> {
|
||||
Box::new(Exporter {
|
||||
exporters: Vec::new(),
|
||||
})
|
||||
}
|
||||
|
||||
/// The Exporter is the internal implementation of the ExportManager
|
||||
struct Exporter {
|
||||
exporters: Vec<Box<ResultExporter>>,
|
||||
}
|
||||
|
||||
impl ExportManager for Exporter {
|
||||
fn add_exporter(&mut self, for_type: &ResultExportType) {
|
||||
match for_type {
|
||||
&ResultExportType::Csv(ref file_name) => self.exporters
|
||||
.push(Box::from(CsvExporter::new(file_name.clone()))),
|
||||
};
|
||||
}
|
||||
|
||||
fn add_result(&mut self, result: ExportEntry) {
|
||||
for exp in self.exporters.iter_mut() {
|
||||
exp.add_entry(result.clone());
|
||||
}
|
||||
}
|
||||
|
||||
fn write_results(&self) -> Result<()> {
|
||||
for exp in &self.exporters {
|
||||
exp.write()?;
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
@@ -5,3 +5,4 @@ pub mod outlier_detection;
|
||||
pub mod warnings;
|
||||
pub mod timer;
|
||||
pub mod shell;
|
||||
pub mod export;
|
||||
+36
-3
@@ -6,7 +6,12 @@ extern crate cfg_if;
|
||||
#[macro_use]
|
||||
extern crate clap;
|
||||
extern crate colored;
|
||||
extern crate csv;
|
||||
extern crate indicatif;
|
||||
extern crate serde;
|
||||
|
||||
#[macro_use]
|
||||
extern crate serde_derive;
|
||||
extern crate statistical;
|
||||
|
||||
cfg_if! {
|
||||
@@ -33,6 +38,7 @@ mod hyperfine;
|
||||
|
||||
use hyperfine::internal::{CmdFailureAction, HyperfineOptions, OutputStyleOption};
|
||||
use hyperfine::benchmark::{mean_shell_spawning_time, run_benchmark};
|
||||
use hyperfine::export::{create_export_manager, ExportManager, ResultExportType};
|
||||
|
||||
/// Print error message to stderr and terminate
|
||||
pub fn error(message: &str) -> ! {
|
||||
@@ -41,12 +47,16 @@ pub fn error(message: &str) -> ! {
|
||||
}
|
||||
|
||||
/// Runs the benchmark for the given commands
|
||||
fn run(commands: &Vec<&str>, options: &HyperfineOptions) -> io::Result<()> {
|
||||
fn run(
|
||||
commands: &Vec<&str>,
|
||||
options: &HyperfineOptions,
|
||||
exporter: &mut Option<Box<ExportManager>>,
|
||||
) -> io::Result<()> {
|
||||
let shell_spawning_time = mean_shell_spawning_time(&options.output_style)?;
|
||||
|
||||
// Run the benchmarks
|
||||
for (num, cmd) in commands.iter().enumerate() {
|
||||
run_benchmark(num, cmd, shell_spawning_time, options)?;
|
||||
run_benchmark(num, cmd, shell_spawning_time, options, exporter)?;
|
||||
}
|
||||
|
||||
Ok(())
|
||||
@@ -129,6 +139,13 @@ fn main() {
|
||||
.short("i")
|
||||
.help("Ignore non-zero exit codes."),
|
||||
)
|
||||
.arg(
|
||||
Arg::with_name("export-csv")
|
||||
.long("export-csv")
|
||||
.takes_value(true)
|
||||
.value_name("FILE")
|
||||
.help("Export the timing results to the given file in csv format."),
|
||||
)
|
||||
.help_message("Print this help message.")
|
||||
.version_message("Show version information.")
|
||||
.get_matches();
|
||||
@@ -158,6 +175,18 @@ fn main() {
|
||||
},
|
||||
};
|
||||
|
||||
// Initial impl since we're only doing csv files, expand once we have multiple
|
||||
// export types. Simplest probably to do the same for each, but check for
|
||||
// None manager on later additions (JSON, Markdown, etc.)
|
||||
let mut export_manager = match matches.value_of("export-csv") {
|
||||
Some(filename) => {
|
||||
let mut export_manager = create_export_manager();
|
||||
export_manager.add_exporter(&ResultExportType::Csv(filename.to_string()));
|
||||
Some(export_manager)
|
||||
}
|
||||
None => None,
|
||||
};
|
||||
|
||||
// We default Windows to NoColor if full had been specified.
|
||||
if cfg!(windows) && options.output_style == OutputStyleOption::Full {
|
||||
options.output_style = OutputStyleOption::NoColor;
|
||||
@@ -172,9 +201,13 @@ fn main() {
|
||||
}
|
||||
|
||||
let commands = matches.values_of("command").unwrap().collect();
|
||||
let res = run(&commands, &options);
|
||||
let res = run(&commands, &options, &mut export_manager);
|
||||
|
||||
if let Err(e) = res {
|
||||
error(e.description());
|
||||
}
|
||||
|
||||
if let Some(exporter) = export_manager {
|
||||
exporter.write_results().unwrap();
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user