Include raw commands in JSON exports when names differ

This commit is contained in:
David Peter committed 2026-10-05 17:02:34 +02:00
1 parent 1b3ec922fa
commit c5d3a81fc5
7 files changed
+79 -2

No files matched your search

+5 -1
View File
@@ -15,9 +15,13 @@ pub struct Parameter {
/// Meta data and performance metrics for a single benchmark
#[derive(Debug, Default, Clone, Serialize, PartialEq)]
pub struct BenchmarkResult {
/// The full command line of the program that is being benchmarked
/// The display name of the command being benchmarked
pub command: String,
/// The expanded command line, when it differs from the display name
#[serde(skip_serializing_if = "Option::is_none")]
pub command_raw: Option<String>,
/// Performance metric measurements and exit codes for each run
#[serde(flatten)]
pub measurements: Measurements,
+6 -1
View File
@@ -475,8 +475,13 @@ impl<'a> Benchmark<'a> {
self.run_cleanup_command(self.command.get_parameters().iter().cloned(), output_policy)?;
let command = self.command.get_name();
let command_raw = self.command.get_command_line();
let command_raw = (command_raw != command).then_some(command_raw);
Ok(BenchmarkResult {
command: self.command.get_name(),
command,
command_raw,
measurements,
parameters: self
.command
+1
View File
@@ -158,6 +158,7 @@ fn create_result(name: &str, mean: f64) -> BenchmarkResult {
BenchmarkResult {
command: name.into(),
command_raw: None,
measurements: Measurements {
measurements: vec![Measurement {
time_wall_clock: Time::new::<second>(mean),
+2
View File
@@ -81,6 +81,7 @@ fn test_csv() {
let results = vec![
BenchmarkResult {
command: String::from("command_a"),
command_raw: None,
measurements: Measurements::new(vec![
Measurement {
time_wall_clock: Time::new::<second>(7.0),
@@ -125,6 +126,7 @@ fn test_csv() {
},
BenchmarkResult {
command: String::from("command_b"),
command_raw: None,
measurements: Measurements::new(vec![
Measurement {
time_wall_clock: Time::new::<second>(17.0),
+2
View File
@@ -182,6 +182,7 @@ fn test_json_optional_memory() {
] {
let result = BenchmarkResult {
command: "example".into(),
command_raw: None,
measurements: Measurements::new(vec![Measurement {
peak_memory_usage: memory,
..Measurement::default()
@@ -249,6 +250,7 @@ fn test_json_summaries_for_parameterized_results() {
.into_iter()
.map(|(size, times)| BenchmarkResult {
command: "example".into(),
command_raw: None,
parameters: [(
"size".into(),
Parameter {
+8
View File
@@ -28,6 +28,7 @@ fn test_markup_export_auto_ms() {
let results = [
BenchmarkResult {
command: String::from("sleep 0.1"),
command_raw: None,
measurements: Measurements::new(vec![
Measurement {
time_wall_clock: Time::new::<second>(0.09),
@@ -55,6 +56,7 @@ fn test_markup_export_auto_ms() {
},
BenchmarkResult {
command: String::from("sleep 2"),
command_raw: None,
measurements: Measurements::new(vec![
Measurement {
time_wall_clock: Time::new::<second>(2.0),
@@ -127,6 +129,7 @@ fn test_markup_export_auto_s() {
let results = [
BenchmarkResult {
command: String::from("sleep 2"),
command_raw: None,
measurements: Measurements::new(vec![
Measurement {
time_wall_clock: Time::new::<second>(2.1),
@@ -154,6 +157,7 @@ fn test_markup_export_auto_s() {
},
BenchmarkResult {
command: String::from("sleep 0.1"),
command_raw: None,
measurements: Measurements::new(vec![
Measurement {
time_wall_clock: Time::new::<second>(0.1),
@@ -226,6 +230,7 @@ fn test_markup_export_manual_ms() {
let timing_results = [
BenchmarkResult {
command: String::from("sleep 2"),
command_raw: None,
measurements: Measurements::new(vec![
Measurement {
time_wall_clock: Time::new::<second>(2.1),
@@ -253,6 +258,7 @@ fn test_markup_export_manual_ms() {
},
BenchmarkResult {
command: String::from("sleep 0.1"),
command_raw: None,
measurements: Measurements::new(vec![
Measurement {
time_wall_clock: Time::new::<second>(0.1),
@@ -324,6 +330,7 @@ fn test_markup_export_manual_s() {
let results = [
BenchmarkResult {
command: String::from("sleep 2"),
command_raw: None,
measurements: Measurements::new(vec![
Measurement {
time_wall_clock: Time::new::<second>(2.01),
@@ -351,6 +358,7 @@ fn test_markup_export_manual_s() {
},
BenchmarkResult {
command: String::from("sleep 0.1"),
command_raw: None,
measurements: Measurements::new(vec![
Measurement {
time_wall_clock: Time::new::<second>(0.11),
+55
View File
@@ -42,6 +42,61 @@ fn one_run_is_supported() {
.success();
}
#[test]
fn json_includes_raw_command_only_when_different() {
for (args, expected) in [
(vec!["sleep 0.01"], vec![("sleep 0.01", None)]),
(
vec!["--command-name=example", "sleep 0.01"],
vec![("example", Some("sleep 0.01"))],
),
(
vec!["--command-name=sleep 0.01", "sleep 0.01"],
vec![("sleep 0.01", None)],
),
(
vec![
"-L",
"delay",
"0.01,0.02",
"--command-name=delay {delay}",
"sleep {delay}",
],
vec![
("delay 0.01", Some("sleep 0.01")),
("delay 0.02", Some("sleep 0.02")),
],
),
(
vec![
"-L",
"delay",
"0.01,0.02",
"--command-name=sleep {delay}",
"sleep {delay}",
],
vec![("sleep 0.01", None), ("sleep 0.02", None)],
),
] {
let output = hyperfine_debug()
.args(["--runs=1", "--style=none", "--export-json=-"])
.args(args)
.output()
.unwrap();
assert!(output.status.success());
let export: serde_json::Value = serde_json::from_slice(&output.stdout).unwrap();
let results = export["results"].as_array().unwrap();
assert_eq!(results.len(), expected.len());
for (result, (command, command_raw)) in results.iter().zip(expected) {
assert_eq!(result["command"], command);
assert_eq!(
result.get("command_raw"),
command_raw.map(serde_json::Value::from).as_ref()
);
}
}
}
#[test]
fn json_memory_availability_matches_platform() {
let output = hyperfine_raw_command()