Represent memory usage as f64 as well

This commit is contained in:
David Peter authored and David Peter committed 2026-10-05 16:00:08 +02:00
1 parent 27ad0fb65e
commit 6b4e9eb5c2
8 files changed
+93 -79

No files matched your search

Generated
+1 -12
View File
@@ -515,7 +515,7 @@ dependencies = [
"num-complex",
"num-integer",
"num-iter",
"num-rational 0.2.4",
"num-rational",
"num-traits",
]
@@ -572,16 +572,6 @@ dependencies = [
"num-traits",
]
[[package]]
name = "num-rational"
version = "0.4.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f83d14da390562dca69fc84082e73e548e1ad308d24accdedd2720017cb37824"
dependencies = [
"num-integer",
"num-traits",
]
[[package]]
name = "num-traits"
version = "0.2.19"
@@ -1041,7 +1031,6 @@ version = "0.36.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ffd36e5350a65d112584053ee91843955826bf9e56ec0d1351214e01f6d7cd9c"
dependencies = [
"num-rational 0.4.2",
"num-traits",
"typenum",
]
-1
View File
@@ -32,7 +32,6 @@ uom = { version = "0.36.0", default-features = false, features = [
"std",
"si",
"f64",
"u64",
] }
[target.'cfg(not(windows))'.dependencies]
+2 -2
View File
@@ -9,7 +9,7 @@ use crate::options::{
CmdFailureAction, CommandInputPolicy, CommandOutputPolicy, Options, OutputStyleOption, Shell,
};
use crate::output::progress_bar::get_progress_bar;
use crate::quantity::{byte, second, Information, Time, TimeQuantity};
use crate::quantity::{second, Information, InformationQuantity, Time, TimeQuantity};
use crate::timer::execute_and_measure;
use crate::util::randomized_environment_offset;
@@ -348,7 +348,7 @@ impl Executor for MockExecutor {
time_wall_clock: Self::extract_time(command.get_command_line()),
time_user: Time::zero(),
time_system: Time::zero(),
peak_memory_usage: Information::new::<byte>(0),
peak_memory_usage: Information::zero(),
exit_status,
})
}
+10 -14
View File
@@ -2,10 +2,9 @@ use std::process::ExitStatus;
use serde::Serialize;
use crate::outlier_detection::modified_zscores;
use crate::quantity::{
max, mean, median, min, second, serialize_information, serialize_time, standard_deviation,
Information, Time, TimeQuantity,
max, mean, median, min, modified_zscores, serialize_information, serialize_time,
standard_deviation, Information, Time,
};
use crate::util::exit_code::extract_exit_code;
@@ -103,6 +102,11 @@ impl Measurements {
max(&self.wall_clock_times())
}
/// Compute modified Z-scores for the wall clock times
pub fn modified_zscores(&self) -> Vec<f64> {
modified_zscores(&self.wall_clock_times())
}
/// The average user time
pub fn time_user_mean(&self) -> Time {
mean(
@@ -126,19 +130,11 @@ impl Measurements {
}
pub fn peak_memory_usage_mean(&self) -> Information {
self.measurements
.iter()
.map(|m| m.peak_memory_usage)
.max() // TODO: should be mean: do we need InformationF64?
.unwrap_or_default()
}
pub fn modified_zscores(&self) -> Vec<f64> {
modified_zscores(
mean(
&self
.wall_clock_times()
.measurements
.iter()
.map(|t| t.value_in(second)) // TODO
.map(|m| m.peak_memory_usage)
.collect::<Vec<_>>(),
)
}
+6 -6
View File
@@ -85,21 +85,21 @@ fn test_csv() {
time_wall_clock: Time::new::<second>(7.0),
time_user: Time::new::<second>(7.0),
time_system: Time::zero(),
peak_memory_usage: Information::new::<byte>(1024),
peak_memory_usage: Information::new::<byte>(1024.),
exit_status: ExitStatus::default(),
},
Measurement {
time_wall_clock: Time::new::<second>(8.0),
time_user: Time::new::<second>(8.0),
time_system: Time::zero(),
peak_memory_usage: Information::new::<byte>(1024),
peak_memory_usage: Information::new::<byte>(1024.),
exit_status: ExitStatus::default(),
},
Measurement {
time_wall_clock: Time::new::<second>(12.0),
time_user: Time::new::<second>(12.0),
time_system: Time::zero(),
peak_memory_usage: Information::new::<byte>(1024),
peak_memory_usage: Information::new::<byte>(1024.),
exit_status: ExitStatus::default(),
},
]),
@@ -129,21 +129,21 @@ fn test_csv() {
time_wall_clock: Time::new::<second>(17.0),
time_user: Time::new::<second>(17.0),
time_system: Time::zero(),
peak_memory_usage: Information::new::<byte>(1024),
peak_memory_usage: Information::new::<byte>(1024.),
exit_status: ExitStatus::default(),
},
Measurement {
time_wall_clock: Time::new::<second>(18.0),
time_user: Time::new::<second>(18.0),
time_system: Time::zero(),
peak_memory_usage: Information::new::<byte>(1024),
peak_memory_usage: Information::new::<byte>(1024.),
exit_status: ExitStatus::default(),
},
Measurement {
time_wall_clock: Time::new::<second>(19.0),
time_user: Time::new::<second>(19.0),
time_system: Time::zero(),
peak_memory_usage: Information::new::<byte>(1024),
peak_memory_usage: Information::new::<byte>(1024.),
exit_status: ExitStatus::default(),
},
]),
+24 -24
View File
@@ -33,21 +33,21 @@ fn test_markup_export_auto_ms() {
time_wall_clock: Time::new::<second>(0.09),
time_user: Time::new::<second>(0.09),
time_system: Time::zero(),
peak_memory_usage: Information::new::<byte>(1024),
peak_memory_usage: Information::new::<byte>(1024.),
exit_status: ExitStatus::default(),
},
Measurement {
time_wall_clock: Time::new::<second>(0.10),
time_user: Time::new::<second>(0.10),
time_system: Time::zero(),
peak_memory_usage: Information::new::<byte>(1024),
peak_memory_usage: Information::new::<byte>(1024.),
exit_status: ExitStatus::default(),
},
Measurement {
time_wall_clock: Time::new::<second>(0.14),
time_user: Time::new::<second>(0.14),
time_system: Time::zero(),
peak_memory_usage: Information::new::<byte>(1024),
peak_memory_usage: Information::new::<byte>(1024.),
exit_status: ExitStatus::default(),
},
]),
@@ -60,21 +60,21 @@ fn test_markup_export_auto_ms() {
time_wall_clock: Time::new::<second>(2.0),
time_user: Time::new::<second>(2.0),
time_system: Time::zero(),
peak_memory_usage: Information::new::<byte>(1024),
peak_memory_usage: Information::new::<byte>(1024.),
exit_status: ExitStatus::default(),
},
Measurement {
time_wall_clock: Time::new::<second>(3.0),
time_user: Time::new::<second>(3.0),
time_system: Time::zero(),
peak_memory_usage: Information::new::<byte>(1024),
peak_memory_usage: Information::new::<byte>(1024.),
exit_status: ExitStatus::default(),
},
Measurement {
time_wall_clock: Time::new::<second>(4.0),
time_user: Time::new::<second>(4.0),
time_system: Time::zero(),
peak_memory_usage: Information::new::<byte>(1024),
peak_memory_usage: Information::new::<byte>(1024.),
exit_status: ExitStatus::default(),
},
]),
@@ -132,21 +132,21 @@ fn test_markup_export_auto_s() {
time_wall_clock: Time::new::<second>(2.1),
time_user: Time::new::<second>(2.1),
time_system: Time::zero(),
peak_memory_usage: Information::new::<byte>(1024),
peak_memory_usage: Information::new::<byte>(1024.),
exit_status: ExitStatus::default(),
},
Measurement {
time_wall_clock: Time::new::<second>(2.2),
time_user: Time::new::<second>(2.2),
time_system: Time::zero(),
peak_memory_usage: Information::new::<byte>(1024),
peak_memory_usage: Information::new::<byte>(1024.),
exit_status: ExitStatus::default(),
},
Measurement {
time_wall_clock: Time::new::<second>(2.3),
time_user: Time::new::<second>(2.3),
time_system: Time::zero(),
peak_memory_usage: Information::new::<byte>(1024),
peak_memory_usage: Information::new::<byte>(1024.),
exit_status: ExitStatus::default(),
},
]),
@@ -159,21 +159,21 @@ fn test_markup_export_auto_s() {
time_wall_clock: Time::new::<second>(0.1),
time_user: Time::new::<second>(0.1),
time_system: Time::zero(),
peak_memory_usage: Information::new::<byte>(1024),
peak_memory_usage: Information::new::<byte>(1024.),
exit_status: ExitStatus::default(),
},
Measurement {
time_wall_clock: Time::new::<second>(0.2),
time_user: Time::new::<second>(0.2),
time_system: Time::zero(),
peak_memory_usage: Information::new::<byte>(1024),
peak_memory_usage: Information::new::<byte>(1024.),
exit_status: ExitStatus::default(),
},
Measurement {
time_wall_clock: Time::new::<second>(0.3),
time_user: Time::new::<second>(0.3),
time_system: Time::zero(),
peak_memory_usage: Information::new::<byte>(1024),
peak_memory_usage: Information::new::<byte>(1024.),
exit_status: ExitStatus::default(),
},
]),
@@ -231,21 +231,21 @@ fn test_markup_export_manual_ms() {
time_wall_clock: Time::new::<second>(2.1),
time_user: Time::new::<second>(2.1),
time_system: Time::zero(),
peak_memory_usage: Information::new::<byte>(1024),
peak_memory_usage: Information::new::<byte>(1024.),
exit_status: ExitStatus::default(),
},
Measurement {
time_wall_clock: Time::new::<second>(2.2),
time_user: Time::new::<second>(2.2),
time_system: Time::zero(),
peak_memory_usage: Information::new::<byte>(1024),
peak_memory_usage: Information::new::<byte>(1024.),
exit_status: ExitStatus::default(),
},
Measurement {
time_wall_clock: Time::new::<second>(2.3),
time_user: Time::new::<second>(2.3),
time_system: Time::zero(),
peak_memory_usage: Information::new::<byte>(1024),
peak_memory_usage: Information::new::<byte>(1024.),
exit_status: ExitStatus::default(),
},
]),
@@ -258,21 +258,21 @@ fn test_markup_export_manual_ms() {
time_wall_clock: Time::new::<second>(0.1),
time_user: Time::new::<second>(0.1),
time_system: Time::zero(),
peak_memory_usage: Information::new::<byte>(1024),
peak_memory_usage: Information::new::<byte>(1024.),
exit_status: ExitStatus::default(),
},
Measurement {
time_wall_clock: Time::new::<second>(0.2),
time_user: Time::new::<second>(0.2),
time_system: Time::zero(),
peak_memory_usage: Information::new::<byte>(1024),
peak_memory_usage: Information::new::<byte>(1024.),
exit_status: ExitStatus::default(),
},
Measurement {
time_wall_clock: Time::new::<second>(0.3),
time_user: Time::new::<second>(0.3),
time_system: Time::zero(),
peak_memory_usage: Information::new::<byte>(1024),
peak_memory_usage: Information::new::<byte>(1024.),
exit_status: ExitStatus::default(),
},
]),
@@ -329,21 +329,21 @@ fn test_markup_export_manual_s() {
time_wall_clock: Time::new::<second>(2.01),
time_user: Time::new::<second>(2.01),
time_system: Time::zero(),
peak_memory_usage: Information::new::<byte>(1024),
peak_memory_usage: Information::new::<byte>(1024.),
exit_status: ExitStatus::default(),
},
Measurement {
time_wall_clock: Time::new::<second>(2.02),
time_user: Time::new::<second>(2.02),
time_system: Time::zero(),
peak_memory_usage: Information::new::<byte>(1024),
peak_memory_usage: Information::new::<byte>(1024.),
exit_status: ExitStatus::default(),
},
Measurement {
time_wall_clock: Time::new::<second>(2.03),
time_user: Time::new::<second>(2.03),
time_system: Time::zero(),
peak_memory_usage: Information::new::<byte>(1024),
peak_memory_usage: Information::new::<byte>(1024.),
exit_status: ExitStatus::default(),
},
]),
@@ -356,21 +356,21 @@ fn test_markup_export_manual_s() {
time_wall_clock: Time::new::<second>(0.11),
time_user: Time::new::<second>(0.11),
time_system: Time::zero(),
peak_memory_usage: Information::new::<byte>(1024),
peak_memory_usage: Information::new::<byte>(1024.),
exit_status: ExitStatus::default(),
},
Measurement {
time_wall_clock: Time::new::<second>(0.12),
time_user: Time::new::<second>(0.12),
time_system: Time::zero(),
peak_memory_usage: Information::new::<byte>(1024),
peak_memory_usage: Information::new::<byte>(1024.),
exit_status: ExitStatus::default(),
},
Measurement {
time_wall_clock: Time::new::<second>(0.13),
time_user: Time::new::<second>(0.13),
time_system: Time::zero(),
peak_memory_usage: Information::new::<byte>(1024),
peak_memory_usage: Information::new::<byte>(1024.),
exit_status: ExitStatus::default(),
},
]),
+45 -17
View File
@@ -9,9 +9,7 @@ pub use uom::si::information::{byte, kibibyte};
pub use uom::si::ratio::ratio;
pub use uom::si::time::{hour, microsecond, millisecond, minute, nanosecond, second};
pub use si::f64::Ratio;
pub use si::f64::Time;
pub use si::u64::Information;
pub use si::f64::{Information, Ratio, Time};
pub use si::f64::{Information, Ratio, Time};
pub use si::information::{byte, gibibyte, kibibyte, mebibyte, tebibyte};
@@ -92,29 +90,29 @@ pub const fn const_time_from_seconds(value: f64) -> Time {
pub trait InformationQuantity {
fn zero() -> Information {
Information::new::<byte>(0)
Information::new::<byte>(0.)
}
fn value_in<U>(&self, u: U) -> u64
fn value_in<U>(&self, u: U) -> f64
where
U: si::information::Unit + Conversion<u64, T = uom::num_rational::Ratio<u64>>;
U: si::information::Unit + Conversion<f64, T = f64>;
fn to_string<U>(&self, u: U) -> String
where
U: si::information::Unit + Conversion<u64, T = uom::num_rational::Ratio<u64>>;
U: si::information::Unit + Conversion<f64, T = f64>;
}
impl InformationQuantity for Information {
fn value_in<U>(&self, _u: U) -> u64
fn value_in<U>(&self, _u: U) -> f64
where
U: si::information::Unit + Conversion<u64, T = uom::num_rational::Ratio<u64>>,
U: si::information::Unit + Conversion<f64, T = f64>,
{
self.get::<U>()
}
fn to_string<U>(&self, u: U) -> String
where
U: si::information::Unit + Conversion<u64, T = uom::num_rational::Ratio<u64>>,
U: si::information::Unit + Conversion<f64, T = f64>,
{
format!(
"{}",
@@ -123,6 +121,31 @@ impl InformationQuantity for Information {
}
}
pub trait UnsafeRawValue {
fn unsafe_raw_value(&self) -> f64;
fn unsafe_from_raw_value(value: f64) -> Self;
}
impl UnsafeRawValue for Time {
fn unsafe_raw_value(&self) -> f64 {
self.value_in(second)
}
fn unsafe_from_raw_value(value: f64) -> Self {
Time::new::<second>(value)
}
}
impl UnsafeRawValue for Information {
fn unsafe_raw_value(&self) -> f64 {
self.value_in(byte)
}
fn unsafe_from_raw_value(value: f64) -> Self {
Information::new::<byte>(value)
}
}
pub fn serialize_time<S>(t: &Time, s: S) -> Result<S::Ok, S::Error>
where
S: Serializer,
@@ -145,11 +168,11 @@ where
macro_rules! quantity_fn {
($name:ident, $unwrapped_values:ident, $body:expr) => {
pub fn $name(values: &[Time]) -> Time {
let $unwrapped_values: Vec<_> = values.iter().map(|q| q.value_in(second)).collect();
pub fn $name<Q: UnsafeRawValue>(values: &[Q]) -> Q {
let $unwrapped_values: Vec<_> = values.iter().map(|q| q.unsafe_raw_value()).collect();
let result_value = $body;
Time::new::<second>(result_value)
Q::unsafe_from_raw_value(result_value)
}
};
}
@@ -163,6 +186,11 @@ quantity_fn!(standard_deviation, values, {
statistical::standard_deviation(&values, Some(mean_value))
});
pub fn modified_zscores<Q: UnsafeRawValue>(values: &[Q]) -> Vec<f64> {
let values: Vec<_> = values.iter().map(|q| q.unsafe_raw_value()).collect();
crate::outlier_detection::modified_zscores(&values)
}
#[test]
fn test_time() {
let time = Time::new::<millisecond>(123.4);
@@ -177,11 +205,11 @@ fn test_time() {
#[test]
fn test_information() {
let information = Information::new::<kibibyte>(8);
assert_eq!(information.value_in(byte), 8192);
let information = Information::new::<kibibyte>(8.);
assert_eq!(information.value_in(byte), 8192.);
let information_kib = information.value_in(kibibyte);
assert_eq!(information_kib, 8);
assert_eq!(information_kib, 8.);
}
#[test]
@@ -191,7 +219,7 @@ fn test_format() {
assert_eq!(time.format_auto(Some(TimeUnit::MilliSecond)), "123.4 ms");
assert_eq!(time.format_auto(Some(TimeUnit::MicroSecond)), "123400.0 µs");
let peak_memory_usage = Information::new::<kibibyte>(8);
let peak_memory_usage = Information::new::<kibibyte>(8.);
assert_eq!(peak_memory_usage.to_string(byte), "8192 B");
assert_eq!(peak_memory_usage.to_string(kibibyte), "8 KiB");
}
+5 -3
View File
@@ -1,6 +1,5 @@
#![cfg(not(windows))]
use std::convert::TryFrom;
use std::io;
use std::mem::MaybeUninit;
use std::os::unix::process::ExitStatusExt;
@@ -47,9 +46,12 @@ fn wait4(mut child: Child) -> io::Result<(ExitStatus, ResourceUsage)> {
let memory_usage_byte = if cfg!(target_os = "macos") || cfg!(target_os = "ios") {
// Linux and *BSD return the value in KibiBytes, Darwin flavors in bytes
Information::new::<byte>(u64::try_from(rusage.ru_maxrss).unwrap_or(0))
// A f64 can represent integers up to 2^53 exactly, so we can represent
// all values up to 2^53 bytes = 8 PiB exactly. Beyond that, our precision
// is larger than 1 byte, but that's considered acceptable.
Information::new::<byte>(rusage.ru_maxrss as f64)
} else {
Information::new::<kibibyte>(u64::try_from(rusage.ru_maxrss).unwrap_or(0))
Information::new::<kibibyte>(rusage.ru_maxrss as f64)
};
Ok((