From ebf127338ceaa89672e9e4f651ba62f8a5c6a218 Mon Sep 17 00:00:00 2001 From: David Peter Date: Mon, 5 Oct 2026 14:19:47 +0200 Subject: [PATCH] Further simplification of the API --- src/benchmark/mod.rs | 9 ++- src/export/markup.rs | 10 +--- src/output/warnings.rs | 4 +- src/quantity/mod.rs | 123 ++++++++++++++--------------------------- 4 files changed, 51 insertions(+), 95 deletions(-) diff --git a/src/benchmark/mod.rs b/src/benchmark/mod.rs index c8a9f18..d504e4b 100644 --- a/src/benchmark/mod.rs +++ b/src/benchmark/mod.rs @@ -365,9 +365,12 @@ impl<'a> Benchmark<'a> { } // Formatting and console output - let (mean_str, time_unit) = measurements - .time_wall_clock_mean() - .format_auto_with_unit(self.options.time_unit); + let t_wall_clock_mean = measurements.time_wall_clock_mean(); + let time_unit = self + .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 num_str = format!("{num_runs} runs", num_runs = measurements.len()); diff --git a/src/export/markup.rs b/src/export/markup.rs index 2331ac9..0c10a6d 100644 --- a/src/export/markup.rs +++ b/src/export/markup.rs @@ -53,10 +53,9 @@ pub trait MarkupExporter { let cmd_str = result.command_with_unused_parameters().replace('|', "\\|"); let mean_str = result .mean_wall_clock_time() - .format_value_auto(Some(time_unit)) - .0; + .format_value_auto(Some(time_unit)); let stddev_str = if let Some(stddev) = result.measurements.stddev() { - format!(" ± {}", stddev.format_value_auto(Some(time_unit)).0) + format!(" ± {}", stddev.format_value_auto(Some(time_unit))) } else { "".into() }; @@ -117,10 +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() - .format_auto_with_unit(None) - .1 + first_result.mean_wall_clock_time().suitable_unit() } else { // Default to `Second`. TimeUnit::Second diff --git a/src/output/warnings.rs b/src/output/warnings.rs index a0d5698..bf358be 100644 --- a/src/output/warnings.rs +++ b/src/output/warnings.rs @@ -1,7 +1,7 @@ use std::fmt; use crate::benchmark::MIN_EXECUTION_TIME; -use crate::quantity::{Time, TimeQuantity, TimeUnit}; +use crate::quantity::{Time, TimeQuantity}; pub struct OutlierWarningOptions { pub warmup_in_use: bool, @@ -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_value_in(TimeUnit::MilliSecond, 0) + min_execution_time = MIN_EXECUTION_TIME.format_auto(None) ), Warnings::NonZeroExitCode => write!(f, "Ignoring non-zero exit code."), Warnings::SlowInitialRun(time_first_run, ref options) => write!( diff --git a/src/quantity/mod.rs b/src/quantity/mod.rs index 75f1442..ad3e236 100644 --- a/src/quantity/mod.rs +++ b/src/quantity/mod.rs @@ -32,10 +32,15 @@ pub trait TimeQuantity { where U: si::time::Unit + Conversion; - fn format_value_in(&self, time_unit: TimeUnit, precision: usize) -> String; + fn suitable_unit(&self) -> TimeUnit; + fn format_auto(&self, time_unit: Option) -> String; - fn format_auto_with_unit(&self, time_unit: Option) -> (String, TimeUnit); - fn format_value_auto(&self, time_unit: Option) -> (String, TimeUnit); + fn format_value_auto(&self, time_unit: Option) -> String; +} + +fn format_value_in(t: Time, u: TimeUnit, precision: Option) -> String { + let precision = precision.unwrap_or_else(|| if u == TimeUnit::Second { 3 } else { 1 }); + u.format(t, precision) } impl TimeQuantity for Time { @@ -46,42 +51,31 @@ impl TimeQuantity for Time { self.get::() } - fn format_value_in(&self, u: TimeUnit, precision: usize) -> String { - u.format(*self, precision) + fn suitable_unit(&self) -> TimeUnit { + if *self < Time::new::(1.0) { + TimeUnit::MicroSecond + } else if *self < Time::new::(1.0) { + TimeUnit::MilliSecond + } else { + TimeUnit::Second + } } /// Format the given 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 { - self.format_auto_with_unit(time_unit).0 + let time_unit = time_unit.unwrap_or_else(|| self.suitable_unit()); + + let value = format_value_in(*self, time_unit, None); + + format!("{} {}", value, time_unit.short_name()) } /// Like `format_duration`, but returns the target unit as well. - fn format_auto_with_unit(&self, time_unit: Option) -> (String, TimeUnit) { - let (out_str, out_unit) = self.format_value_auto(time_unit); + fn format_value_auto(&self, time_unit: Option) -> String { + let time_unit = time_unit.unwrap_or_else(|| self.suitable_unit()); - (format!("{} {}", out_str, out_unit.short_name()), out_unit) - } - - /// Like `format_duration`, but returns the target unit as well. - fn format_value_auto(&self, time_unit: Option) -> (String, TimeUnit) { - let (time_unit, precision) = if (*self < Time::new::(1.0) - && time_unit.is_none()) - || time_unit == Some(TimeUnit::MicroSecond) - { - (TimeUnit::MicroSecond, 1) - } else if (*self < Time::new::(1.0) && time_unit.is_none()) - || time_unit == Some(TimeUnit::MilliSecond) - { - (TimeUnit::MilliSecond, 1) - } else { - let time_unit = time_unit.unwrap_or(TimeUnit::Second); - let precision = if time_unit == TimeUnit::Second { 3 } else { 1 }; - - (time_unit, precision) - }; - - (self.format_value_in(time_unit, precision), time_unit) + format_value_in(*self, time_unit, None) } } @@ -211,72 +205,35 @@ fn test_mean() { } #[test] -fn test_format_duration() { - let (out_str, out_unit) = Time::new::(1.3).format_auto_with_unit(None); - -#[test] -fn test_suitable_unit_information() { +fn test_suiteable_unit() { + assert_eq!(Time::new::(1.3).suitable_unit(), TimeUnit::Second); + assert_eq!(Time::new::(1.0).suitable_unit(), TimeUnit::Second); assert_eq!( - Information::new::(512.0).suitable_unit(), - InformationUnit::Byte + Time::new::(0.999).suitable_unit(), + TimeUnit::MilliSecond ); assert_eq!( - Information::new::(2048.0).suitable_unit(), - InformationUnit::KibiByte + Time::new::(0.0005).suitable_unit(), + TimeUnit::MicroSecond ); assert_eq!( - Information::new::(2_097_152.0).suitable_unit(), - InformationUnit::MebiByte + Time::new::(0.).suitable_unit(), + TimeUnit::MicroSecond ); assert_eq!( - Information::new::(2_147_483_648.0).suitable_unit(), - InformationUnit::GibiByte + Time::new::(1000.0).suitable_unit(), + TimeUnit::Second ); } - let (out_str, out_unit) = Time::new::(1.0).format_auto_with_unit(None); - - assert_eq!("1.000 s", out_str); - assert_eq!(TimeUnit::Second, out_unit); - - let (out_str, out_unit) = Time::new::(0.999).format_auto_with_unit(None); - - assert_eq!("999.0 ms", out_str); - assert_eq!(TimeUnit::MilliSecond, out_unit); - - let (out_str, out_unit) = Time::new::(0.0005).format_auto_with_unit(None); - - assert_eq!("500.0 µs", out_str); - assert_eq!(TimeUnit::MicroSecond, out_unit); - - let (out_str, out_unit) = Time::new::(0.).format_auto_with_unit(None); - - assert_eq!("0.0 µs", out_str); - assert_eq!(TimeUnit::MicroSecond, out_unit); - - let (out_str, out_unit) = Time::new::(1000.0).format_auto_with_unit(None); - - assert_eq!("1000.000 s", out_str); - assert_eq!(TimeUnit::Second, out_unit); -} - #[test] fn test_format_duration_unit_with_unit() { - let (out_str, out_unit) = - Time::new::(1.3).format_auto_with_unit(Some(TimeUnit::Second)); + let out = Time::new::(1.3).format_auto(Some(TimeUnit::Second)); + assert_eq!("1.300 s", out); - let out = Time::new::(1.3).format(TimeUnit::MilliSecond); + let out = Time::new::(1.3).format_auto(Some(TimeUnit::MilliSecond)); assert_eq!("1300.0 ms", out); - let (out_str, out_unit) = - Time::new::(1.3).format_auto_with_unit(Some(TimeUnit::MilliSecond)); - - assert_eq!("1300.0 ms", out_str); - assert_eq!(TimeUnit::MilliSecond, out_unit); - - let (out_str, out_unit) = - Time::new::(1.3).format_auto_with_unit(Some(TimeUnit::MicroSecond)); - - assert_eq!("1300000.0 µs", out_str); - assert_eq!(TimeUnit::MicroSecond, out_unit); + let out = Time::new::(1.3).format_auto(Some(TimeUnit::MicroSecond)); + assert_eq!("1300000.0 µs", out); }