diff --git a/src/benchmark/mod.rs b/src/benchmark/mod.rs index 7f1ff51..d4d3f3e 100644 --- a/src/benchmark/mod.rs +++ b/src/benchmark/mod.rs @@ -331,7 +331,10 @@ impl<'a> Benchmark<'a> { let msg = { let t_wall_clock_mean = measurements.time_wall_clock_mean(); - let time_unit = t_wall_clock_mean.suitable_unit(); + let time_unit = self + .options + .time_unit + .unwrap_or(t_wall_clock_mean.suitable_unit()); let mean = t_wall_clock_mean.format(time_unit); format!("Current estimate: {}", mean.to_string().green()) }; diff --git a/src/output/warnings.rs b/src/output/warnings.rs index 8400a6c..98ebdb7 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::{FormatQuantity, Time}; +use crate::quantity::{FormatQuantity, Time, TimeUnit}; pub struct OutlierWarningOptions { pub warmup_in_use: bool, @@ -21,11 +21,11 @@ impl fmt::Display for Warnings { match *self { Warnings::FastExecutionTime => write!( f, - "Command took less than {min_execution_time} to complete. Note that the results might be \ + "Command took less than {} ms to complete. Note that the results might be \ 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() + MIN_EXECUTION_TIME.format_with_precision(TimeUnit::MilliSecond, 0) ), 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 4442705..867ab20 100644 --- a/src/quantity/mod.rs +++ b/src/quantity/mod.rs @@ -1,4 +1,3 @@ -use core::f64; use std::marker::PhantomData; use serde::ser::SerializeStruct; @@ -54,9 +53,7 @@ impl FormatQuantity for Time { /// Format the given time duration. The unit will be determined automatically. fn format_auto(&self) -> String { - let unit = self.suitable_unit(); - let value = self.format(unit); - format!("{} {}", value, unit.short_name()) + self.format(self.suitable_unit()) } /// Like `format`, but without displaying the unit. @@ -102,9 +99,7 @@ impl FormatQuantity for Information { /// Format the given information. The unit will be determined automatically. fn format_auto(&self) -> String { - let unit = self.suitable_unit(); - let value = self.format(unit); - format!("{} {}", value, unit.short_name()) + self.format(self.suitable_unit()) } /// Like `format`, but without displaying the unit. @@ -206,9 +201,11 @@ fn test_format() { let time = Time::new::(123.4); assert_eq!(time.format(TimeUnit::Second), "0.123 s"); assert_eq!(time.format(TimeUnit::MilliSecond), "123.4 ms"); + assert_eq!(time.format_auto(), "123.4 ms"); assert_eq!(time.format(TimeUnit::MicroSecond), "123400.0 µs"); let peak_memory_usage = Information::new::(8.); + assert_eq!(peak_memory_usage.format_auto(), "8.0 KiB"); assert_eq!(peak_memory_usage.format(InformationUnit::Byte), "8192 B"); assert_eq!( peak_memory_usage.format(InformationUnit::KibiByte), diff --git a/src/quantity/units.rs b/src/quantity/units.rs index 057e5b4..0e457f5 100644 --- a/src/quantity/units.rs +++ b/src/quantity/units.rs @@ -139,91 +139,6 @@ impl> UnitImpl } } -/// Supported information units -#[derive(Debug, Clone, Copy, PartialEq, Eq)] - -pub enum InformationUnit { - Byte, - KibiByte, - MebiByte, - GibiByte, - TebiByte, -} - -impl IsUnit for InformationUnit { - type Quantity = Information; - - fn dispatch(&self) -> Box> { - match self { - InformationUnit::Byte => Box::new(InformationUnitDispatcher::::new()), - InformationUnit::KibiByte => Box::new(InformationUnitDispatcher::::new()), - InformationUnit::MebiByte => Box::new(InformationUnitDispatcher::::new()), - InformationUnit::GibiByte => Box::new(InformationUnitDispatcher::::new()), - InformationUnit::TebiByte => Box::new(InformationUnitDispatcher::::new()), - } - } - - fn preferred_precision(&self) -> usize { - match self { - InformationUnit::Byte => 0, - _ => 1, - } - } -} - -pub trait UnitImpl { - type Quantity; - - fn short_name(&self) -> &'static str; - fn format_value(&self, value: Self::Quantity, precision: usize) -> String; -} - -struct TimeUnitDispatcher> { - u: PhantomData, -} - -impl> TimeUnitDispatcher { - fn new() -> Self { - TimeUnitDispatcher { u: PhantomData } - } -} - -impl> UnitImpl for TimeUnitDispatcher { - type Quantity = Time; - - fn short_name(&self) -> &'static str { - U::abbreviation() - } - - fn format_value(&self, value: Time, precision: usize) -> String { - format!("{value:.precision$}", value = value.get::()) - } -} - -struct InformationUnitDispatcher> { - u: PhantomData, -} - -impl> InformationUnitDispatcher { - fn new() -> Self { - InformationUnitDispatcher { u: PhantomData } - } -} - -impl> UnitImpl - for InformationUnitDispatcher -{ - type Quantity = Information; - - fn short_name(&self) -> &'static str { - U::abbreviation() - } - - fn format_value(&self, value: Information, precision: usize) -> String { - format!("{value:.precision$}", value = value.get::()) - } -} - #[test] fn test_time_unit_short_name() { assert_eq!("s", TimeUnit::Second.short_name()); @@ -232,3 +147,20 @@ fn test_time_unit_short_name() { assert_eq!("min", TimeUnit::Minute.short_name()); assert_eq!("h", TimeUnit::Hour.short_name()); } + +// Note - the values are rounded when formatted. +#[test] +fn test_unit_format() { + use crate::quantity::FormatQuantity; + + let value = Time::new::(123.456789); + assert_eq!("123.457", value.format_value(TimeUnit::Second)); + assert_eq!("123456.8", value.format_value(TimeUnit::MilliSecond)); + + assert_eq!( + "1234.6", + Time::new::(0.00123456).format_value(TimeUnit::MicroSecond) + ); + assert_eq!("2.1", value.format_value(TimeUnit::Minute)); + assert_eq!("0.0", value.format_value(TimeUnit::Hour)); +}