mirror of
https://github.com/sharkdp/hyperfine.git
synced 2026-11-01 08:50:19 +00:00
Updates
This commit is contained in:
1 parent
55dfe6722c
commit
a027c1eb22
21 files changed
+346
-154
No files matched your search
@@ -100,8 +100,34 @@ pub struct Measurement {
|
||||
pub exit_status: ExitStatus,
|
||||
}
|
||||
|
||||
impl Measurement {
|
||||
/// Total CPU time for this run, including user and kernel mode.
|
||||
pub fn time_cpu(&self) -> Time {
|
||||
self.time_user + self.time_system
|
||||
}
|
||||
}
|
||||
|
||||
fn serialize_measurements<S>(measurements: &[Measurement], serializer: S) -> Result<S::Ok, S::Error>
|
||||
where
|
||||
S: serde::Serializer,
|
||||
{
|
||||
#[derive(Serialize)]
|
||||
struct WithCpuTime<'a> {
|
||||
#[serde(flatten)]
|
||||
measurement: &'a Measurement,
|
||||
#[serde(serialize_with = "serialize_time")]
|
||||
time_cpu: Time,
|
||||
}
|
||||
|
||||
serializer.collect_seq(measurements.iter().map(|measurement| WithCpuTime {
|
||||
measurement,
|
||||
time_cpu: measurement.time_cpu(),
|
||||
}))
|
||||
}
|
||||
|
||||
#[derive(Debug, Default, Clone, Serialize, PartialEq)]
|
||||
pub struct Measurements {
|
||||
#[serde(serialize_with = "serialize_measurements")]
|
||||
pub measurements: Vec<Measurement>,
|
||||
}
|
||||
|
||||
|
||||
@@ -81,7 +81,7 @@ fn generate_results(args: &[&'static str]) -> Result<Vec<BenchmarkResult>> {
|
||||
|
||||
#[test]
|
||||
fn scheduler_basic() -> Result<()> {
|
||||
insta::assert_yaml_snapshot!(generate_results(&["--runs=2", "sleep 0.123", "sleep 0.456"])?, @r#"
|
||||
insta::assert_yaml_snapshot!(generate_results(&["--runs=2", "sleep 0.123", "sleep 0.456"])?, @"
|
||||
- command: sleep 0.123
|
||||
measurements:
|
||||
- time_wall_clock:
|
||||
@@ -97,6 +97,9 @@ fn scheduler_basic() -> Result<()> {
|
||||
value: 0
|
||||
unit: byte
|
||||
exit_code: 0
|
||||
time_cpu:
|
||||
value: 0
|
||||
unit: second
|
||||
- time_wall_clock:
|
||||
value: 0.123
|
||||
unit: second
|
||||
@@ -110,6 +113,9 @@ fn scheduler_basic() -> Result<()> {
|
||||
value: 0
|
||||
unit: byte
|
||||
exit_code: 0
|
||||
time_cpu:
|
||||
value: 0
|
||||
unit: second
|
||||
- command: sleep 0.456
|
||||
measurements:
|
||||
- time_wall_clock:
|
||||
@@ -125,6 +131,9 @@ fn scheduler_basic() -> Result<()> {
|
||||
value: 0
|
||||
unit: byte
|
||||
exit_code: 0
|
||||
time_cpu:
|
||||
value: 0
|
||||
unit: second
|
||||
- time_wall_clock:
|
||||
value: 0.456
|
||||
unit: second
|
||||
@@ -138,7 +147,10 @@ fn scheduler_basic() -> Result<()> {
|
||||
value: 0
|
||||
unit: byte
|
||||
exit_code: 0
|
||||
"#);
|
||||
time_cpu:
|
||||
value: 0
|
||||
unit: second
|
||||
");
|
||||
|
||||
Ok(())
|
||||
}
|
||||
+3
-3
@@ -57,11 +57,11 @@ fn build_command() -> Command {
|
||||
.default_value("default")
|
||||
.help("Metrics to display, in order. The first is used for non-JSON exports. \
|
||||
Compare all commands with the first command. Presets: default (wall-clock \
|
||||
time and peak RSS; wall-clock time only on Windows), speed (wall-clock, user, \
|
||||
and system time), all (all available metrics, skipping unavailable \
|
||||
time and peak RSS; wall-clock time only on Windows), time (wall-clock, total CPU, \
|
||||
user, and system time), all (all available metrics, skipping unavailable \
|
||||
measurements). All presets use automatic \
|
||||
units with wall-clock time first; use a preset on its own. Metrics: time_wall_clock, \
|
||||
time_user, time_system, memory_peak_resident, cpu_cycles, instructions, \
|
||||
time_cpu (user + system), time_user, time_system, memory_peak_resident, cpu_cycles, instructions, \
|
||||
cache_references, cache_misses, branch_misses. Optional units: ns/us/ms/s/min/h \
|
||||
for time, B/kB/MB/GB/TB/KiB/MiB/GiB/TiB for memory, count/k/M/B for counters \
|
||||
(k = thousand, M = million, B = billion). Example: \
|
||||
|
||||
+34
-3
@@ -9,6 +9,7 @@ use crate::quantity::{byte, ratio, second, Ratio};
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
||||
pub enum Metric {
|
||||
TimeWallClock,
|
||||
TimeCpu,
|
||||
TimeUser,
|
||||
TimeSystem,
|
||||
MemoryPeakResident,
|
||||
@@ -20,8 +21,9 @@ pub enum Metric {
|
||||
}
|
||||
|
||||
impl Metric {
|
||||
pub const ALL: [Self; 9] = [
|
||||
pub const ALL: [Self; 10] = [
|
||||
Self::TimeWallClock,
|
||||
Self::TimeCpu,
|
||||
Self::TimeUser,
|
||||
Self::TimeSystem,
|
||||
Self::MemoryPeakResident,
|
||||
@@ -35,6 +37,7 @@ impl Metric {
|
||||
pub fn name(self) -> &'static str {
|
||||
match self {
|
||||
Self::TimeWallClock => "time_wall_clock",
|
||||
Self::TimeCpu => "time_cpu",
|
||||
Self::TimeUser => "time_user",
|
||||
Self::TimeSystem => "time_system",
|
||||
Self::MemoryPeakResident => "memory_peak_resident",
|
||||
@@ -49,6 +52,7 @@ impl Metric {
|
||||
pub fn label(self) -> &'static str {
|
||||
match self {
|
||||
Self::TimeWallClock => "Wall Time",
|
||||
Self::TimeCpu => "CPU time",
|
||||
Self::TimeUser => "User time",
|
||||
Self::TimeSystem => "System time",
|
||||
Self::MemoryPeakResident => "Memory",
|
||||
@@ -65,6 +69,7 @@ impl Metric {
|
||||
let counters = &measurement.hardware_counters;
|
||||
match self {
|
||||
Self::TimeWallClock => Some(measurement.time_wall_clock.get::<second>()),
|
||||
Self::TimeCpu => Some(measurement.time_cpu().get::<second>()),
|
||||
Self::TimeUser => Some(measurement.time_user.get::<second>()),
|
||||
Self::TimeSystem => Some(measurement.time_system.get::<second>()),
|
||||
Self::MemoryPeakResident => measurement.memory_peak_resident.map(|v| v.get::<byte>()),
|
||||
@@ -79,7 +84,7 @@ impl Metric {
|
||||
pub fn is_time(self) -> bool {
|
||||
matches!(
|
||||
self,
|
||||
Self::TimeWallClock | Self::TimeUser | Self::TimeSystem
|
||||
Self::TimeWallClock | Self::TimeCpu | Self::TimeUser | Self::TimeSystem
|
||||
)
|
||||
}
|
||||
|
||||
@@ -349,7 +354,33 @@ impl Stats {
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
use crate::quantity::Information;
|
||||
use crate::quantity::{Information, Time};
|
||||
|
||||
#[test]
|
||||
fn cpu_time_statistics_use_per_run_totals() {
|
||||
let measurements = Measurements::new(
|
||||
[(1.0, 3.0), (3.0, 1.0)]
|
||||
.iter()
|
||||
.map(|&(user, system)| Measurement {
|
||||
time_user: Time::new::<second>(user),
|
||||
time_system: Time::new::<second>(system),
|
||||
..Measurement::default()
|
||||
})
|
||||
.collect(),
|
||||
);
|
||||
let selection = MetricSelection::parse_list("time_cpu:ms").unwrap()[0];
|
||||
let stats = selection.metric.summarize(&measurements).unwrap();
|
||||
assert_eq!(selection.csv_unit().format(stats.mean), "4000.0 ms");
|
||||
// User and system time vary, but their per-run total is constant.
|
||||
assert_eq!(stats.stddev, Some(0.0));
|
||||
assert_eq!(stats.min, 4.0);
|
||||
assert_eq!(stats.max, 4.0);
|
||||
let json = serde_json::to_value(&measurements).unwrap();
|
||||
for sample in json["measurements"].as_array().unwrap() {
|
||||
assert_eq!(sample["time_cpu"]["value"], 4.0);
|
||||
assert_eq!(sample["time_cpu"]["unit"], "second");
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn selection_units_and_validation() {
|
||||
|
||||
+9
-4
@@ -397,10 +397,15 @@ impl Options {
|
||||
|
||||
match matches.get_one::<String>("metrics").unwrap().as_str() {
|
||||
"default" => {}
|
||||
"speed" => {
|
||||
options.metrics = [Metric::TimeWallClock, Metric::TimeUser, Metric::TimeSystem]
|
||||
.map(|metric| MetricSelection { metric, unit: None })
|
||||
.to_vec();
|
||||
"time" => {
|
||||
options.metrics = [
|
||||
Metric::TimeWallClock,
|
||||
Metric::TimeCpu,
|
||||
Metric::TimeUser,
|
||||
Metric::TimeSystem,
|
||||
]
|
||||
.map(|metric| MetricSelection { metric, unit: None })
|
||||
.to_vec();
|
||||
}
|
||||
"all" => {
|
||||
let shell = matches!(
|
||||
|
||||
Reference in new issue
Block a user