From 14d773998a732a49d9867b67b06f9d95704706bc Mon Sep 17 00:00:00 2001 From: David Peter Date: Mon, 5 Oct 2026 14:13:58 +0200 Subject: [PATCH] Introduce new BenchmarkRun struct --- src/benchmark/benchmark_result.rs | 71 +++++++- src/benchmark/mod.rs | 27 ++- src/benchmark/relative_speed.rs | 35 ++-- src/benchmark/scheduler.rs | 22 +-- src/export/csv.rs | 85 ++++------ src/export/markup.rs | 8 +- src/export/tests.rs | 263 +++++++++++------------------- 7 files changed, 247 insertions(+), 264 deletions(-) diff --git a/src/benchmark/benchmark_result.rs b/src/benchmark/benchmark_result.rs index 387884d..6a2eea5 100644 --- a/src/benchmark/benchmark_result.rs +++ b/src/benchmark/benchmark_result.rs @@ -1,7 +1,19 @@ use std::collections::BTreeMap; -use serde::ser::SerializeStruct; -use serde::{Serialize, Serializer}; +use serde::Serialize; +use statistical::{mean, median, standard_deviation}; + +use crate::util::{ + min_max::{max, min}, + units::Second, +}; + +#[derive(Debug, Default, Clone, Serialize, PartialEq)] +pub struct BenchmarkRun { + pub wall_clock_time: Second, + // user_time: Second, + // system_time: Second, +} use crate::benchmark::measurement::Measurements; use crate::quantity::{byte, second, Time}; @@ -25,8 +37,21 @@ pub struct BenchmarkResult { /// The full command line, including parameters not used in the command template. pub command_with_unused_parameters: String, - /// Performance measurements and exit statuses for each run - pub measurements: Measurements, + /// Time spent in user mode + pub user: f64, + + /// Time spent in kernel mode + pub system: f64, + + /// All run time measurements + pub runs: Vec, + + /// Maximum memory usage of the process, in bytes + #[serde(skip_serializing_if = "Option::is_none")] + pub memory_usage_byte: Option>, + + /// Exit codes of all command invocations + pub exit_codes: Vec>, /// Parameter values for this benchmark pub parameters: BTreeMap, @@ -95,3 +120,41 @@ impl Serialize for BenchmarkResult { state.end() } } + +impl BenchmarkResult { + fn wall_clock_times(&self) -> Vec { + self.runs.iter().map(|run| run.wall_clock_time).collect() + } + + /// The average run time + pub fn mean(&self) -> Second { + mean(&self.wall_clock_times()) + } + + /// The standard deviation of all run times. Not available if only one run has been performed + pub fn stddev(&self) -> Option { + let times = self.wall_clock_times(); + + let t_mean = mean(×); + if times.len() > 1 { + Some(standard_deviation(×, Some(t_mean))) + } else { + None + } + } + + /// The median run time + pub fn median(&self) -> Second { + median(&self.wall_clock_times()) + } + + /// The minimum run time + pub fn min(&self) -> Second { + min(&self.wall_clock_times()) + } + + /// The maximum run time + pub fn max(&self) -> Second { + max(&self.wall_clock_times()) + } +} diff --git a/src/benchmark/mod.rs b/src/benchmark/mod.rs index caa589f..f5c7e28 100644 --- a/src/benchmark/mod.rs +++ b/src/benchmark/mod.rs @@ -8,6 +8,7 @@ use std::cmp; use std::io::{self, Write}; use std::time::Instant; +use crate::benchmark::benchmark_result::BenchmarkRun; use crate::benchmark::executor::BenchmarkIteration; use crate::command::Command; use crate::options::{ @@ -26,6 +27,7 @@ use measurement::{Measurement, Measurements}; use anyhow::{anyhow, Result}; use colored::*; +use statistical::{mean, standard_deviation}; use self::executor::Executor; @@ -369,11 +371,15 @@ impl<'a> Benchmark<'a> { } // Compute statistical quantities - let t_num = measurements.len(); - let t_mean = measurements.time_wall_clock_mean(); - let t_stddev = measurements.stddev(); - let t_min = measurements.min(); - let t_max = measurements.max(); + let t_num = times_real.len(); + let t_mean = mean(×_real); + let t_stddev = if times_real.len() > 1 { + Some(standard_deviation(×_real, Some(t_mean))) + } else { + None + }; + let t_min = min(×_real); + let t_max = max(×_real); let user_mean = measurements.time_user_mean(); let system_mean = measurements.time_system_mean(); @@ -484,7 +490,16 @@ impl<'a> Benchmark<'a> { Ok(BenchmarkResult { command: self.command.get_name(), command_with_unused_parameters: self.command.get_name_with_unused_parameters(), - measurements, + user: user_mean, + system: system_mean, + runs: times_real + .iter() + .map(|t| BenchmarkRun { + wall_clock_time: *t, + }) + .collect(), + memory_usage_byte: Some(memory_usage_byte), + exit_codes, parameters: self .command .get_parameters() diff --git a/src/benchmark/relative_speed.rs b/src/benchmark/relative_speed.rs index e62a591..fc18ae3 100644 --- a/src/benchmark/relative_speed.rs +++ b/src/benchmark/relative_speed.rs @@ -31,9 +31,7 @@ impl BenchmarkResultWithRelativeSpeed<'_> { } pub fn compare_mean_time(l: &BenchmarkResult, r: &BenchmarkResult) -> Ordering { - l.mean_wall_clock_time() - .partial_cmp(&r.mean_wall_clock_time()) - .unwrap_or(Ordering::Equal) + l.mean().partial_cmp(&r.mean()).unwrap_or(Ordering::Equal) } pub fn fastest_of(results: &[BenchmarkResult]) -> &BenchmarkResult { @@ -68,11 +66,9 @@ fn compute_relative_speeds<'a>( } let ratio = match relative_ordering { - Ordering::Less => reference.mean_wall_clock_time() / result.mean_wall_clock_time(), - Ordering::Equal => Ratio::new::(1.0), - Ordering::Greater => { - result.mean_wall_clock_time() / reference.mean_wall_clock_time() - } + Ordering::Less => reference.mean() / result.mean(), + Ordering::Equal => 1.0, + Ordering::Greater => result.mean() / reference.mean(), }; // https://en.wikipedia.org/wiki/Propagation_of_uncertainty#Example_formulas @@ -117,9 +113,7 @@ pub fn compute_with_check_from_reference<'a>( reference: &'a BenchmarkResult, sort_order: SortOrder, ) -> Option>> { - if fastest_of(results).mean_wall_clock_time() == Time::zero() - || reference.mean_wall_clock_time() == Time::zero() - { + if fastest_of(results).mean() == 0.0 || reference.mean() == 0.0 { return None; } @@ -132,7 +126,7 @@ pub fn compute_with_check( ) -> Option>> { let fastest = fastest_of(results); - if fastest.mean_wall_clock_time() == Time::zero() { + if fastest.mean() == 0.0 { return None; } @@ -153,19 +147,18 @@ pub fn compute<'a>( fn create_result(name: &str, mean: f64) -> BenchmarkResult { use std::collections::BTreeMap; - use crate::benchmark::measurement::{Measurement, Measurements}; - use crate::quantity::{second, Time}; + use crate::benchmark::benchmark_result::BenchmarkRun; BenchmarkResult { command: name.into(), command_with_unused_parameters: name.into(), - measurements: Measurements { - measurements: vec![Measurement { - time_wall_clock: Time::new::(mean), - time_user: Time::new::(mean), - ..Default::default() - }], - }, + user: mean, + system: 0.0, + runs: vec![BenchmarkRun { + wall_clock_time: mean, + }], + memory_usage_byte: None, + exit_codes: Vec::new(), parameters: BTreeMap::new(), } } diff --git a/src/benchmark/scheduler.rs b/src/benchmark/scheduler.rs index db036d6..56d75c1 100644 --- a/src/benchmark/scheduler.rs +++ b/src/benchmark/scheduler.rs @@ -205,16 +205,11 @@ fn generate_results(args: &[&'static str]) -> Result> { fn scheduler_basic() -> Result<()> { insta::assert_yaml_snapshot!(generate_results(&["--runs=2", "sleep 0.123", "sleep 0.456"])?, @r#" - command: sleep 0.123 - mean: 0.123 - stddev: 0 - median: 0.123 user: 0 system: 0 - min: 0.123 - max: 0.123 - times: - - 0.123 - - 0.123 + runs: + - wall_clock_time: 0.123 + - wall_clock_time: 0.123 memory_usage_byte: - 0 - 0 @@ -222,16 +217,11 @@ fn scheduler_basic() -> Result<()> { - 0 - 0 - command: sleep 0.456 - mean: 0.456 - stddev: 0 - median: 0.456 user: 0 system: 0 - min: 0.456 - max: 0.456 - times: - - 0.456 - - 0.456 + runs: + - wall_clock_time: 0.456 + - wall_clock_time: 0.456 memory_usage_byte: - 0 - 0 diff --git a/src/export/csv.rs b/src/export/csv.rs index 15cc3a5..27e8bf6 100644 --- a/src/export/csv.rs +++ b/src/export/csv.rs @@ -44,13 +44,13 @@ impl Exporter for CsvExporter { for res in results { let mut fields = vec![Cow::Borrowed(res.command.as_bytes())]; for f in &[ - res.mean_wall_clock_time(), - res.measurements.stddev().unwrap_or_default(), - res.measurements.median(), - res.measurements.time_user_mean(), - res.measurements.time_system_mean(), - res.measurements.min(), - res.measurements.max(), + res.mean(), + res.stddev().unwrap_or(0.0), + res.median(), + res.user, + res.system, + res.min(), + res.max(), ] { fields.push(Cow::Owned( f.format_with_precision(CSV_UNIT, CSV_PRECISION) @@ -67,6 +67,9 @@ impl Exporter for CsvExporter { } } +#[cfg(test)] +use crate::benchmark::benchmark_result::BenchmarkRun; + #[test] fn test_csv() { use crate::benchmark::benchmark_result::Parameter; @@ -82,29 +85,21 @@ fn test_csv() { BenchmarkResult { command: String::from("command_a"), command_with_unused_parameters: String::from("command_a"), - measurements: Measurements::new(vec![ - Measurement { - time_wall_clock: Time::new::(7.0), - time_user: Time::new::(7.0), - time_system: Time::zero(), - peak_memory_usage: Information::new::(1024.), - exit_status: ExitStatus::default(), + user: 3.0, + system: 4.0, + runs: vec![ + BenchmarkRun { + wall_clock_time: 7.0, }, - Measurement { - time_wall_clock: Time::new::(8.0), - time_user: Time::new::(8.0), - time_system: Time::zero(), - peak_memory_usage: Information::new::(1024.), - exit_status: ExitStatus::default(), + BenchmarkRun { + wall_clock_time: 8.0, }, - Measurement { - time_wall_clock: Time::new::(12.0), - time_user: Time::new::(12.0), - time_system: Time::zero(), - peak_memory_usage: Information::new::(1024.), - exit_status: ExitStatus::default(), + BenchmarkRun { + wall_clock_time: 12.0, }, - ]), + ], + memory_usage_byte: None, + exit_codes: vec![Some(0), Some(0), Some(0)], parameters: { let mut params = BTreeMap::new(); params.insert( @@ -127,29 +122,21 @@ fn test_csv() { BenchmarkResult { command: String::from("command_b"), command_with_unused_parameters: String::from("command_b"), - measurements: Measurements::new(vec![ - Measurement { - time_wall_clock: Time::new::(17.0), - time_user: Time::new::(17.0), - time_system: Time::zero(), - peak_memory_usage: Information::new::(1024.), - exit_status: ExitStatus::default(), + user: 13.0, + system: 14.0, + runs: vec![ + BenchmarkRun { + wall_clock_time: 17.0, }, - Measurement { - time_wall_clock: Time::new::(18.0), - time_user: Time::new::(18.0), - time_system: Time::zero(), - peak_memory_usage: Information::new::(1024.), - exit_status: ExitStatus::default(), + BenchmarkRun { + wall_clock_time: 18.0, }, - Measurement { - time_wall_clock: Time::new::(19.0), - time_user: Time::new::(19.0), - time_system: Time::zero(), - peak_memory_usage: Information::new::(1024.), - exit_status: ExitStatus::default(), + BenchmarkRun { + wall_clock_time: 19.0, }, - ]), + ], + memory_usage_byte: None, + exit_codes: vec![Some(0), Some(0), Some(0)], parameters: { let mut params = BTreeMap::new(); params.insert( @@ -180,7 +167,7 @@ fn test_csv() { insta::assert_snapshot!(actual, @r#" command,mean,stddev,median,user,system,min,max,parameter_bar,parameter_foo - command_a,9.000000,2.645751,8.000000,9.000000,0.000000,7.000000,12.000000,two,one - command_b,18.000000,1.000000,18.000000,18.000000,0.000000,17.000000,19.000000,seven,one + command_a,9,2.6457513110645907,8,3,4,7,12,two,one + command_b,18,1,18,13,14,17,19,seven,one "#); } diff --git a/src/export/markup.rs b/src/export/markup.rs index 0eea533..aac3795 100644 --- a/src/export/markup.rs +++ b/src/export/markup.rs @@ -53,9 +53,9 @@ pub trait MarkupExporter { let cmd_str = measurement .command_with_unused_parameters .replace('|', "\\|"); - let mean_str = measurement.mean_wall_clock_time().format_value(unit); - let stddev_str = if let Some(stddev) = measurement.measurements.stddev() { - format!(" ± {}", stddev.format_value(unit)) + let mean_str = format_duration_value(measurement.mean(), Some(unit)).0; + let stddev_str = if let Some(stddev) = measurement.stddev() { + format!(" ± {}", format_duration_value(stddev, Some(unit)).0) } else { "".into() }; @@ -116,7 +116,7 @@ pub trait MarkupExporter { fn determine_unit_from_results(results: &[BenchmarkResult]) -> TimeUnit { if let Some(first_result) = results.first() { // Use the first BenchmarkResult entry to determine the unit for all entries. - first_result.mean_wall_clock_time().suitable_unit() + format_duration_value(first_result.mean(), None).1 } else { // Default to `Second`. TimeUnit::Second diff --git a/src/export/tests.rs b/src/export/tests.rs index abe340a..527128c 100644 --- a/src/export/tests.rs +++ b/src/export/tests.rs @@ -1,6 +1,5 @@ use super::Exporter; -use crate::benchmark::benchmark_result::BenchmarkResult; -use crate::benchmark::measurement::{Measurement, Measurements}; +use crate::benchmark::benchmark_result::{BenchmarkResult, BenchmarkRun}; use crate::export::asciidoc::AsciidocExporter; use crate::export::orgmode::OrgmodeExporter; use crate::quantity::{byte, second, Information, Time, TimeUnit, Zero}; @@ -29,57 +28,41 @@ fn test_markup_export_auto_ms() { BenchmarkResult { command: String::from("sleep 0.1"), command_with_unused_parameters: String::from("sleep 0.1"), - measurements: Measurements::new(vec![ - Measurement { - time_wall_clock: Time::new::(0.09), - time_user: Time::new::(0.09), - time_system: Time::zero(), - peak_memory_usage: Information::new::(1024.), - exit_status: ExitStatus::default(), + user: 0.0009, + system: 0.0011, + runs: vec![ + BenchmarkRun { + wall_clock_time: 0.09, }, - Measurement { - time_wall_clock: Time::new::(0.10), - time_user: Time::new::(0.10), - time_system: Time::zero(), - peak_memory_usage: Information::new::(1024.), - exit_status: ExitStatus::default(), + BenchmarkRun { + wall_clock_time: 0.10, }, - Measurement { - time_wall_clock: Time::new::(0.14), - time_user: Time::new::(0.14), - time_system: Time::zero(), - peak_memory_usage: Information::new::(1024.), - exit_status: ExitStatus::default(), + BenchmarkRun { + wall_clock_time: 0.14, }, - ]), + ], + memory_usage_byte: None, + exit_codes: vec![Some(0), Some(0), Some(0)], parameters: BTreeMap::new(), }, BenchmarkResult { command: String::from("sleep 2"), command_with_unused_parameters: String::from("sleep 2"), - measurements: Measurements::new(vec![ - Measurement { - time_wall_clock: Time::new::(2.0), - time_user: Time::new::(2.0), - time_system: Time::zero(), - peak_memory_usage: Information::new::(1024.), - exit_status: ExitStatus::default(), + user: 0.0009, + system: 0.0012, + runs: vec![ + BenchmarkRun { + wall_clock_time: 2.0, }, - Measurement { - time_wall_clock: Time::new::(3.0), - time_user: Time::new::(3.0), - time_system: Time::zero(), - peak_memory_usage: Information::new::(1024.), - exit_status: ExitStatus::default(), + BenchmarkRun { + wall_clock_time: 3.0, }, - Measurement { - time_wall_clock: Time::new::(4.0), - time_user: Time::new::(4.0), - time_system: Time::zero(), - peak_memory_usage: Information::new::(1024.), - exit_status: ExitStatus::default(), + BenchmarkRun { + wall_clock_time: 4.0, }, - ]), + ], + memory_usage_byte: None, + exit_codes: vec![Some(0), Some(0), Some(0)], parameters: BTreeMap::new(), }, ]; @@ -130,57 +113,41 @@ fn test_markup_export_auto_s() { BenchmarkResult { command: String::from("sleep 2"), command_with_unused_parameters: String::from("sleep 2"), - measurements: Measurements::new(vec![ - Measurement { - time_wall_clock: Time::new::(2.1), - time_user: Time::new::(2.1), - time_system: Time::zero(), - peak_memory_usage: Information::new::(1024.), - exit_status: ExitStatus::default(), + user: 0.0009, + system: 0.0012, + runs: vec![ + BenchmarkRun { + wall_clock_time: 2.1, }, - Measurement { - time_wall_clock: Time::new::(2.2), - time_user: Time::new::(2.2), - time_system: Time::zero(), - peak_memory_usage: Information::new::(1024.), - exit_status: ExitStatus::default(), + BenchmarkRun { + wall_clock_time: 2.2, }, - Measurement { - time_wall_clock: Time::new::(2.3), - time_user: Time::new::(2.3), - time_system: Time::zero(), - peak_memory_usage: Information::new::(1024.), - exit_status: ExitStatus::default(), + BenchmarkRun { + wall_clock_time: 2.3, }, - ]), + ], + memory_usage_byte: None, + exit_codes: vec![Some(0), Some(0), Some(0)], parameters: BTreeMap::new(), }, BenchmarkResult { command: String::from("sleep 0.1"), command_with_unused_parameters: String::from("sleep 0.1"), - measurements: Measurements::new(vec![ - Measurement { - time_wall_clock: Time::new::(0.1), - time_user: Time::new::(0.1), - time_system: Time::zero(), - peak_memory_usage: Information::new::(1024.), - exit_status: ExitStatus::default(), + user: 0.0009, + system: 0.0011, + runs: vec![ + BenchmarkRun { + wall_clock_time: 0.1, }, - Measurement { - time_wall_clock: Time::new::(0.2), - time_user: Time::new::(0.2), - time_system: Time::zero(), - peak_memory_usage: Information::new::(1024.), - exit_status: ExitStatus::default(), + BenchmarkRun { + wall_clock_time: 0.2, }, - Measurement { - time_wall_clock: Time::new::(0.3), - time_user: Time::new::(0.3), - time_system: Time::zero(), - peak_memory_usage: Information::new::(1024.), - exit_status: ExitStatus::default(), + BenchmarkRun { + wall_clock_time: 0.3, }, - ]), + ], + memory_usage_byte: None, + exit_codes: vec![Some(0), Some(0), Some(0)], parameters: BTreeMap::new(), }, ]; @@ -231,57 +198,41 @@ fn test_markup_export_manual_ms() { BenchmarkResult { command: String::from("sleep 2"), command_with_unused_parameters: String::from("sleep 2"), - measurements: Measurements::new(vec![ - Measurement { - time_wall_clock: Time::new::(2.1), - time_user: Time::new::(2.1), - time_system: Time::zero(), - peak_memory_usage: Information::new::(1024.), - exit_status: ExitStatus::default(), + user: 0.0009, + system: 0.0012, + runs: vec![ + BenchmarkRun { + wall_clock_time: 2.1, }, - Measurement { - time_wall_clock: Time::new::(2.2), - time_user: Time::new::(2.2), - time_system: Time::zero(), - peak_memory_usage: Information::new::(1024.), - exit_status: ExitStatus::default(), + BenchmarkRun { + wall_clock_time: 2.2, }, - Measurement { - time_wall_clock: Time::new::(2.3), - time_user: Time::new::(2.3), - time_system: Time::zero(), - peak_memory_usage: Information::new::(1024.), - exit_status: ExitStatus::default(), + BenchmarkRun { + wall_clock_time: 2.3, }, - ]), + ], + memory_usage_byte: None, + exit_codes: vec![Some(0), Some(0), Some(0)], parameters: BTreeMap::new(), }, BenchmarkResult { command: String::from("sleep 0.1"), command_with_unused_parameters: String::from("sleep 0.1"), - measurements: Measurements::new(vec![ - Measurement { - time_wall_clock: Time::new::(0.1), - time_user: Time::new::(0.1), - time_system: Time::zero(), - peak_memory_usage: Information::new::(1024.), - exit_status: ExitStatus::default(), + user: 0.0009, + system: 0.0011, + runs: vec![ + BenchmarkRun { + wall_clock_time: 0.1, }, - Measurement { - time_wall_clock: Time::new::(0.2), - time_user: Time::new::(0.2), - time_system: Time::zero(), - peak_memory_usage: Information::new::(1024.), - exit_status: ExitStatus::default(), + BenchmarkRun { + wall_clock_time: 0.2, }, - Measurement { - time_wall_clock: Time::new::(0.3), - time_user: Time::new::(0.3), - time_system: Time::zero(), - peak_memory_usage: Information::new::(1024.), - exit_status: ExitStatus::default(), + BenchmarkRun { + wall_clock_time: 0.3, }, - ]), + ], + memory_usage_byte: None, + exit_codes: vec![Some(0), Some(0), Some(0)], parameters: BTreeMap::new(), }, ]; @@ -331,69 +282,53 @@ fn test_markup_export_manual_s() { BenchmarkResult { command: String::from("sleep 2"), command_with_unused_parameters: String::from("sleep 2"), - measurements: Measurements::new(vec![ - Measurement { - time_wall_clock: Time::new::(2.01), - time_user: Time::new::(2.01), - time_system: Time::zero(), - peak_memory_usage: Information::new::(1024.), - exit_status: ExitStatus::default(), + user: 0.0009, + system: 0.0012, + runs: vec![ + BenchmarkRun { + wall_clock_time: 2.01, }, - Measurement { - time_wall_clock: Time::new::(2.02), - time_user: Time::new::(2.02), - time_system: Time::zero(), - peak_memory_usage: Information::new::(1024.), - exit_status: ExitStatus::default(), + BenchmarkRun { + wall_clock_time: 2.02, }, - Measurement { - time_wall_clock: Time::new::(2.03), - time_user: Time::new::(2.03), - time_system: Time::zero(), - peak_memory_usage: Information::new::(1024.), - exit_status: ExitStatus::default(), + BenchmarkRun { + wall_clock_time: 2.03, }, - ]), + ], + memory_usage_byte: None, + exit_codes: vec![Some(0), Some(0), Some(0)], parameters: BTreeMap::new(), }, BenchmarkResult { command: String::from("sleep 0.1"), command_with_unused_parameters: String::from("sleep 0.1"), - measurements: Measurements::new(vec![ - Measurement { - time_wall_clock: Time::new::(0.11), - time_user: Time::new::(0.11), - time_system: Time::zero(), - peak_memory_usage: Information::new::(1024.), - exit_status: ExitStatus::default(), + user: 0.0009, + system: 0.0011, + runs: vec![ + BenchmarkRun { + wall_clock_time: 0.11, }, - Measurement { - time_wall_clock: Time::new::(0.12), - time_user: Time::new::(0.12), - time_system: Time::zero(), - peak_memory_usage: Information::new::(1024.), - exit_status: ExitStatus::default(), + BenchmarkRun { + wall_clock_time: 0.12, }, - Measurement { - time_wall_clock: Time::new::(0.13), - time_user: Time::new::(0.13), - time_system: Time::zero(), - peak_memory_usage: Information::new::(1024.), - exit_status: ExitStatus::default(), + BenchmarkRun { + wall_clock_time: 0.13, }, - ]), + ], + memory_usage_byte: None, + exit_codes: vec![Some(0), Some(0), Some(0)], parameters: BTreeMap::new(), }, ]; - insta::assert_snapshot!(get_output::(&results, Some(TimeUnit::Second), SortOrder::Command), @r#" + insta::assert_snapshot!(get_output::(&results, Some(Unit::Second), SortOrder::Command), @r#" | Command | Mean [s] | Min [s] | Max [s] | Relative | |:---|---:|---:|---:|---:| | `sleep 2` | 2.020 ± 0.010 | 2.010 | 2.030 | 16.83 ± 1.41 | | `sleep 0.1` | 0.120 ± 0.010 | 0.110 | 0.130 | 1.00 | "#); - insta::assert_snapshot!(get_output::(&results, Some(TimeUnit::Second), SortOrder::MeanTime), @r#" + insta::assert_snapshot!(get_output::(&results, Some(Unit::Second), SortOrder::MeanTime), @r#" | Command | Mean [s] | Min [s] | Max [s] | Relative | |:---|---:|---:|---:|---:| | `sleep 0.1` | 0.120 ± 0.010 | 0.110 | 0.130 | 1.00 |