From 6c7e102a242b3224654cd0872c7faa08ef345086 Mon Sep 17 00:00:00 2001 From: Steve Pentland Date: Wed, 7 Feb 2018 19:03:52 -0500 Subject: [PATCH] Refactor execute and measure to shell, abstract away cpu timer --- src/hyperfine/benchmark.rs | 46 ++---------------------- src/hyperfine/shell.rs | 51 +++++++++++++++++++++++++-- src/hyperfine/timer/mod.rs | 28 ++++++++++++--- src/hyperfine/timer/unix_timer.rs | 21 ++++++++--- src/hyperfine/timer/wallclocktimer.rs | 15 +++++--- src/hyperfine/timer/windows_timer.rs | 28 +++++++++------ 6 files changed, 117 insertions(+), 72 deletions(-) diff --git a/src/hyperfine/benchmark.rs b/src/hyperfine/benchmark.rs index 668336c..d6e121b 100644 --- a/src/hyperfine/benchmark.rs +++ b/src/hyperfine/benchmark.rs @@ -1,5 +1,4 @@ use std::io; -use std::process::ExitStatus; use colored::*; use statistical::{mean, standard_deviation}; @@ -9,9 +8,9 @@ use hyperfine::internal::{get_progress_bar, max, min, CmdFailureAction, Hyperfin use hyperfine::warnings::Warnings; use hyperfine::format::{format_duration, format_duration_unit}; use hyperfine::outlier_detection::{modified_zscores, OUTLIER_THRESHOLD}; -use hyperfine::timer::Timer; +use hyperfine::timer::{TimerStart, TimerStop}; use hyperfine::timer::wallclocktimer::WallClockTimer; -use hyperfine::shell::run_shell_command; +use hyperfine::shell::execute_and_time; /// Results from timing a single shell command @@ -293,44 +292,3 @@ pub fn run_benchmark( Ok(()) } - -#[derive(Debug, Copy, Clone)] -struct ExecuteResult { - user_time: f64, - system_time: f64, - status: ExitStatus, -} - -#[cfg(windows)] -fn execute_and_time(command: &str) -> io::Result { - use hyperfine::timer::windows_timer::{CPUTimer, WindowsTimer}; - use std::os::windows::io::AsRawHandle; - - let mut child = run_shell_command(command)?; - let timer = CPUTimer::start(child.as_raw_handle()); - let status = child.wait()?; - - let (user_time, system_time) = timer.stop(); - Ok(ExecuteResult { - user_time, - system_time, - status, - }) -} - -#[cfg(not(windows))] -fn execute_and_time(command: &str) -> io::Result { - use hyperfine::timer::unix_timer::CPUTimer; - - let cpu_timer = CPUTimer::start(); - - let status = run_shell_command(command)?; - - let (user_time, system_time) = cpu_timer.stop(); - - Ok(ExecuteResult { - user_time, - system_time, - status, - }) -} diff --git a/src/hyperfine/shell.rs b/src/hyperfine/shell.rs index 138df3a..ab52b4b 100644 --- a/src/hyperfine/shell.rs +++ b/src/hyperfine/shell.rs @@ -1,11 +1,56 @@ use std; use std::io; -use std::process::{Command, Stdio}; +use std::process::{Command, ExitStatus, Stdio}; +use hyperfine::timer::get_cpu_timer; + +/// Used to indicate the result of running a command +#[derive(Debug, Copy, Clone)] +pub struct ExecuteResult { + /// The amount of user time the process used + pub user_time: f64, + + /// The amount of cpu time the process used + pub system_time: f64, + + /// The exit status of the process + pub status: ExitStatus, +} + +/// Execute the given command and return a timing summary +#[cfg(windows)] +pub fn execute_and_time(command: &str) -> io::Result { + let mut child = run_shell_command(command)?; + let cpu_timer = get_cpu_timer(&child); + let status = child.wait()?; + + let (user_time, system_time) = cpu_timer.stop(); + Ok(ExecuteResult { + user_time, + system_time, + status, + }) +} + +/// Execute the given command and return a timing summary +#[cfg(not(windows))] +pub fn execute_and_time(command: &str) -> io::Result { + let cpu_timer = get_cpu_timer(); + + let status = run_shell_command(command)?; + + let (user_time, system_time) = cpu_timer.stop(); + + Ok(ExecuteResult { + user_time, + system_time, + status, + }) +} /// Run a standard shell command #[cfg(not(windows))] -pub fn run_shell_command(command: &str) -> io::Result { +fn run_shell_command(command: &str) -> io::Result { Command::new("sh") .arg("-c") .arg(command) @@ -17,7 +62,7 @@ pub fn run_shell_command(command: &str) -> io::Result /// Run a Windows shell command using cmd.exe #[cfg(windows)] -pub fn run_shell_command(command: &str) -> io::Result { +fn run_shell_command(command: &str) -> io::Result { Command::new("cmd") .arg("/C") .arg(command) diff --git a/src/hyperfine/timer/mod.rs b/src/hyperfine/timer/mod.rs index d34bead..2e99d37 100644 --- a/src/hyperfine/timer/mod.rs +++ b/src/hyperfine/timer/mod.rs @@ -3,15 +3,33 @@ mod internal; pub mod wallclocktimer; #[cfg(not(windows))] -pub mod unix_timer; +mod unix_timer; + +#[cfg(not(windows))] +pub use self::unix_timer::get_cpu_timer; #[cfg(windows)] -pub mod windows_timer; +mod windows_timer; -/// Defines a general timer with start/stop functionality. -pub trait Timer { - type Result; +#[cfg(windows)] +pub use self::windows_timer::get_cpu_timer; +use std::process::Child; + +pub trait Timer +where + Self: TimerStart + TimerStop, +{ +} + +/// Defines start functionality of a timer. +pub trait TimerStart { fn start() -> Self; + fn start_for_process(process: &Child) -> Self; +} + +/// Defines stop functionality of a timer. +pub trait TimerStop { + type Result; fn stop(&self) -> Self::Result; } diff --git a/src/hyperfine/timer/unix_timer.rs b/src/hyperfine/timer/unix_timer.rs index e36d456..6868d52 100644 --- a/src/hyperfine/timer/unix_timer.rs +++ b/src/hyperfine/timer/unix_timer.rs @@ -1,24 +1,35 @@ #![cfg(not(windows))] use super::internal::{CPUInterval, CPUTimes}; -use hyperfine::timer::Timer; +use hyperfine::timer::{TimerStart, TimerStop}; use hyperfine::internal::Second; use std::mem; +use std::process::Child; -pub struct CPUTimer { +pub fn get_cpu_timer() -> Box> { + Box::new(CPUTimer::start()) +} + +struct CPUTimer { start_cpu: CPUTimes, } -impl Timer for CPUTimer { - type Result = (Second, Second); - +impl TimerStart for CPUTimer { fn start() -> Self { CPUTimer { start_cpu: get_cpu_times(), } } + fn start_for_process(_: &Child) -> Self { + Self::start() + } +} + +impl TimerStop for CPUTimer { + type Result = (Second, Second); + fn stop(&self) -> Self::Result { let end_cpu = get_cpu_times(); let cpu_interval = cpu_time_interval(&self.start_cpu, &end_cpu); diff --git a/src/hyperfine/timer/wallclocktimer.rs b/src/hyperfine/timer/wallclocktimer.rs index 61a5a0c..e68cda1 100644 --- a/src/hyperfine/timer/wallclocktimer.rs +++ b/src/hyperfine/timer/wallclocktimer.rs @@ -1,21 +1,28 @@ +use std::process::Child; use std::time::Instant; use hyperfine::internal::Second; -use hyperfine::timer::Timer; +use hyperfine::timer::{TimerStart, TimerStop}; pub struct WallClockTimer { start: Instant, } -impl Timer for WallClockTimer { - type Result = Second; - +impl TimerStart for WallClockTimer { fn start() -> WallClockTimer { WallClockTimer { start: Instant::now(), } } + fn start_for_process(_: &Child) -> Self { + Self::start() + } +} + +impl TimerStop for WallClockTimer { + type Result = Second; + fn stop(&self) -> Second { let duration = self.start.elapsed(); duration.as_secs() as f64 + (duration.subsec_nanos() as f64) * 1e-9 diff --git a/src/hyperfine/timer/windows_timer.rs b/src/hyperfine/timer/windows_timer.rs index 2fbfa13..6ee82e1 100644 --- a/src/hyperfine/timer/windows_timer.rs +++ b/src/hyperfine/timer/windows_timer.rs @@ -2,33 +2,39 @@ use super::internal::CPUTimes; use hyperfine::internal::Second; +use hyperfine::timer::{TimerStart, TimerStop}; use winapi::um::processthreadsapi::GetProcessTimes; use winapi::um::winnt::HANDLE; use std::mem; -use std::os::windows::io::RawHandle; +use std::os::windows::io::{AsRawHandle, RawHandle}; +use std::process::Child; const HUNDRED_NS_PER_MS: i64 = 10; -pub trait WindowsTimer { - type Result; - - fn start(handle: RawHandle) -> Self; - fn stop(&self) -> Self::Result; +pub fn get_cpu_timer(process: &Child) -> Box> { + Box::new(CPUTimer::start_for_process(process)) } -pub struct CPUTimer { +struct CPUTimer { handle: RawHandle, } -impl WindowsTimer for CPUTimer { - type Result = (Second, Second); +impl TimerStart for CPUTimer { - fn start(handle: RawHandle) -> Self { - CPUTimer { handle } + fn start() -> Self { + panic!() } + fn start_for_process(process: &Child) -> Self { + CPUTimer { handle: process.as_raw_handle() } + } +} + +impl TimerStop for CPUTimer { + type Result = (Second, Second); + fn stop(&self) -> Self::Result { let times = get_cpu_times(self.handle); (times.user_usec as f64 * 1e-6, times.system_usec as f64 * 1e-6)