From 6cb9566118c274d8511f0df5acf0035acce731fc Mon Sep 17 00:00:00 2001 From: David Peter Date: Mon, 5 Oct 2026 09:47:09 +0200 Subject: [PATCH] Unify timer and executor measurement results --- src/benchmark/executor.rs | 59 +++++++------------ .../{timing_result.rs => measurement.rs} | 9 ++- src/benchmark/mod.rs | 27 ++++----- src/timer/mod.rs | 19 ++---- 4 files changed, 44 insertions(+), 70 deletions(-) rename src/benchmark/{timing_result.rs => measurement.rs} (62%) diff --git a/src/benchmark/executor.rs b/src/benchmark/executor.rs index 915b735..b2d7974 100644 --- a/src/benchmark/executor.rs +++ b/src/benchmark/executor.rs @@ -7,11 +7,11 @@ use crate::options::{ CmdFailureAction, CommandInputPolicy, CommandOutputPolicy, Options, OutputStyleOption, Shell, }; use crate::output::progress_bar::get_progress_bar; -use crate::timer::{execute_and_measure, TimerResult}; +use crate::timer::execute_and_measure; use crate::util::randomized_environment_offset; use crate::util::units::Second; -use super::timing_result::TimingResult; +use super::measurement::Measurement; use anyhow::{bail, Context, Result}; use statistical::mean; @@ -40,7 +40,7 @@ pub trait Executor { iteration: BenchmarkIteration, command_failure_action: Option, output_policy: &CommandOutputPolicy, - ) -> Result<(TimingResult, ExitStatus)>; + ) -> Result; /// Perform a calibration of this executor. For example, /// when running commands through a shell, we need to @@ -62,7 +62,7 @@ fn run_command_and_measure_common( command_input_policy: &CommandInputPolicy, command_output_policy: &CommandOutputPolicy, command_name: &str, -) -> Result { +) -> Result { let stdin = command_input_policy.get_stdin()?; let (stdout, stderr) = command_output_policy.get_stdout_stderr()?; command.stdin(stdin).stdout(stdout).stderr(stderr); @@ -136,25 +136,15 @@ impl Executor for RawExecutor<'_> { iteration: BenchmarkIteration, command_failure_action: Option, output_policy: &CommandOutputPolicy, - ) -> Result<(TimingResult, ExitStatus)> { - let result = run_command_and_measure_common( + ) -> Result { + run_command_and_measure_common( command.get_command()?, iteration, command_failure_action.unwrap_or_else(|| self.options.command_failure_action.clone()), &self.options.command_input_policy, output_policy, &command.get_command_line(), - )?; - - Ok(( - TimingResult { - time_real: result.time_real, - time_user: result.time_user, - time_system: result.time_system, - memory_usage_byte: result.memory_usage_byte, - }, - result.status, - )) + ) } fn calibrate(&mut self) -> Result<()> { @@ -169,7 +159,7 @@ impl Executor for RawExecutor<'_> { pub struct ShellExecutor<'a> { options: &'a Options, shell: &'a Shell, - shell_spawning_time: Option, + shell_spawning_time: Option, } impl<'a> ShellExecutor<'a> { @@ -189,7 +179,7 @@ impl Executor for ShellExecutor<'_> { iteration: BenchmarkIteration, command_failure_action: Option, output_policy: &CommandOutputPolicy, - ) -> Result<(TimingResult, ExitStatus)> { + ) -> Result { let on_windows_cmd = cfg!(windows) && *self.shell == Shell::Default("cmd.exe"); let mut command_builder = self.shell.command(); command_builder.arg(if on_windows_cmd { "/C" } else { "-c" }); @@ -218,15 +208,7 @@ impl Executor for ShellExecutor<'_> { result.time_system = (result.time_system - spawning_time.time_system).max(0.0); } - Ok(( - TimingResult { - time_real: result.time_real, - time_user: result.time_user, - time_system: result.time_system, - memory_usage_byte: result.memory_usage_byte, - }, - result.status, - )) + Ok(result) } /// Measure the average shell spawning time @@ -268,7 +250,7 @@ impl Executor for ShellExecutor<'_> { shell_cmd ); } - Ok((r, _)) => { + Ok(r) => { times_real.push(r.time_real); times_user.push(r.time_user); times_system.push(r.time_system); @@ -284,11 +266,12 @@ impl Executor for ShellExecutor<'_> { bar.finish_and_clear() } - self.shell_spawning_time = Some(TimingResult { + self.shell_spawning_time = Some(Measurement { time_real: mean(×_real), time_user: mean(×_user), time_system: mean(×_system), memory_usage_byte: 0, + status: ExitStatus::default(), }); Ok(()) @@ -326,7 +309,7 @@ impl Executor for MockExecutor { _iteration: BenchmarkIteration, _command_failure_action: Option, _output_policy: &CommandOutputPolicy, - ) -> Result<(TimingResult, ExitStatus)> { + ) -> Result { #[cfg(unix)] let status = { use std::os::unix::process::ExitStatusExt; @@ -339,15 +322,13 @@ impl Executor for MockExecutor { ExitStatus::from_raw(0) }; - Ok(( - TimingResult { - time_real: Self::extract_time(command.get_command_line()), - time_user: 0.0, - time_system: 0.0, - memory_usage_byte: 0, - }, + Ok(Measurement { + time_real: Self::extract_time(command.get_command_line()), + time_user: 0.0, + time_system: 0.0, + memory_usage_byte: 0, status, - )) + }) } fn calibrate(&mut self) -> Result<()> { diff --git a/src/benchmark/timing_result.rs b/src/benchmark/measurement.rs similarity index 62% rename from src/benchmark/timing_result.rs rename to src/benchmark/measurement.rs index f7aac92..d724146 100644 --- a/src/benchmark/timing_result.rs +++ b/src/benchmark/measurement.rs @@ -1,8 +1,10 @@ +use std::process::ExitStatus; + use crate::util::units::Second; -/// Results from timing a single command +/// Performance measurements and exit status from running a single command #[derive(Debug, Default, Copy, Clone)] -pub struct TimingResult { +pub struct Measurement { /// Wall clock time pub time_real: Second, @@ -14,4 +16,7 @@ pub struct TimingResult { /// Maximum amount of memory used, in bytes pub memory_usage_byte: u64, + + /// The exit status of the process + pub status: ExitStatus, } diff --git a/src/benchmark/mod.rs b/src/benchmark/mod.rs index b6c615d..0bf0673 100644 --- a/src/benchmark/mod.rs +++ b/src/benchmark/mod.rs @@ -1,8 +1,8 @@ pub mod benchmark_result; pub mod executor; +pub mod measurement; pub mod relative_speed; pub mod scheduler; -pub mod timing_result; use std::cmp; use std::io::{self, Write}; @@ -22,7 +22,7 @@ use crate::util::exit_code::extract_exit_code; use crate::util::min_max::{max, min}; use crate::util::units::Second; use benchmark_result::BenchmarkResult; -use timing_result::TimingResult; +use measurement::Measurement; use anyhow::{anyhow, Result}; use colored::*; @@ -61,7 +61,7 @@ impl<'a> Benchmark<'a> { command: &Command<'_>, error_output: &'static str, output_policy: &CommandOutputPolicy, - ) -> Result { + ) -> Result { self.executor .run_command_and_measure( command, @@ -69,7 +69,6 @@ impl<'a> Benchmark<'a> { Some(CmdFailureAction::RaiseError), output_policy, ) - .map(|r| r.0) .map_err(|_| anyhow!(error_output)) } @@ -78,7 +77,7 @@ impl<'a> Benchmark<'a> { &self, parameters: impl IntoIterator>, output_policy: &CommandOutputPolicy, - ) -> Result { + ) -> Result { let command = self .options .setup_command @@ -99,7 +98,7 @@ impl<'a> Benchmark<'a> { &self, parameters: impl IntoIterator>, output_policy: &CommandOutputPolicy, - ) -> Result { + ) -> Result { let command = self .options .cleanup_command @@ -120,7 +119,7 @@ impl<'a> Benchmark<'a> { &self, command: &Command<'_>, output_policy: &CommandOutputPolicy, - ) -> Result { + ) -> Result { let error_output = "The preparation command terminated with a non-zero exit code. \ Append ' || true' to the command if you are sure that this can be ignored."; @@ -132,7 +131,7 @@ impl<'a> Benchmark<'a> { &self, command: &Command<'_>, output_policy: &CommandOutputPolicy, - ) -> Result { + ) -> Result { let error_output = "The conclusion command terminated with a non-zero exit code. \ Append ' || true' to the command if you are sure that this can be ignored."; @@ -247,13 +246,13 @@ impl<'a> Benchmark<'a> { preparation_result.map_or(0.0, |res| res.time_real + self.executor.time_overhead()); // Initial timing run - let (res, status) = self.executor.run_command_and_measure( + let res = self.executor.run_command_and_measure( self.command, BenchmarkIteration::Benchmark(0), None, output_policy, )?; - let success = status.success(); + let success = res.status.success(); let conclusion_result = run_conclusion_command()?; let conclusion_overhead = @@ -284,7 +283,7 @@ impl<'a> Benchmark<'a> { times_user.push(res.time_user); times_system.push(res.time_system); memory_usage_byte.push(res.memory_usage_byte); - exit_codes.push(extract_exit_code(status)); + exit_codes.push(extract_exit_code(res.status)); all_succeeded = all_succeeded && success; @@ -309,19 +308,19 @@ impl<'a> Benchmark<'a> { bar.set_message(msg.to_owned()) } - let (res, status) = self.executor.run_command_and_measure( + let res = self.executor.run_command_and_measure( self.command, BenchmarkIteration::Benchmark(i + 1), None, output_policy, )?; - let success = status.success(); + let success = res.status.success(); times_real.push(res.time_real); times_user.push(res.time_user); times_system.push(res.time_system); memory_usage_byte.push(res.memory_usage_byte); - exit_codes.push(extract_exit_code(status)); + exit_codes.push(extract_exit_code(res.status)); all_succeeded = all_succeeded && success; diff --git a/src/timer/mod.rs b/src/timer/mod.rs index b2cd265..35fa7fc 100644 --- a/src/timer/mod.rs +++ b/src/timer/mod.rs @@ -16,11 +16,11 @@ use std::os::fd::AsFd; #[cfg(target_os = "windows")] use windows_sys::Win32::System::Threading::CREATE_SUSPENDED; -use crate::util::units::Second; +use crate::benchmark::measurement::Measurement; use wall_clock_timer::WallClockTimer; use std::io::Read; -use std::process::{ChildStdout, Command, ExitStatus}; +use std::process::{ChildStdout, Command}; use anyhow::Result; @@ -37,17 +37,6 @@ struct CPUTimes { pub memory_usage_byte: u64, } -/// Used to indicate the result of running a command -#[derive(Debug, Copy, Clone)] -pub struct TimerResult { - pub time_real: Second, - pub time_user: Second, - pub time_system: Second, - pub memory_usage_byte: u64, - /// The exit status of the process - pub status: ExitStatus, -} - /// Discard the output of a child process. fn discard(output: ChildStdout) { const CHUNK_SIZE: usize = 64 << 10; @@ -80,7 +69,7 @@ fn discard(output: ChildStdout) { } /// Execute the given command and return a timing summary -pub fn execute_and_measure(mut command: Command) -> Result { +pub fn execute_and_measure(mut command: Command) -> Result { #[cfg(not(windows))] let cpu_timer = self::unix_timer::CPUTimer::start(); @@ -111,7 +100,7 @@ pub fn execute_and_measure(mut command: Command) -> Result { let time_real = wallclock_timer.stop(); let (time_user, time_system, memory_usage_byte) = cpu_timer.stop(); - Ok(TimerResult { + Ok(Measurement { time_real, time_user, time_system,