diff --git a/Cargo.lock b/Cargo.lock index 8cc7a8b..5b93f7a 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -394,6 +394,7 @@ dependencies = [ "shell-words", "tempfile", "thiserror", + "uom", "windows-sys 0.61.2", ] @@ -932,6 +933,12 @@ dependencies = [ "winnow", ] +[[package]] +name = "typenum" +version = "1.20.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b6f5e870be6c3b371b77fe0ee0bafb859fa4964b4404c27de1d380043c4dda20" + [[package]] name = "unicode-ident" version = "1.0.26" @@ -950,6 +957,16 @@ version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b4ac048d71ede7ee76d585517add45da530660ef4390e49b098733c6e897f254" +[[package]] +name = "uom" +version = "0.36.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ffd36e5350a65d112584053ee91843955826bf9e56ec0d1351214e01f6d7cd9c" +dependencies = [ + "num-traits", + "typenum", +] + [[package]] name = "utf8parse" version = "0.2.2" diff --git a/Cargo.toml b/Cargo.toml index e2ab23a..cf2050b 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -28,6 +28,7 @@ rand = "0.10" shell-words = "1.1" thiserror = "2.0" anyhow = "1.0" +uom = { version = "0.36.0", default-features = false, features = ["std", "si", "f64"] } [target.'cfg(not(windows))'.dependencies] libc = "0.2" diff --git a/src/benchmark/executor.rs b/src/benchmark/executor.rs index 52284a4..e08774d 100644 --- a/src/benchmark/executor.rs +++ b/src/benchmark/executor.rs @@ -7,9 +7,9 @@ use crate::options::{ CmdFailureAction, CommandInputPolicy, CommandOutputPolicy, Options, OutputStyleOption, Shell, }; use crate::output::progress_bar::get_progress_bar; +use crate::quantity::{second, Information, Time, Zero}; use crate::timer::execute_and_measure; use crate::util::randomized_environment_offset; -use crate::util::units::Second; use super::measurement::{Measurement, Measurements}; @@ -51,7 +51,7 @@ pub trait Executor { /// performing a measurement. This should return the time /// that is being used in addition to the actual runtime /// of the command. - fn time_overhead(&self) -> Second; + fn time_overhead(&self) -> Time; } fn run_command_and_measure_common( @@ -150,8 +150,8 @@ impl Executor for RawExecutor<'_> { Ok(()) } - fn time_overhead(&self) -> Second { - 0.0 + fn time_overhead(&self) -> Time { + Time::zero() } } @@ -203,9 +203,9 @@ impl Executor for ShellExecutor<'_> { // Subtract shell spawning time if let Some(spawning_time) = self.shell_spawning_time { result.time_wall_clock = - (result.time_wall_clock - spawning_time.time_wall_clock).max(0.0); - result.time_user = (result.time_user - spawning_time.time_user).max(0.0); - result.time_system = (result.time_system - spawning_time.time_system).max(0.0); + (result.time_wall_clock - spawning_time.time_wall_clock).max(Time::zero()); + result.time_user = (result.time_user - spawning_time.time_user).max(Time::zero()); + result.time_system = (result.time_system - spawning_time.time_system).max(Time::zero()); } Ok(result) @@ -266,14 +266,14 @@ impl Executor for ShellExecutor<'_> { time_wall_clock: measurements.time_wall_clock_mean(), time_user: measurements.time_user_mean(), time_system: measurements.time_system_mean(), - peak_memory_usage: 0, + peak_memory_usage: Information::zero(), exit_status: ExitStatus::default(), }); Ok(()) } - fn time_overhead(&self) -> Second { + fn time_overhead(&self) -> Time { self.shell_spawning_time.unwrap().time_wall_clock } } @@ -288,13 +288,15 @@ impl MockExecutor { MockExecutor { shell } } - fn extract_time>(sleep_command: S) -> Second { + fn extract_time>(sleep_command: S) -> Time { assert!(sleep_command.as_ref().starts_with("sleep ")); - sleep_command - .as_ref() - .trim_start_matches("sleep ") - .parse::() - .unwrap() + Time::new::( + sleep_command + .as_ref() + .trim_start_matches("sleep ") + .parse::() + .unwrap(), + ) } } @@ -320,9 +322,9 @@ impl Executor for MockExecutor { Ok(Measurement { time_wall_clock: Self::extract_time(command.get_command_line()), - time_user: 0.0, - time_system: 0.0, - peak_memory_usage: 0, + time_user: Time::zero(), + time_system: Time::zero(), + peak_memory_usage: Information::zero(), exit_status, }) } @@ -331,9 +333,9 @@ impl Executor for MockExecutor { Ok(()) } - fn time_overhead(&self) -> Second { + fn time_overhead(&self) -> Time { match &self.shell { - None => 0.0, + None => Time::zero(), Some(shell) => Self::extract_time(shell), } } @@ -341,5 +343,8 @@ impl Executor for MockExecutor { #[test] fn test_mock_executor_extract_time() { - assert_eq!(MockExecutor::extract_time("sleep 0.1"), 0.1); + assert_eq!( + MockExecutor::extract_time("sleep 0.1"), + Time::new::(0.1) + ); } diff --git a/src/benchmark/measurement.rs b/src/benchmark/measurement.rs index 4e4efef..eb1edc9 100644 --- a/src/benchmark/measurement.rs +++ b/src/benchmark/measurement.rs @@ -1,23 +1,23 @@ use std::process::ExitStatus; use crate::outlier_detection::modified_zscores; +use crate::quantity::{second, Information, Time}; use crate::util::statistics::{max, mean, median, min, standard_deviation}; -use crate::util::units::Second; /// Performance measurements and exit status from running a single command #[derive(Debug, Default, Copy, Clone)] pub struct Measurement { /// Wall clock time - pub time_wall_clock: Second, + pub time_wall_clock: Time, /// Time spent in user mode - pub time_user: Second, + pub time_user: Time, /// Time spent in kernel mode - pub time_system: Second, + pub time_system: Time, - /// Maximum amount of memory used, in bytes - pub peak_memory_usage: u64, + /// Maximum amount of memory used + pub peak_memory_usage: Information, /// The exit status of the process pub exit_status: ExitStatus, @@ -42,17 +42,17 @@ impl Measurements { self.measurements.push(measurement); } - pub fn wall_clock_times(&self) -> impl Iterator + '_ { + pub fn wall_clock_times(&self) -> impl Iterator + '_ { self.measurements.iter().map(|m| m.time_wall_clock) } /// The average wall clock time. - pub fn time_wall_clock_mean(&self) -> Second { + pub fn time_wall_clock_mean(&self) -> Time { mean(self.wall_clock_times()) } /// The standard deviation of wall clock times, if at least two runs were measured. - pub fn stddev(&self) -> Option { + pub fn stddev(&self) -> Option