mirror of
https://github.com/sharkdp/hyperfine.git
synced 2026-10-28 08:08:58 +00:00
Switch to unit-safe quantities
This commit is contained in:
1 parent
914d5cbc59
commit
f9aa299c0f
15 files changed
+399
-287
No files matched your search
Generated
+10
-2
@@ -392,6 +392,8 @@ dependencies = [
|
||||
"serde",
|
||||
"serde_json",
|
||||
"shell-words",
|
||||
"static_assertions",
|
||||
"statistical",
|
||||
"tempfile",
|
||||
"thiserror",
|
||||
"uom",
|
||||
@@ -818,8 +820,14 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "bbbb5d9659141646ae647b42fe094daf6c6192d1620870b449d9557f748b2daa"
|
||||
|
||||
[[package]]
|
||||
name = "strip-ansi-escapes"
|
||||
version = "0.2.1"
|
||||
name = "static_assertions"
|
||||
version = "1.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f"
|
||||
|
||||
[[package]]
|
||||
name = "statistical"
|
||||
version = "1.0.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2a8f8038e7e7969abb3f1b7c2a811225e9296da208539e0f79c5251d6cac0025"
|
||||
dependencies = [
|
||||
|
||||
+1
-1
@@ -28,7 +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"] }
|
||||
static_assertions = "1.1.0"
|
||||
|
||||
[target.'cfg(not(windows))'.dependencies]
|
||||
libc = "0.2"
|
||||
|
||||
@@ -2,7 +2,7 @@ use std::collections::BTreeMap;
|
||||
|
||||
use serde::Serialize;
|
||||
|
||||
use crate::{benchmark::measurement::Measurements, util::units::Second};
|
||||
use crate::benchmark::{measurement::Measurements, quantity::Second};
|
||||
|
||||
/// Parameter value and whether it was used in the command line template
|
||||
#[derive(Debug, Default, Clone, Serialize, PartialEq)]
|
||||
|
||||
+25
-16
@@ -2,6 +2,9 @@
|
||||
use std::os::windows::process::CommandExt;
|
||||
use std::process::ExitStatus;
|
||||
|
||||
use crate::benchmark::quantity::mean;
|
||||
use crate::benchmark::quantity::Byte;
|
||||
use crate::benchmark::quantity::Second;
|
||||
use crate::command::Command;
|
||||
use crate::options::{
|
||||
CmdFailureAction, CommandInputPolicy, CommandOutputPolicy, Options, OutputStyleOption, Shell,
|
||||
@@ -161,8 +164,8 @@ impl Executor for RawExecutor<'_> {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn time_overhead(&self) -> Time {
|
||||
Time::zero()
|
||||
fn time_overhead(&self) -> Second {
|
||||
Second::zero()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -212,11 +215,20 @@ impl Executor for ShellExecutor<'_> {
|
||||
)?;
|
||||
|
||||
// Subtract shell spawning time
|
||||
fn ensure_non_negative(time: Second) -> Second {
|
||||
if time < Second::zero() {
|
||||
Second::zero()
|
||||
} else {
|
||||
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);
|
||||
ensure_non_negative(result.time_wall_clock - spawning_time.time_wall_clock);
|
||||
result.time_user = ensure_non_negative(result.time_user - spawning_time.time_user);
|
||||
result.time_system =
|
||||
ensure_non_negative(result.time_system - spawning_time.time_system);
|
||||
}
|
||||
|
||||
Ok((
|
||||
@@ -243,7 +255,7 @@ impl Executor for ShellExecutor<'_> {
|
||||
None
|
||||
};
|
||||
|
||||
let mut times_wall_clock: Vec<Second> = vec![];
|
||||
let mut times_wall_clock: Vec<Second> = vec![]; // TODO
|
||||
let mut times_user: Vec<Second> = vec![];
|
||||
let mut times_system: Vec<Second> = vec![];
|
||||
|
||||
@@ -289,7 +301,7 @@ impl Executor for ShellExecutor<'_> {
|
||||
time_wall_clock: mean(×_wall_clock),
|
||||
time_user: mean(×_user),
|
||||
time_system: mean(×_system),
|
||||
memory_usage_byte: 0,
|
||||
memory_usage_byte: Byte::new(0),
|
||||
});
|
||||
|
||||
Ok(())
|
||||
@@ -312,7 +324,7 @@ impl MockExecutor {
|
||||
|
||||
fn extract_time<S: AsRef<str>>(sleep_command: S) -> Time {
|
||||
assert!(sleep_command.as_ref().starts_with("sleep "));
|
||||
Time::new::<second>(
|
||||
Second::new(
|
||||
sleep_command
|
||||
.as_ref()
|
||||
.trim_start_matches("sleep ")
|
||||
@@ -345,9 +357,9 @@ impl Executor for MockExecutor {
|
||||
Ok((
|
||||
TimingResult {
|
||||
time_wall_clock: Self::extract_time(command.get_command_line()),
|
||||
time_user: 0.0,
|
||||
time_system: 0.0,
|
||||
memory_usage_byte: 0,
|
||||
time_user: Second::zero(),
|
||||
time_system: Second::zero(),
|
||||
memory_usage_byte: Byte::new(0),
|
||||
},
|
||||
status,
|
||||
))
|
||||
@@ -359,7 +371,7 @@ impl Executor for MockExecutor {
|
||||
|
||||
fn time_overhead(&self) -> Time {
|
||||
match &self.shell {
|
||||
None => Time::zero(),
|
||||
None => Second::zero(),
|
||||
Some(shell) => Self::extract_time(shell),
|
||||
}
|
||||
}
|
||||
@@ -367,8 +379,5 @@ impl Executor for MockExecutor {
|
||||
|
||||
#[test]
|
||||
fn test_mock_executor_extract_time() {
|
||||
assert_eq!(
|
||||
MockExecutor::extract_time("sleep 0.1"),
|
||||
Time::new::<second>(0.1)
|
||||
);
|
||||
assert_eq!(MockExecutor::extract_time("sleep 0.1"), Second::new(0.1));
|
||||
}
|
||||
@@ -1,12 +1,7 @@
|
||||
use serde::Serialize;
|
||||
|
||||
use statistical::{mean, median, standard_deviation};
|
||||
|
||||
use crate::util::units::Second;
|
||||
use crate::{
|
||||
outlier_detection::modified_zscores,
|
||||
util::min_max::{max, min},
|
||||
};
|
||||
use crate::benchmark::quantity::{max, mean, median, min, standard_deviation, Byte, Second};
|
||||
use crate::outlier_detection::modified_zscores;
|
||||
|
||||
/// Performance metric measurements and exit code for a single run
|
||||
#[derive(Debug, Clone, Serialize, PartialEq)]
|
||||
@@ -20,8 +15,8 @@ pub struct Measurement {
|
||||
/// Time spent in kernel mode
|
||||
pub system_time: Second,
|
||||
|
||||
/// Maximum memory usage of the process, in bytes
|
||||
pub memory_usage_byte: u64,
|
||||
/// Maximum memory usage of the process
|
||||
pub memory_usage_byte: Byte,
|
||||
|
||||
/// Exit codes of the process
|
||||
pub exit_code: Option<i32>,
|
||||
@@ -65,11 +60,10 @@ impl Measurements {
|
||||
pub fn stddev(&self) -> Option<Second> {
|
||||
let times = self.wall_clock_times();
|
||||
|
||||
let t_mean = mean(×);
|
||||
if times.len() > 1 {
|
||||
Some(standard_deviation(×, Some(t_mean)))
|
||||
} else {
|
||||
if times.len() < 2 {
|
||||
None
|
||||
} else {
|
||||
Some(standard_deviation(×))
|
||||
}
|
||||
}
|
||||
|
||||
@@ -111,7 +105,13 @@ impl Measurements {
|
||||
}
|
||||
|
||||
pub fn modified_zscores(&self) -> Vec<f64> {
|
||||
modified_zscores(&self.wall_clock_times())
|
||||
modified_zscores(
|
||||
&self
|
||||
.wall_clock_times()
|
||||
.iter()
|
||||
.map(|t| t.value_in::<Second>()) // TODO
|
||||
.collect::<Vec<_>>(),
|
||||
)
|
||||
}
|
||||
|
||||
pub fn peak_memory_usage_mean(&self) -> Information {
|
||||
|
||||
@@ -12,6 +12,7 @@ use std::time::Instant;
|
||||
use crate::benchmark::benchmark_result::Parameter;
|
||||
use crate::benchmark::executor::BenchmarkIteration;
|
||||
use crate::benchmark::measurement::{Measurement, Measurements};
|
||||
use crate::benchmark::quantity::{MilliSecond, Second};
|
||||
use crate::command::Command;
|
||||
use crate::options::{
|
||||
CmdFailureAction, CommandOutputPolicy, ExecutorKind, Options, OutputStyleOption,
|
||||
@@ -26,7 +27,6 @@ use crate::output::warnings::{OutlierWarningOptions, Warnings};
|
||||
use crate::parameter::ParameterNameAndValue;
|
||||
use crate::quantity::{byte, const_time_from_seconds, ratio, second, FormatQuantity, Time, Zero};
|
||||
use crate::util::exit_code::extract_exit_code;
|
||||
use crate::util::units::Second;
|
||||
use benchmark_result::BenchmarkResult;
|
||||
use measurement::{Measurement, Measurements};
|
||||
|
||||
@@ -36,7 +36,7 @@ use colored::*;
|
||||
use self::executor::Executor;
|
||||
|
||||
/// Threshold for warning about fast execution time
|
||||
pub const MIN_EXECUTION_TIME: Time = const_time_from_seconds(5e-3);
|
||||
pub const MIN_EXECUTION_TIME: MilliSecond = MilliSecond::new(5.);
|
||||
|
||||
pub struct Benchmark<'a> {
|
||||
number: usize,
|
||||
@@ -265,7 +265,7 @@ impl<'a> Benchmark<'a> {
|
||||
};
|
||||
|
||||
let preparation_result = run_preparation_command()?;
|
||||
let preparation_overhead = preparation_result.map_or(0.0, |res| {
|
||||
let preparation_overhead = preparation_result.map_or(Second::zero(), |res| {
|
||||
res.time_wall_clock + self.executor.time_overhead()
|
||||
});
|
||||
|
||||
@@ -294,7 +294,7 @@ impl<'a> Benchmark<'a> {
|
||||
}
|
||||
|
||||
let conclusion_result = run_conclusion_command()?;
|
||||
let conclusion_overhead = conclusion_result.map_or(0.0, |res| {
|
||||
let conclusion_overhead = conclusion_result.map_or(Second::zero(), |res| {
|
||||
res.time_wall_clock + self.executor.time_overhead()
|
||||
});
|
||||
|
||||
@@ -434,7 +434,7 @@ impl<'a> Benchmark<'a> {
|
||||
&& measurements
|
||||
.wall_clock_times()
|
||||
.iter()
|
||||
.any(|&t| t < MIN_EXECUTION_TIME)
|
||||
.any(|&t| t < MIN_EXECUTION_TIME.convert_to::<Second>())
|
||||
{
|
||||
warnings.push(Warnings::FastExecutionTime);
|
||||
}
|
||||
|
||||
+184
-82
@@ -1,103 +1,205 @@
|
||||
use std::fmt::{self, Display, Formatter};
|
||||
use std::{
|
||||
fmt::{self, Display, Formatter},
|
||||
ops::{Add, Div, Sub},
|
||||
};
|
||||
|
||||
use serde::Serialize;
|
||||
|
||||
#[derive(Debug, Clone, Serialize, PartialEq)]
|
||||
enum MetricPrefix {
|
||||
Nano,
|
||||
Micro,
|
||||
Milli,
|
||||
None,
|
||||
pub trait IsQuantity {
|
||||
type Value;
|
||||
|
||||
const IS_TIME: bool;
|
||||
const METRIC_PREFIX_TIME: i32;
|
||||
const IS_INFORMATION: bool;
|
||||
const BINARY_PREFIX_INFORMATION: i32;
|
||||
|
||||
fn unsafe_from(value: Self::Value) -> Self;
|
||||
}
|
||||
|
||||
impl Display for MetricPrefix {
|
||||
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
|
||||
match self {
|
||||
MetricPrefix::Nano => write!(f, "n"),
|
||||
MetricPrefix::Micro => write!(f, "µ"),
|
||||
MetricPrefix::Milli => write!(f, "m"),
|
||||
MetricPrefix::None => Ok(()),
|
||||
#[derive(Debug, Clone, Copy, Default, Serialize, PartialEq, Eq, PartialOrd)] // TODO: check partialord
|
||||
pub struct Quantity<
|
||||
Value,
|
||||
const IS_TIME: bool,
|
||||
const METRIC_PREFIX_TIME: i32,
|
||||
const IS_INFORMATION: bool,
|
||||
const BINARY_PREFIX_INFORMATION: i32,
|
||||
>(Value);
|
||||
|
||||
impl<
|
||||
Value,
|
||||
const IS_TIME: bool,
|
||||
const METRIC_PREFIX_TIME: i32,
|
||||
const IS_INFORMATION: bool,
|
||||
const BINARY_PREFIX_INFORMATION: i32,
|
||||
> IsQuantity
|
||||
for Quantity<Value, IS_TIME, METRIC_PREFIX_TIME, IS_INFORMATION, BINARY_PREFIX_INFORMATION>
|
||||
{
|
||||
type Value = Value;
|
||||
const IS_TIME: bool = IS_TIME;
|
||||
const METRIC_PREFIX_TIME: i32 = METRIC_PREFIX_TIME;
|
||||
const IS_INFORMATION: bool = IS_INFORMATION;
|
||||
const BINARY_PREFIX_INFORMATION: i32 = BINARY_PREFIX_INFORMATION;
|
||||
|
||||
fn unsafe_from(value: Self::Value) -> Self {
|
||||
Self(value)
|
||||
}
|
||||
}
|
||||
|
||||
type Time<const PREFIX: i32> = Quantity<f64, true, PREFIX, false, 0>;
|
||||
type Information<const PREFIX: i32> = Quantity<u64, false, 0, true, PREFIX>;
|
||||
|
||||
pub type Second = Time<0>;
|
||||
pub type MilliSecond = Time<-3>;
|
||||
pub type MicroSecond = Time<-6>;
|
||||
|
||||
pub type Byte = Information<0>;
|
||||
pub type KibiByte = Information<10>;
|
||||
pub type MebiByte = Information<20>;
|
||||
pub type GibiByte = Information<30>;
|
||||
pub type TebiByte = Information<40>;
|
||||
|
||||
impl<
|
||||
Value: Copy + Default,
|
||||
const IS_TIME: bool,
|
||||
const METRIC_PREFIX_TIME: i32,
|
||||
const IS_INFORMATION: bool,
|
||||
const BINARY_PREFIX_INFORMATION: i32,
|
||||
> Quantity<Value, IS_TIME, METRIC_PREFIX_TIME, IS_INFORMATION, BINARY_PREFIX_INFORMATION>
|
||||
{
|
||||
pub const fn new(value: Value) -> Self {
|
||||
Self(value)
|
||||
}
|
||||
|
||||
pub fn zero() -> Self {
|
||||
Self::new(Value::default())
|
||||
}
|
||||
|
||||
pub fn value_in<TargetUnit: IsQuantity>(&self) -> Value {
|
||||
const {
|
||||
assert!(IS_TIME == TargetUnit::IS_TIME);
|
||||
assert!(METRIC_PREFIX_TIME == TargetUnit::METRIC_PREFIX_TIME);
|
||||
assert!(IS_INFORMATION == TargetUnit::IS_INFORMATION);
|
||||
assert!(BINARY_PREFIX_INFORMATION == TargetUnit::BINARY_PREFIX_INFORMATION);
|
||||
}
|
||||
|
||||
self.0
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Serialize, PartialEq)]
|
||||
enum BinaryPrefix {
|
||||
None,
|
||||
Kibi,
|
||||
Mebi,
|
||||
Gibi,
|
||||
Tebi,
|
||||
impl<const METRIC_PREFIX_TIME: i32> Time<METRIC_PREFIX_TIME> {
|
||||
pub fn convert_to<TargetUnit: IsQuantity<Value = f64>>(&self) -> TargetUnit {
|
||||
let factor = 10_f64.powi(METRIC_PREFIX_TIME - TargetUnit::METRIC_PREFIX_TIME);
|
||||
|
||||
TargetUnit::unsafe_from(self.0 * factor)
|
||||
}
|
||||
}
|
||||
|
||||
impl Display for BinaryPrefix {
|
||||
impl<const METRIC_PREFIX_TIME: i32> Add<Time<METRIC_PREFIX_TIME>> for Time<METRIC_PREFIX_TIME> {
|
||||
type Output = Time<METRIC_PREFIX_TIME>;
|
||||
|
||||
fn add(self, rhs: Time<METRIC_PREFIX_TIME>) -> Self::Output {
|
||||
Time::new(self.0 + rhs.0)
|
||||
}
|
||||
}
|
||||
|
||||
impl<const METRIC_PREFIX_TIME: i32> Sub<Time<METRIC_PREFIX_TIME>> for Time<METRIC_PREFIX_TIME> {
|
||||
type Output = Time<METRIC_PREFIX_TIME>;
|
||||
|
||||
fn sub(self, rhs: Time<METRIC_PREFIX_TIME>) -> Self::Output {
|
||||
Time::new(self.0 - rhs.0)
|
||||
}
|
||||
}
|
||||
|
||||
impl<const METRIC_PREFIX_TIME: i32> Div<Time<METRIC_PREFIX_TIME>> for Time<METRIC_PREFIX_TIME> {
|
||||
type Output = f64;
|
||||
|
||||
fn div(self, rhs: Time<METRIC_PREFIX_TIME>) -> Self::Output {
|
||||
self.0 / rhs.0
|
||||
}
|
||||
}
|
||||
|
||||
impl<const METRIC_PREFIX_TIME: i32> Display for Time<METRIC_PREFIX_TIME> {
|
||||
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
|
||||
match self {
|
||||
BinaryPrefix::None => Ok(()),
|
||||
BinaryPrefix::Kibi => write!(f, "Ki"),
|
||||
BinaryPrefix::Mebi => write!(f, "Mi"),
|
||||
BinaryPrefix::Gibi => write!(f, "Gi"),
|
||||
BinaryPrefix::Tebi => write!(f, "Ti"),
|
||||
let prefix = match METRIC_PREFIX_TIME {
|
||||
-6 => "µ",
|
||||
-3 => "m",
|
||||
0 => "s",
|
||||
_ => unreachable!(),
|
||||
};
|
||||
write!(f, "{} {}s", self.0, prefix)
|
||||
}
|
||||
}
|
||||
|
||||
impl<const BINARY_PREFIX_INFORMATION: i32> Display for Information<BINARY_PREFIX_INFORMATION> {
|
||||
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
|
||||
let prefix = match BINARY_PREFIX_INFORMATION {
|
||||
0 => "",
|
||||
10 => "Ki",
|
||||
20 => "Mi",
|
||||
30 => "Gi",
|
||||
40 => "Ti",
|
||||
_ => unreachable!(),
|
||||
};
|
||||
write!(f, "{} {}B", self.0, prefix)
|
||||
}
|
||||
}
|
||||
|
||||
macro_rules! quantity_fn {
|
||||
($name:ident, $unwrapped_values:ident, $body:expr) => {
|
||||
pub fn $name<
|
||||
const IS_TIME: bool,
|
||||
const METRIC_PREFIX_TIME: i32,
|
||||
const IS_INFORMATION: bool,
|
||||
const BINARY_PREFIX_INFORMATION: i32,
|
||||
>(
|
||||
values: &[Quantity<
|
||||
f64,
|
||||
IS_TIME,
|
||||
METRIC_PREFIX_TIME,
|
||||
IS_INFORMATION,
|
||||
BINARY_PREFIX_INFORMATION,
|
||||
>],
|
||||
) -> Quantity<f64, IS_TIME, METRIC_PREFIX_TIME, IS_INFORMATION, BINARY_PREFIX_INFORMATION> {
|
||||
let $unwrapped_values: Vec<f64> = values.iter().map(|v| v.0).collect();
|
||||
let result_value = $body;
|
||||
Quantity::new(result_value)
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Serialize, PartialEq)]
|
||||
pub enum Unit {
|
||||
Second(MetricPrefix),
|
||||
Byte(BinaryPrefix),
|
||||
}
|
||||
|
||||
pub const SECOND: Unit = Unit::Second(MetricPrefix::None);
|
||||
pub const MILLISECOND: Unit = Unit::Second(MetricPrefix::Milli);
|
||||
pub const MICROSECOND: Unit = Unit::Second(MetricPrefix::Micro);
|
||||
pub const BYTE: Unit = Unit::Byte(BinaryPrefix::None);
|
||||
|
||||
impl Display for Unit {
|
||||
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
|
||||
match self {
|
||||
Unit::Second(prefix) => write!(f, "{prefix}s",),
|
||||
Unit::Byte(prefix) => write!(f, "{prefix}B"),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Serialize, PartialEq)]
|
||||
pub struct Quantity<Value> {
|
||||
value: Value,
|
||||
unit: Unit,
|
||||
}
|
||||
|
||||
impl<Value> Quantity<Value> {
|
||||
pub fn new(value: Value, unit: Unit) -> Self {
|
||||
Self { value, unit }
|
||||
}
|
||||
}
|
||||
|
||||
impl<Value: Display> Display for Quantity<Value> {
|
||||
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
|
||||
write!(f, "{} {}", self.value, self.unit)
|
||||
}
|
||||
}
|
||||
|
||||
pub fn mean(values: &[Quantity<f64>]) -> Quantity<f64> {
|
||||
statistical::mean(values).unwrap()
|
||||
}
|
||||
|
||||
pub type Time = Quantity<f64>;
|
||||
pub type Memory = Quantity<u64>;
|
||||
quantity_fn!(mean, values, statistical::mean(&values));
|
||||
quantity_fn!(median, values, statistical::median(&values));
|
||||
quantity_fn!(min, values, crate::util::min_max::min(&values));
|
||||
quantity_fn!(max, values, crate::util::min_max::max(&values));
|
||||
quantity_fn!(standard_deviation, values, {
|
||||
let mean_value = statistical::mean(&values);
|
||||
statistical::standard_deviation(&values, Some(mean_value))
|
||||
});
|
||||
|
||||
#[test]
|
||||
fn basic() {
|
||||
let time = Time {
|
||||
value: 123.4,
|
||||
unit: Unit::Second(MetricPrefix::Milli),
|
||||
};
|
||||
fn test_quantity() {
|
||||
let time = MilliSecond::new(123.4);
|
||||
assert_eq!(time.value_in::<MilliSecond>(), 123.4);
|
||||
|
||||
let time_s = time.convert_to::<Second>();
|
||||
approx::assert_relative_eq!(time_s.value_in::<Second>(), 0.1234);
|
||||
|
||||
let time_us = time.convert_to::<MicroSecond>();
|
||||
approx::assert_relative_eq!(time_us.value_in::<MicroSecond>(), 123400.0);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_format() {
|
||||
let time = MilliSecond::new(123.4);
|
||||
assert_eq!(time.to_string(), "123.4 ms");
|
||||
|
||||
let peak_memory_usage = Memory {
|
||||
value: 8,
|
||||
unit: Unit::Byte(BinaryPrefix::Kibi),
|
||||
};
|
||||
let peak_memory_usage = KibiByte::new(8);
|
||||
assert_eq!(peak_memory_usage.to_string(), "8 KiB");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_mean() {
|
||||
let values = vec![MilliSecond::new(123.4), MilliSecond::new(234.5)];
|
||||
let result = mean(&values);
|
||||
assert_eq!(result.to_string(), "178.95 ms");
|
||||
}
|
||||
@@ -1,10 +1,7 @@
|
||||
use std::cmp::Ordering;
|
||||
|
||||
use super::benchmark_result::BenchmarkResult;
|
||||
use crate::{
|
||||
options::SortOrder,
|
||||
quantity::{self, Ratio, Time, Zero},
|
||||
};
|
||||
use crate::{benchmark::quantity::Second, options::SortOrder};
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct BenchmarkResultWithRelativeSpeed<'a> {
|
||||
@@ -55,8 +52,8 @@ fn compute_relative_speeds<'a>(
|
||||
let is_reference = std::ptr::eq(result, reference);
|
||||
let relative_ordering = compare_mean_time(result, reference);
|
||||
|
||||
if result.mean_wall_clock_time() == Time::zero()
|
||||
|| reference.mean_wall_clock_time() == Time::zero()
|
||||
if result.mean_wall_clock_time() == Second::zero()
|
||||
|| reference.mean_wall_clock_time() == Second::zero()
|
||||
{
|
||||
return BenchmarkResultWithRelativeSpeed {
|
||||
result,
|
||||
@@ -117,7 +114,8 @@ pub fn compute_with_check_from_reference<'a>(
|
||||
reference: &'a BenchmarkResult,
|
||||
sort_order: SortOrder,
|
||||
) -> Option<Vec<BenchmarkResultWithRelativeSpeed<'a>>> {
|
||||
if fastest_of(results).mean_wall_clock_time() == 0.0 || reference.mean_wall_clock_time() == 0.0
|
||||
if fastest_of(results).mean_wall_clock_time() == Second::zero()
|
||||
|| reference.mean_wall_clock_time() == Second::zero()
|
||||
{
|
||||
return None;
|
||||
}
|
||||
@@ -131,7 +129,7 @@ pub fn compute_with_check(
|
||||
) -> Option<Vec<BenchmarkResultWithRelativeSpeed<'_>>> {
|
||||
let fastest = fastest_of(results);
|
||||
|
||||
if fastest.mean_wall_clock_time() == 0.0 {
|
||||
if fastest.mean_wall_clock_time() == Second::zero() {
|
||||
return None;
|
||||
}
|
||||
|
||||
@@ -152,16 +150,19 @@ pub fn compute<'a>(
|
||||
fn create_result(name: &str, mean: f64) -> BenchmarkResult {
|
||||
use std::collections::BTreeMap;
|
||||
|
||||
use crate::benchmark::measurement::{Measurement, Measurements};
|
||||
use crate::benchmark::{
|
||||
measurement::{Measurement, Measurements},
|
||||
quantity::Byte,
|
||||
};
|
||||
|
||||
BenchmarkResult {
|
||||
command: name.into(),
|
||||
measurements: Measurements {
|
||||
measurements: vec![Measurement {
|
||||
wall_clock_time: mean,
|
||||
user_time: mean,
|
||||
system_time: 0.,
|
||||
memory_usage_byte: 1024,
|
||||
wall_clock_time: Second::new(mean),
|
||||
user_time: Second::new(mean),
|
||||
system_time: Second::zero(),
|
||||
memory_usage_byte: Byte::new(1024),
|
||||
exit_code: Some(0),
|
||||
}],
|
||||
},
|
||||
|
||||
+28
-37
@@ -4,6 +4,7 @@ use csv::WriterBuilder;
|
||||
|
||||
use super::Exporter;
|
||||
use crate::benchmark::benchmark_result::BenchmarkResult;
|
||||
use crate::benchmark::quantity::Second;
|
||||
use crate::options::SortOrder;
|
||||
use crate::quantity::{FormatQuantity, TimeUnit};
|
||||
|
||||
@@ -45,17 +46,14 @@ impl Exporter for CsvExporter {
|
||||
let mut fields = vec![Cow::Borrowed(res.command.as_bytes())];
|
||||
for f in &[
|
||||
res.mean_wall_clock_time(),
|
||||
res.measurements.stddev().unwrap_or(0.0),
|
||||
res.measurements.stddev().unwrap_or_default(),
|
||||
res.measurements.median(),
|
||||
res.measurements.user_mean(),
|
||||
res.measurements.system_mean(),
|
||||
res.measurements.min(),
|
||||
res.measurements.max(),
|
||||
] {
|
||||
fields.push(Cow::Owned(
|
||||
f.format_with_precision(CSV_UNIT, CSV_PRECISION)
|
||||
.into_bytes(),
|
||||
))
|
||||
fields.push(Cow::Owned(f.value_in::<Second>().to_string().into_bytes()))
|
||||
}
|
||||
for v in res.parameters.values() {
|
||||
fields.push(Cow::Borrowed(v.value.as_bytes()))
|
||||
@@ -67,20 +65,13 @@ impl Exporter for CsvExporter {
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
use crate::benchmark::benchmark_result::Parameter;
|
||||
|
||||
#[cfg(test)]
|
||||
use crate::benchmark::measurement::{Measurement, Measurements};
|
||||
|
||||
#[test]
|
||||
fn test_csv() {
|
||||
use crate::benchmark::benchmark_result::Parameter;
|
||||
use crate::benchmark::measurement::{Measurement, Measurements};
|
||||
use crate::quantity::{byte, second, Information, Time, Zero};
|
||||
use crate::benchmark::quantity::{Byte, Second};
|
||||
|
||||
use std::collections::BTreeMap;
|
||||
use std::process::ExitStatus;
|
||||
|
||||
let exporter = CsvExporter::default();
|
||||
|
||||
@@ -89,24 +80,24 @@ fn test_csv() {
|
||||
command: String::from("command_a"),
|
||||
measurements: Measurements::new(vec![
|
||||
Measurement {
|
||||
wall_clock_time: 7.0,
|
||||
user_time: 7.0,
|
||||
system_time: 0.0,
|
||||
memory_usage_byte: 1024,
|
||||
wall_clock_time: Second::new(7.0),
|
||||
user_time: Second::new(7.0),
|
||||
system_time: Second::zero(),
|
||||
memory_usage_byte: Byte::new(1024),
|
||||
exit_code: Some(0),
|
||||
},
|
||||
Measurement {
|
||||
wall_clock_time: 8.0,
|
||||
user_time: 8.0,
|
||||
system_time: 0.0,
|
||||
memory_usage_byte: 1024,
|
||||
wall_clock_time: Second::new(8.0),
|
||||
user_time: Second::new(8.0),
|
||||
system_time: Second::zero(),
|
||||
memory_usage_byte: Byte::new(1024),
|
||||
exit_code: Some(0),
|
||||
},
|
||||
Measurement {
|
||||
wall_clock_time: 12.0,
|
||||
user_time: 12.0,
|
||||
system_time: 0.0,
|
||||
memory_usage_byte: 1024,
|
||||
wall_clock_time: Second::new(12.0),
|
||||
user_time: Second::new(12.0),
|
||||
system_time: Second::zero(),
|
||||
memory_usage_byte: Byte::new(1024),
|
||||
exit_code: Some(0),
|
||||
},
|
||||
]),
|
||||
@@ -133,24 +124,24 @@ fn test_csv() {
|
||||
command: String::from("command_b"),
|
||||
measurements: Measurements::new(vec![
|
||||
Measurement {
|
||||
wall_clock_time: 17.0,
|
||||
user_time: 17.0,
|
||||
system_time: 0.0,
|
||||
memory_usage_byte: 1024,
|
||||
wall_clock_time: Second::new(17.0),
|
||||
user_time: Second::new(17.0),
|
||||
system_time: Second::zero(),
|
||||
memory_usage_byte: Byte::new(1024),
|
||||
exit_code: Some(0),
|
||||
},
|
||||
Measurement {
|
||||
wall_clock_time: 18.0,
|
||||
user_time: 18.0,
|
||||
system_time: 0.0,
|
||||
memory_usage_byte: 1024,
|
||||
wall_clock_time: Second::new(18.0),
|
||||
user_time: Second::new(18.0),
|
||||
system_time: Second::zero(),
|
||||
memory_usage_byte: Byte::new(1024),
|
||||
exit_code: Some(0),
|
||||
},
|
||||
Measurement {
|
||||
wall_clock_time: 19.0,
|
||||
user_time: 19.0,
|
||||
system_time: 0.0,
|
||||
memory_usage_byte: 1024,
|
||||
wall_clock_time: Second::new(19.0),
|
||||
user_time: Second::new(19.0),
|
||||
system_time: Second::zero(),
|
||||
memory_usage_byte: Byte::new(1024),
|
||||
exit_code: Some(0),
|
||||
},
|
||||
]),
|
||||
|
||||
+97
-96
@@ -1,6 +1,7 @@
|
||||
use super::Exporter;
|
||||
use crate::benchmark::benchmark_result::BenchmarkResult;
|
||||
use crate::benchmark::measurement::{Measurement, Measurements};
|
||||
use crate::benchmark::quantity::{Byte, Second};
|
||||
use crate::export::asciidoc::AsciidocExporter;
|
||||
use crate::export::orgmode::OrgmodeExporter;
|
||||
use crate::quantity::{byte, second, Information, Time, TimeUnit, Zero};
|
||||
@@ -30,24 +31,24 @@ fn test_markup_export_auto_ms() {
|
||||
command: String::from("sleep 0.1"),
|
||||
measurements: Measurements::new(vec![
|
||||
Measurement {
|
||||
wall_clock_time: 0.09,
|
||||
user_time: 0.09,
|
||||
system_time: 0.,
|
||||
memory_usage_byte: 1024,
|
||||
wall_clock_time: Second::new(0.09),
|
||||
user_time: Second::new(0.09),
|
||||
system_time: Second::zero(),
|
||||
memory_usage_byte: Byte::new(1024),
|
||||
exit_code: Some(0),
|
||||
},
|
||||
Measurement {
|
||||
wall_clock_time: 0.10,
|
||||
user_time: 0.10,
|
||||
system_time: 0.,
|
||||
memory_usage_byte: 1024,
|
||||
wall_clock_time: Second::new(0.10),
|
||||
user_time: Second::new(0.10),
|
||||
system_time: Second::zero(),
|
||||
memory_usage_byte: Byte::new(1024),
|
||||
exit_code: Some(0),
|
||||
},
|
||||
Measurement {
|
||||
wall_clock_time: 0.14,
|
||||
user_time: 0.14,
|
||||
system_time: 0.,
|
||||
memory_usage_byte: 1024,
|
||||
wall_clock_time: Second::new(0.14),
|
||||
user_time: Second::new(0.14),
|
||||
system_time: Second::zero(),
|
||||
memory_usage_byte: Byte::new(1024),
|
||||
exit_code: Some(0),
|
||||
},
|
||||
]),
|
||||
@@ -57,24 +58,24 @@ fn test_markup_export_auto_ms() {
|
||||
command: String::from("sleep 2"),
|
||||
measurements: Measurements::new(vec![
|
||||
Measurement {
|
||||
wall_clock_time: 2.0,
|
||||
user_time: 2.0,
|
||||
system_time: 0.,
|
||||
memory_usage_byte: 1024,
|
||||
wall_clock_time: Second::new(2.0),
|
||||
user_time: Second::new(2.0),
|
||||
system_time: Second::zero(),
|
||||
memory_usage_byte: Byte::new(1024),
|
||||
exit_code: Some(0),
|
||||
},
|
||||
Measurement {
|
||||
wall_clock_time: 3.0,
|
||||
user_time: 3.0,
|
||||
system_time: 0.,
|
||||
memory_usage_byte: 1024,
|
||||
wall_clock_time: Second::new(3.0),
|
||||
user_time: Second::new(3.0),
|
||||
system_time: Second::zero(),
|
||||
memory_usage_byte: Byte::new(1024),
|
||||
exit_code: Some(0),
|
||||
},
|
||||
Measurement {
|
||||
wall_clock_time: 4.0,
|
||||
user_time: 4.0,
|
||||
system_time: 0.,
|
||||
memory_usage_byte: 1024,
|
||||
wall_clock_time: Second::new(4.0),
|
||||
user_time: Second::new(4.0),
|
||||
system_time: Second::zero(),
|
||||
memory_usage_byte: Byte::new(1024),
|
||||
exit_code: Some(0),
|
||||
},
|
||||
]),
|
||||
@@ -129,24 +130,24 @@ fn test_markup_export_auto_s() {
|
||||
command: String::from("sleep 2"),
|
||||
measurements: Measurements::new(vec![
|
||||
Measurement {
|
||||
wall_clock_time: 2.1,
|
||||
user_time: 2.1,
|
||||
system_time: 0.,
|
||||
memory_usage_byte: 1024,
|
||||
wall_clock_time: Second::new(2.1),
|
||||
user_time: Second::new(2.1),
|
||||
system_time: Second::zero(),
|
||||
memory_usage_byte: Byte::new(1024),
|
||||
exit_code: Some(0),
|
||||
},
|
||||
Measurement {
|
||||
wall_clock_time: 2.2,
|
||||
user_time: 2.2,
|
||||
system_time: 0.,
|
||||
memory_usage_byte: 1024,
|
||||
wall_clock_time: Second::new(2.2),
|
||||
user_time: Second::new(2.2),
|
||||
system_time: Second::zero(),
|
||||
memory_usage_byte: Byte::new(1024),
|
||||
exit_code: Some(0),
|
||||
},
|
||||
Measurement {
|
||||
wall_clock_time: 2.3,
|
||||
user_time: 2.3,
|
||||
system_time: 0.,
|
||||
memory_usage_byte: 1024,
|
||||
wall_clock_time: Second::new(2.3),
|
||||
user_time: Second::new(2.3),
|
||||
system_time: Second::zero(),
|
||||
memory_usage_byte: Byte::new(1024),
|
||||
exit_code: Some(0),
|
||||
},
|
||||
]),
|
||||
@@ -156,24 +157,24 @@ fn test_markup_export_auto_s() {
|
||||
command: String::from("sleep 0.1"),
|
||||
measurements: Measurements::new(vec![
|
||||
Measurement {
|
||||
wall_clock_time: 0.1,
|
||||
user_time: 0.1,
|
||||
system_time: 0.,
|
||||
memory_usage_byte: 1024,
|
||||
wall_clock_time: Second::new(0.1),
|
||||
user_time: Second::new(0.1),
|
||||
system_time: Second::zero(),
|
||||
memory_usage_byte: Byte::new(1024),
|
||||
exit_code: Some(0),
|
||||
},
|
||||
Measurement {
|
||||
wall_clock_time: 0.2,
|
||||
user_time: 0.2,
|
||||
system_time: 0.,
|
||||
memory_usage_byte: 1024,
|
||||
wall_clock_time: Second::new(0.2),
|
||||
user_time: Second::new(0.2),
|
||||
system_time: Second::zero(),
|
||||
memory_usage_byte: Byte::new(1024),
|
||||
exit_code: Some(0),
|
||||
},
|
||||
Measurement {
|
||||
wall_clock_time: 0.3,
|
||||
user_time: 0.3,
|
||||
system_time: 0.,
|
||||
memory_usage_byte: 1024,
|
||||
wall_clock_time: Second::new(0.3),
|
||||
user_time: Second::new(0.3),
|
||||
system_time: Second::zero(),
|
||||
memory_usage_byte: Byte::new(1024),
|
||||
exit_code: Some(0),
|
||||
},
|
||||
]),
|
||||
@@ -228,24 +229,24 @@ fn test_markup_export_manual_ms() {
|
||||
command: String::from("sleep 2"),
|
||||
measurements: Measurements::new(vec![
|
||||
Measurement {
|
||||
wall_clock_time: 2.1,
|
||||
user_time: 2.1,
|
||||
system_time: 0.,
|
||||
memory_usage_byte: 1024,
|
||||
wall_clock_time: Second::new(2.1),
|
||||
user_time: Second::new(2.1),
|
||||
system_time: Second::zero(),
|
||||
memory_usage_byte: Byte::new(1024),
|
||||
exit_code: Some(0),
|
||||
},
|
||||
Measurement {
|
||||
wall_clock_time: 2.2,
|
||||
user_time: 2.2,
|
||||
system_time: 0.,
|
||||
memory_usage_byte: 1024,
|
||||
wall_clock_time: Second::new(2.2),
|
||||
user_time: Second::new(2.2),
|
||||
system_time: Second::zero(),
|
||||
memory_usage_byte: Byte::new(1024),
|
||||
exit_code: Some(0),
|
||||
},
|
||||
Measurement {
|
||||
wall_clock_time: 2.3,
|
||||
user_time: 2.3,
|
||||
system_time: 0.,
|
||||
memory_usage_byte: 1024,
|
||||
wall_clock_time: Second::new(2.3),
|
||||
user_time: Second::new(2.3),
|
||||
system_time: Second::zero(),
|
||||
memory_usage_byte: Byte::new(1024),
|
||||
exit_code: Some(0),
|
||||
},
|
||||
]),
|
||||
@@ -255,24 +256,24 @@ fn test_markup_export_manual_ms() {
|
||||
command: String::from("sleep 0.1"),
|
||||
measurements: Measurements::new(vec![
|
||||
Measurement {
|
||||
wall_clock_time: 0.1,
|
||||
user_time: 0.1,
|
||||
system_time: 0.,
|
||||
memory_usage_byte: 1024,
|
||||
wall_clock_time: Second::new(0.1),
|
||||
user_time: Second::new(0.1),
|
||||
system_time: Second::zero(),
|
||||
memory_usage_byte: Byte::new(1024),
|
||||
exit_code: Some(0),
|
||||
},
|
||||
Measurement {
|
||||
wall_clock_time: 0.2,
|
||||
user_time: 0.2,
|
||||
system_time: 0.,
|
||||
memory_usage_byte: 1024,
|
||||
wall_clock_time: Second::new(0.2),
|
||||
user_time: Second::new(0.2),
|
||||
system_time: Second::zero(),
|
||||
memory_usage_byte: Byte::new(1024),
|
||||
exit_code: Some(0),
|
||||
},
|
||||
Measurement {
|
||||
wall_clock_time: 0.3,
|
||||
user_time: 0.3,
|
||||
system_time: 0.,
|
||||
memory_usage_byte: 1024,
|
||||
wall_clock_time: Second::new(0.3),
|
||||
user_time: Second::new(0.3),
|
||||
system_time: Second::zero(),
|
||||
memory_usage_byte: Byte::new(1024),
|
||||
exit_code: Some(0),
|
||||
},
|
||||
]),
|
||||
@@ -326,24 +327,24 @@ fn test_markup_export_manual_s() {
|
||||
command: String::from("sleep 2"),
|
||||
measurements: Measurements::new(vec![
|
||||
Measurement {
|
||||
wall_clock_time: 2.01,
|
||||
user_time: 2.01,
|
||||
system_time: 0.,
|
||||
memory_usage_byte: 1024,
|
||||
wall_clock_time: Second::new(2.01),
|
||||
user_time: Second::new(2.01),
|
||||
system_time: Second::zero(),
|
||||
memory_usage_byte: Byte::new(1024),
|
||||
exit_code: Some(0),
|
||||
},
|
||||
Measurement {
|
||||
wall_clock_time: 2.02,
|
||||
user_time: 2.02,
|
||||
system_time: 0.,
|
||||
memory_usage_byte: 1024,
|
||||
wall_clock_time: Second::new(2.02),
|
||||
user_time: Second::new(2.02),
|
||||
system_time: Second::zero(),
|
||||
memory_usage_byte: Byte::new(1024),
|
||||
exit_code: Some(0),
|
||||
},
|
||||
Measurement {
|
||||
wall_clock_time: 2.03,
|
||||
user_time: 2.03,
|
||||
system_time: 0.,
|
||||
memory_usage_byte: 1024,
|
||||
wall_clock_time: Second::new(2.03),
|
||||
user_time: Second::new(2.03),
|
||||
system_time: Second::zero(),
|
||||
memory_usage_byte: Byte::new(1024),
|
||||
exit_code: Some(0),
|
||||
},
|
||||
]),
|
||||
@@ -353,24 +354,24 @@ fn test_markup_export_manual_s() {
|
||||
command: String::from("sleep 0.1"),
|
||||
measurements: Measurements::new(vec![
|
||||
Measurement {
|
||||
wall_clock_time: 0.11,
|
||||
user_time: 0.11,
|
||||
system_time: 0.,
|
||||
memory_usage_byte: 1024,
|
||||
wall_clock_time: Second::new(0.11),
|
||||
user_time: Second::new(0.11),
|
||||
system_time: Second::zero(),
|
||||
memory_usage_byte: Byte::new(1024),
|
||||
exit_code: Some(0),
|
||||
},
|
||||
Measurement {
|
||||
wall_clock_time: 0.12,
|
||||
user_time: 0.12,
|
||||
system_time: 0.,
|
||||
memory_usage_byte: 1024,
|
||||
wall_clock_time: Second::new(0.12),
|
||||
user_time: Second::new(0.12),
|
||||
system_time: Second::zero(),
|
||||
memory_usage_byte: Byte::new(1024),
|
||||
exit_code: Some(0),
|
||||
},
|
||||
Measurement {
|
||||
wall_clock_time: 0.13,
|
||||
user_time: 0.13,
|
||||
system_time: 0.,
|
||||
memory_usage_byte: 1024,
|
||||
wall_clock_time: Second::new(0.13),
|
||||
user_time: Second::new(0.13),
|
||||
system_time: Second::zero(),
|
||||
memory_usage_byte: Byte::new(1024),
|
||||
exit_code: Some(0),
|
||||
},
|
||||
]),
|
||||
|
||||
+4
-3
@@ -7,9 +7,10 @@ use std::{cmp, env, fmt, io};
|
||||
use anyhow::{bail, ensure};
|
||||
use clap::ArgMatches;
|
||||
|
||||
use crate::benchmark::quantity::Second;
|
||||
use crate::command::Commands;
|
||||
use crate::error::OptionsError;
|
||||
use crate::quantity::{second, Time, TimeUnit};
|
||||
use crate::util::units::Unit;
|
||||
|
||||
use anyhow::Result;
|
||||
|
||||
@@ -256,7 +257,7 @@ impl Default for Options {
|
||||
Options {
|
||||
run_bounds: RunBounds::default(),
|
||||
warmup_count: 0,
|
||||
min_benchmarking_time: Time::new::<second>(3.0),
|
||||
min_benchmarking_time: Second::new(3.0),
|
||||
command_failure_action: CmdFailureAction::RaiseError,
|
||||
reference_command: None,
|
||||
reference_name: None,
|
||||
@@ -442,7 +443,7 @@ impl Options {
|
||||
};
|
||||
|
||||
if let Some(time) = matches.get_one::<String>("min-benchmarking-time") {
|
||||
options.min_benchmarking_time = Time::new::<second>(
|
||||
options.min_benchmarking_time = Second::new(
|
||||
time.parse::<f64>()
|
||||
.map_err(|e| OptionsError::FloatParsingError("min-benchmarking-time", e))?,
|
||||
);
|
||||
|
||||
@@ -1,7 +1,8 @@
|
||||
use std::fmt;
|
||||
|
||||
use crate::benchmark::quantity::Second;
|
||||
use crate::benchmark::MIN_EXECUTION_TIME;
|
||||
use crate::quantity::{FormatQuantity, Time, TimeUnit};
|
||||
use crate::output::format::format_duration;
|
||||
|
||||
pub struct OutlierWarningOptions {
|
||||
pub warmup_in_use: bool,
|
||||
@@ -21,11 +22,10 @@ impl fmt::Display for Warnings {
|
||||
match *self {
|
||||
Warnings::FastExecutionTime => write!(
|
||||
f,
|
||||
"Command took less than {} ms to complete. Note that the results might be \
|
||||
"Command took less than {MIN_EXECUTION_TIME} 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.format_with_precision(TimeUnit::MilliSecond, 0)
|
||||
),
|
||||
Warnings::NonZeroExitCode => write!(f, "Ignoring non-zero exit code."),
|
||||
Warnings::SlowInitialRun(time_first_run, ref options) => write!(
|
||||
|
||||
+2
-2
@@ -16,7 +16,7 @@ use std::os::fd::AsFd;
|
||||
#[cfg(target_os = "windows")]
|
||||
use windows_sys::Win32::System::Threading::CREATE_SUSPENDED;
|
||||
|
||||
use crate::benchmark::measurement::Measurement;
|
||||
use crate::benchmark::quantity::{Byte, Second};
|
||||
use wall_clock_timer::WallClockTimer;
|
||||
|
||||
use std::io::Read;
|
||||
@@ -30,7 +30,7 @@ pub struct TimerResult {
|
||||
pub time_wall_clock: Second,
|
||||
pub time_user: Second,
|
||||
pub time_system: Second,
|
||||
pub memory_usage_byte: u64,
|
||||
pub memory_usage_byte: Byte,
|
||||
/// The exit status of the process
|
||||
pub status: ExitStatus,
|
||||
}
|
||||
|
||||
@@ -8,22 +8,22 @@ use std::process::{Child, ExitStatus};
|
||||
|
||||
use anyhow::Result;
|
||||
|
||||
use crate::util::units::Second;
|
||||
use crate::benchmark::quantity::{Byte, Second};
|
||||
|
||||
#[derive(Debug, Copy, Clone)]
|
||||
struct ResourceUsage {
|
||||
/// Total amount of time spent executing in user mode
|
||||
pub user_usec: Second,
|
||||
pub user_usec: f64,
|
||||
|
||||
/// Total amount of time spent executing in kernel mode
|
||||
pub system_usec: Second,
|
||||
pub system_usec: f64,
|
||||
|
||||
/// Maximum amount of memory used by the process, in bytes
|
||||
pub memory_usage_byte: i64,
|
||||
}
|
||||
|
||||
#[allow(clippy::useless_conversion)]
|
||||
fn timeval_to_seconds(tv: libc::timeval) -> Second {
|
||||
fn timeval_to_seconds(tv: libc::timeval) -> f64 {
|
||||
const MICROSEC_PER_SEC: i64 = 1000 * 1000;
|
||||
(i64::from(tv.tv_sec) * MICROSEC_PER_SEC + i64::from(tv.tv_usec)) as f64 * 1e-6
|
||||
}
|
||||
@@ -68,13 +68,13 @@ impl CPUTimer {
|
||||
Self {}
|
||||
}
|
||||
|
||||
pub fn stop(&self, child: Child) -> Result<(ExitStatus, Second, Second, u64)> {
|
||||
pub fn stop(&self, child: Child) -> Result<(ExitStatus, Second, Second, Byte)> {
|
||||
let (status, usage) = wait4(child)?;
|
||||
Ok((
|
||||
status,
|
||||
usage.user_usec,
|
||||
usage.system_usec,
|
||||
u64::try_from(usage.memory_usage_byte).unwrap_or(0),
|
||||
Second::new(usage.user_usec),
|
||||
Second::new(usage.system_usec),
|
||||
Byte::new(u64::try_from(usage.memory_usage_byte).unwrap_or(0)),
|
||||
))
|
||||
}
|
||||
}
|
||||
@@ -1,6 +1,6 @@
|
||||
use std::time::Instant;
|
||||
|
||||
use crate::quantity::{nanosecond, second, Time};
|
||||
use crate::benchmark::quantity::Second;
|
||||
|
||||
pub struct WallClockTimer {
|
||||
start: Instant,
|
||||
@@ -15,8 +15,7 @@ impl WallClockTimer {
|
||||
|
||||
pub fn stop(&self) -> Time {
|
||||
let duration = self.start.elapsed();
|
||||
|
||||
Time::new::<second>(duration.as_secs() as f64)
|
||||
+ Time::new::<nanosecond>(duration.subsec_nanos() as f64)
|
||||
// TODO
|
||||
Second::new(duration.as_secs() as f64 + f64::from(duration.subsec_nanos()) * 1e-9)
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user