mirror of
https://github.com/sharkdp/hyperfine.git
synced 2026-11-01 08:50:19 +00:00
Support hardware counters (instructions, cache misses, ...) (#983)
* Add hardware counters to JSON exports * Clarify Linux hardware counter setup
This commit is contained in:
1 parent
ab86cb99cc
commit
bc3a3f0524
13 files changed
+432
-34
No files matched your search
@@ -62,6 +62,7 @@ fn run_command_and_measure_common(
|
||||
command_input_policy: &CommandInputPolicy,
|
||||
command_output_policy: &CommandOutputPolicy,
|
||||
command_name: &str,
|
||||
collect_hardware_counters: bool,
|
||||
) -> Result<Measurement> {
|
||||
let stdin = command_input_policy.get_stdin()?;
|
||||
let (stdout, stderr) = command_output_policy.get_stdout_stderr()?;
|
||||
@@ -76,7 +77,7 @@ fn run_command_and_measure_common(
|
||||
command.env("HYPERFINE_ITERATION", value);
|
||||
}
|
||||
|
||||
let measurement = execute_and_measure(command)
|
||||
let measurement = execute_and_measure(command, collect_hardware_counters)
|
||||
.with_context(|| format!("Failed to run command '{command_name}'"))?;
|
||||
|
||||
if !measurement.exit_status.success() {
|
||||
@@ -144,6 +145,7 @@ impl Executor for RawExecutor<'_> {
|
||||
&self.options.command_input_policy,
|
||||
output_policy,
|
||||
&command.get_command_line(),
|
||||
matches!(iteration, BenchmarkIteration::Benchmark(_)),
|
||||
)
|
||||
}
|
||||
|
||||
@@ -199,6 +201,7 @@ impl Executor for ShellExecutor<'_> {
|
||||
&self.options.command_input_policy,
|
||||
output_policy,
|
||||
&command.get_command_line(),
|
||||
false,
|
||||
)?;
|
||||
|
||||
// Subtract shell spawning time
|
||||
@@ -278,6 +281,7 @@ impl Executor for ShellExecutor<'_> {
|
||||
time_user: measurements.time_user_mean(),
|
||||
time_system: measurements.time_system_mean(),
|
||||
memory_peak_resident: None,
|
||||
hardware_counters: Default::default(),
|
||||
exit_status: ExitStatus::default(),
|
||||
});
|
||||
|
||||
@@ -336,6 +340,7 @@ impl Executor for MockExecutor {
|
||||
time_user: Time::zero(),
|
||||
time_system: Time::zero(),
|
||||
memory_peak_resident: Some(Information::zero()),
|
||||
hardware_counters: Default::default(),
|
||||
exit_status,
|
||||
})
|
||||
}
|
||||
|
||||
@@ -29,6 +29,47 @@ where
|
||||
}
|
||||
}
|
||||
|
||||
fn serialize_optional_count<S>(value: &Option<u64>, serializer: S) -> Result<S::Ok, S::Error>
|
||||
where
|
||||
S: serde::Serializer,
|
||||
{
|
||||
#[derive(Serialize)]
|
||||
struct Count {
|
||||
value: u64,
|
||||
}
|
||||
|
||||
value.map(|value| Count { value }).serialize(serializer)
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Default, Serialize, PartialEq)]
|
||||
pub struct HardwareCounters {
|
||||
#[serde(
|
||||
skip_serializing_if = "Option::is_none",
|
||||
serialize_with = "serialize_optional_count"
|
||||
)]
|
||||
pub cpu_cycles: Option<u64>,
|
||||
#[serde(
|
||||
skip_serializing_if = "Option::is_none",
|
||||
serialize_with = "serialize_optional_count"
|
||||
)]
|
||||
pub instructions: Option<u64>,
|
||||
#[serde(
|
||||
skip_serializing_if = "Option::is_none",
|
||||
serialize_with = "serialize_optional_count"
|
||||
)]
|
||||
pub cache_references: Option<u64>,
|
||||
#[serde(
|
||||
skip_serializing_if = "Option::is_none",
|
||||
serialize_with = "serialize_optional_count"
|
||||
)]
|
||||
pub cache_misses: Option<u64>,
|
||||
#[serde(
|
||||
skip_serializing_if = "Option::is_none",
|
||||
serialize_with = "serialize_optional_count"
|
||||
)]
|
||||
pub branch_misses: Option<u64>,
|
||||
}
|
||||
|
||||
/// Performance metric measurements and exit code for a single run
|
||||
#[derive(Debug, Clone, Default, Serialize, PartialEq)]
|
||||
pub struct Measurement {
|
||||
@@ -51,6 +92,9 @@ pub struct Measurement {
|
||||
)]
|
||||
pub memory_peak_resident: Option<Information>,
|
||||
|
||||
#[serde(flatten)]
|
||||
pub hardware_counters: HardwareCounters,
|
||||
|
||||
// The exit status of the process
|
||||
#[serde(rename = "exit_code", serialize_with = "serialize_exit_status")]
|
||||
pub exit_status: ExitStatus,
|
||||
|
||||
Reference in new issue
Block a user