diff --git a/src/benchmark/mod.rs b/src/benchmark/mod.rs index d504e4b..3c29f4f 100644 --- a/src/benchmark/mod.rs +++ b/src/benchmark/mod.rs @@ -330,9 +330,9 @@ impl<'a> Benchmark<'a> { let benchmark_iteration = BenchmarkIteration::Benchmark(i + 1); let msg = { - let mean = measurements - .time_wall_clock_mean() - .format_auto(self.options.time_unit); + let t_wall_clock_mean = measurements.time_wall_clock_mean(); + let time_unit = t_wall_clock_mean.suitable_unit(); + let mean = t_wall_clock_mean.format(time_unit); format!("Current estimate: {}", mean.to_string().green()) }; @@ -370,13 +370,13 @@ impl<'a> Benchmark<'a> { .options .time_unit .unwrap_or(t_wall_clock_mean.suitable_unit()); - let mean_str = t_wall_clock_mean.format_auto(Some(time_unit)); - let min_str = measurements.min().format_auto(Some(time_unit)); - let max_str = measurements.max().format_auto(Some(time_unit)); + let mean_str = t_wall_clock_mean.format(time_unit); + let min_str = measurements.min().format(time_unit); + let max_str = measurements.max().format(time_unit); let num_str = format!("{num_runs} runs", num_runs = measurements.len()); - let user_str = measurements.time_user_mean().format_auto(Some(time_unit)); - let system_str = measurements.time_system_mean().format_auto(Some(time_unit)); + let user_str = measurements.time_user_mean().format(time_unit); + let system_str = measurements.time_system_mean().format(time_unit); if self.options.output_style != OutputStyleOption::Disabled { if measurements.len() == 1 { @@ -389,7 +389,7 @@ impl<'a> Benchmark<'a> { system_str.blue() )?; } else { - let stddev_str = measurements.stddev().unwrap().format_auto(Some(time_unit)); + let stddev_str = measurements.stddev().unwrap().format(time_unit); console_writeln!( stdout, diff --git a/src/export/csv.rs b/src/export/csv.rs index f6fb60c..614afce 100644 --- a/src/export/csv.rs +++ b/src/export/csv.rs @@ -53,7 +53,8 @@ impl Exporter for CsvExporter { res.measurements.max(), ] { fields.push(Cow::Owned( - f.format(CSV_UNIT, Some(CSV_PRECISION)).into_bytes(), + f.format_with_precision(CSV_UNIT, CSV_PRECISION) + .into_bytes(), )) } for v in res.parameters.values() { diff --git a/src/export/markup.rs b/src/export/markup.rs index 0c10a6d..13ac565 100644 --- a/src/export/markup.rs +++ b/src/export/markup.rs @@ -51,11 +51,9 @@ pub trait MarkupExporter { let result = &entry.result; // prepare data row strings let cmd_str = result.command_with_unused_parameters().replace('|', "\\|"); - let mean_str = result - .mean_wall_clock_time() - .format_value_auto(Some(time_unit)); + let mean_str = result.mean_wall_clock_time().format_value(time_unit); let stddev_str = if let Some(stddev) = result.measurements.stddev() { - format!(" ± {}", stddev.format_value_auto(Some(time_unit))) + format!(" ± {}", stddev.format_value(time_unit)) } else { "".into() }; diff --git a/src/output/warnings.rs b/src/output/warnings.rs index bf358be..be5a78a 100644 --- a/src/output/warnings.rs +++ b/src/output/warnings.rs @@ -25,7 +25,7 @@ impl fmt::Display for Warnings { inaccurate because hyperfine can not calibrate the shell startup time much \ more precise than this limit. You can try to use the `-N`/`--shell=none` \ option to disable the shell completely.", - min_execution_time = MIN_EXECUTION_TIME.format_auto(None) + min_execution_time = MIN_EXECUTION_TIME.format_auto() ), Warnings::NonZeroExitCode => write!(f, "Ignoring non-zero exit code."), Warnings::SlowInitialRun(time_first_run, ref options) => write!( @@ -33,7 +33,7 @@ impl fmt::Display for Warnings { "The first benchmarking run for this command was significantly slower than the \ rest ({time}). This could be caused by (filesystem) caches that were not filled until \ after the first run. {hints}", - time=time_first_run.format_auto(None), + time=time_first_run.format_auto(), hints=match (options.warmup_in_use, options.prepare_in_use) { (true, true) => "You are already using both the '--warmup' option as well \ as the '--prepare' option. Consider re-running the benchmark on a quiet system. \ diff --git a/src/quantity/mod.rs b/src/quantity/mod.rs index f5a2109..eb9b0f2 100644 --- a/src/quantity/mod.rs +++ b/src/quantity/mod.rs @@ -28,9 +28,10 @@ pub trait TimeQuantity { fn suitable_unit(&self) -> TimeUnit; - fn format(&self, u: TimeUnit, precision: Option) -> String; - fn format_auto(&self, time_unit: Option) -> String; - fn format_value_auto(&self, time_unit: Option) -> String; + fn format_with_precision(&self, u: TimeUnit, precision: usize) -> String; + fn format(&self, u: TimeUnit) -> String; + fn format_auto(&self) -> String; + fn format_value(&self, time_unit: TimeUnit) -> String; } impl TimeQuantity for Time { @@ -44,27 +45,27 @@ impl TimeQuantity for Time { } } - /// Format the given time duration as a string. - fn format(&self, u: TimeUnit, precision: Option) -> String { - let precision = precision.unwrap_or_else(|| if u == TimeUnit::Second { 3 } else { 1 }); + /// Format the time duration in the given unit with the given precision. + fn format_with_precision(&self, u: TimeUnit, precision: usize) -> String { u.format(*self, precision) } - /// Format the given time duration as a string. The output-unit can be enforced by setting `unit` to - /// `Some(target_unit)`. If `unit` is `None`, it will be determined automatically. - fn format_auto(&self, time_unit: Option) -> String { - let time_unit = time_unit.unwrap_or_else(|| self.suitable_unit()); - - let value = self.format(time_unit, None); - - format!("{} {}", value, time_unit.short_name()) + /// Format the time duration in the given unit. + fn format(&self, unit: TimeUnit) -> String { + let value = self.format_with_precision(unit, unit.preferred_precision()); + format!("{} {}", value, unit.short_name()) } - /// Like `format_duration`, but returns the target unit as well. - fn format_value_auto(&self, time_unit: Option) -> String { - let time_unit = time_unit.unwrap_or_else(|| self.suitable_unit()); + /// Like `format`, but without displaying the unit. + fn format_value(&self, unit: TimeUnit) -> String { + self.format_with_precision(unit, unit.preferred_precision()) + } - self.format(time_unit, None) + /// Format the given time duration. The unit will be determined automatically. + fn format_auto(&self) -> String { + let time_unit = self.suitable_unit(); + let value = self.format(time_unit); + format!("{} {}", value, time_unit.short_name()) } } @@ -198,9 +199,9 @@ fn test_information() { #[test] fn test_format() { let time = Time::new::(123.4); - assert_eq!(time.format_auto(Some(TimeUnit::Second)), "0.123 s"); - assert_eq!(time.format_auto(Some(TimeUnit::MilliSecond)), "123.4 ms"); - assert_eq!(time.format_auto(Some(TimeUnit::MicroSecond)), "123400.0 µs"); + assert_eq!(time.format(TimeUnit::Second), "0.123 s"); + assert_eq!(time.format(TimeUnit::MilliSecond), "123.4 ms"); + assert_eq!(time.format(TimeUnit::MicroSecond), "123400.0 µs"); let peak_memory_usage = Information::new::(8.); assert_eq!(peak_memory_usage.to_string(byte), "8192 B"); @@ -214,7 +215,7 @@ fn test_mean() { Time::new::(234.5), ]; let result = mean(&values); - assert_eq!(result.format_auto(Some(TimeUnit::MilliSecond)), "178.9 ms"); + assert_eq!(result.format(TimeUnit::MilliSecond), "178.9 ms"); } #[test] @@ -241,12 +242,12 @@ fn test_suiteable_unit() { #[test] fn test_format_duration_unit_with_unit() { - let out = Time::new::(1.3).format_auto(Some(TimeUnit::Second)); + let out = Time::new::(1.3).format(TimeUnit::Second); assert_eq!("1.300 s", out); - let out = Time::new::(1.3).format_auto(Some(TimeUnit::MilliSecond)); + let out = Time::new::(1.3).format(TimeUnit::MilliSecond); assert_eq!("1300.0 ms", out); - let out = Time::new::(1.3).format_auto(Some(TimeUnit::MicroSecond)); + let out = Time::new::(1.3).format(TimeUnit::MicroSecond); assert_eq!("1300000.0 µs", out); } diff --git a/src/quantity/units.rs b/src/quantity/units.rs index 5765ba0..2c1511e 100644 --- a/src/quantity/units.rs +++ b/src/quantity/units.rs @@ -37,6 +37,15 @@ pub enum TimeUnit { Hour, } +impl TimeUnit { + pub fn preferred_precision(self) -> usize { + match self { + TimeUnit::Second => 3, + _ => 1, + } + } +} + struct Dispatcher> { u: PhantomData, }