mirror of
https://github.com/sharkdp/hyperfine.git
synced 2026-11-01 08:50:19 +00:00
Initial work on refactoring
This commit is contained in:
1 parent
eb92bd4674
commit
fefb3f2c16
6 files changed
+105
-92
No files matched your search
+17
-81
@@ -1,6 +1,4 @@
|
|||||||
use std::io;
|
use std::io;
|
||||||
use std::process::{Command, ExitStatus, Stdio};
|
|
||||||
use std::time::Instant;
|
|
||||||
|
|
||||||
use colored::*;
|
use colored::*;
|
||||||
use statistical::{mean, standard_deviation};
|
use statistical::{mean, standard_deviation};
|
||||||
@@ -10,9 +8,10 @@ use hyperfine::internal::{get_progress_bar, max, min, CmdFailureAction, Hyperfin
|
|||||||
use hyperfine::warnings::Warnings;
|
use hyperfine::warnings::Warnings;
|
||||||
use hyperfine::format::{format_duration, format_duration_unit};
|
use hyperfine::format::{format_duration, format_duration_unit};
|
||||||
use hyperfine::outlier_detection::{modified_zscores, OUTLIER_THRESHOLD};
|
use hyperfine::outlier_detection::{modified_zscores, OUTLIER_THRESHOLD};
|
||||||
|
use hyperfine::timer::Timer;
|
||||||
#[cfg(not(target_os = "windows"))]
|
use hyperfine::timer::wallclocktimer::WallClockTimer;
|
||||||
use hyperfine::cputime::{cpu_time_interval, get_cpu_times};
|
use hyperfine::timer::cputimer::CPUTimer;
|
||||||
|
use hyperfine::shell::run_shell_command;
|
||||||
|
|
||||||
/// Results from timing a single shell command
|
/// Results from timing a single shell command
|
||||||
#[derive(Debug, Copy, Clone)]
|
#[derive(Debug, Copy, Clone)]
|
||||||
@@ -42,13 +41,13 @@ pub fn time_shell_command(
|
|||||||
failure_action: CmdFailureAction,
|
failure_action: CmdFailureAction,
|
||||||
shell_spawning_time: Option<TimingResult>,
|
shell_spawning_time: Option<TimingResult>,
|
||||||
) -> io::Result<(TimingResult, bool)> {
|
) -> io::Result<(TimingResult, bool)> {
|
||||||
let start = Instant::now();
|
let wallclock_timer = WallClockTimer::start();
|
||||||
let timer = cpu_interval_timer();
|
let cpu_timer = CPUTimer::start();
|
||||||
|
|
||||||
let status = run_shell_command(shell_cmd)?;
|
let status = run_shell_command(shell_cmd)?;
|
||||||
|
|
||||||
let (mut time_user, mut time_system) = timer();
|
let mut time_real = wallclock_timer.stop();
|
||||||
let duration = start.elapsed();
|
let (mut time_user, mut time_system) = cpu_timer.stop();
|
||||||
|
|
||||||
if failure_action == CmdFailureAction::RaiseError && !status.success() {
|
if failure_action == CmdFailureAction::RaiseError && !status.success() {
|
||||||
return Err(io::Error::new(
|
return Err(io::Error::new(
|
||||||
@@ -58,9 +57,6 @@ pub fn time_shell_command(
|
|||||||
));
|
));
|
||||||
}
|
}
|
||||||
|
|
||||||
// Real time
|
|
||||||
let mut time_real = duration.as_secs() as f64 + (duration.subsec_nanos() as f64) * 1e-9;
|
|
||||||
|
|
||||||
// Correct for shell spawning time
|
// Correct for shell spawning time
|
||||||
if let Some(spawning_time) = shell_spawning_time {
|
if let Some(spawning_time) = shell_spawning_time {
|
||||||
time_real = subtract_shell_spawning_time(time_real, spawning_time.time_real);
|
time_real = subtract_shell_spawning_time(time_real, spawning_time.time_real);
|
||||||
@@ -116,49 +112,6 @@ pub fn mean_shell_spawning_time(style: &OutputStyleOption) -> io::Result<TimingR
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Retrieve a timer Fn that starts on the initial call and stops when the
|
|
||||||
/// returned closure is called.
|
|
||||||
#[cfg(not(target_os = "windows"))]
|
|
||||||
fn cpu_interval_timer() -> Box<Fn() -> (f64, f64)> {
|
|
||||||
let start_cpu = get_cpu_times();
|
|
||||||
let timer = move || {
|
|
||||||
let end_cpu = get_cpu_times();
|
|
||||||
let cpu_interval = cpu_time_interval(&start_cpu, &end_cpu);
|
|
||||||
(cpu_interval.user, cpu_interval.system)
|
|
||||||
};
|
|
||||||
|
|
||||||
Box::new(timer)
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Return a timer Fn that will always return (0,0) when called
|
|
||||||
#[cfg(target_os = "windows")]
|
|
||||||
fn cpu_interval_timer() -> Box<Fn() -> (f64, f64)> {
|
|
||||||
Box::new(|| (0f64, 0f64))
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Run a standard sh command
|
|
||||||
#[cfg(not(target_os = "windows"))]
|
|
||||||
fn run_shell_command(command: &str) -> io::Result<ExitStatus> {
|
|
||||||
Command::new("sh")
|
|
||||||
.arg("-c")
|
|
||||||
.arg(command)
|
|
||||||
.stdin(Stdio::null())
|
|
||||||
.stdout(Stdio::null())
|
|
||||||
.stderr(Stdio::null())
|
|
||||||
.status()
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Run a Windows command using cmd
|
|
||||||
#[cfg(target_os = "windows")]
|
|
||||||
fn run_shell_command(command: &str) -> io::Result<ExitStatus> {
|
|
||||||
Command::new("cmd")
|
|
||||||
.arg(command)
|
|
||||||
.stdin(Stdio::null())
|
|
||||||
.stdout(Stdio::null())
|
|
||||||
.stderr(Stdio::null())
|
|
||||||
.status()
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Run the command specified by `--prepare`.
|
/// Run the command specified by `--prepare`.
|
||||||
fn run_preparation_command(command: &Option<String>) -> io::Result<()> {
|
fn run_preparation_command(command: &Option<String>) -> io::Result<()> {
|
||||||
if let &Some(ref preparation_command) = command {
|
if let &Some(ref preparation_command) = command {
|
||||||
@@ -286,8 +239,15 @@ pub fn run_benchmark(
|
|||||||
let (user_str, user_unit) = format_duration_unit(user_mean, None);
|
let (user_str, user_unit) = format_duration_unit(user_mean, None);
|
||||||
let system_str = format_duration(system_mean, Some(user_unit));
|
let system_str = format_duration(system_mean, Some(user_unit));
|
||||||
|
|
||||||
output_times(mean_str, stddev_str, user_str, system_str);
|
println!(
|
||||||
|
" Time ({} ± {}): {:>8} ± {:>8} [User: {}, System: {}]",
|
||||||
|
"mean".green().bold(),
|
||||||
|
"σ".green(),
|
||||||
|
mean_str.green().bold(),
|
||||||
|
stddev_str.green(),
|
||||||
|
user_str.blue(),
|
||||||
|
system_str.blue()
|
||||||
|
);
|
||||||
println!(" ");
|
println!(" ");
|
||||||
|
|
||||||
println!(
|
println!(
|
||||||
@@ -331,27 +291,3 @@ pub fn run_benchmark(
|
|||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(not(target_os = "windows"))]
|
|
||||||
fn output_times(mean_str: String, stddev_str: String, user_str: String, system_str: String) {
|
|
||||||
println!(
|
|
||||||
" Time ({} ± {}): {:>8} ± {:>8} [User: {}, System: {}]",
|
|
||||||
"mean".green().bold(),
|
|
||||||
"σ".green(),
|
|
||||||
mean_str.green().bold(),
|
|
||||||
stddev_str.green(),
|
|
||||||
user_str.blue(),
|
|
||||||
system_str.blue()
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(target_os = "windows")]
|
|
||||||
fn output_times(mean_str: String, stddev_str: String, _user_str: String, _system_str: String) {
|
|
||||||
println!(
|
|
||||||
" Time ({} ± {}): {:>8} ± {:>8}",
|
|
||||||
"mean".green().bold(),
|
|
||||||
"σ".green(),
|
|
||||||
mean_str.green().bold(),
|
|
||||||
stddev_str.green(),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
@@ -3,6 +3,5 @@ pub mod format;
|
|||||||
pub mod internal;
|
pub mod internal;
|
||||||
pub mod outlier_detection;
|
pub mod outlier_detection;
|
||||||
pub mod warnings;
|
pub mod warnings;
|
||||||
|
pub mod timer;
|
||||||
#[cfg(not(target_os = "windows"))]
|
pub mod shell;
|
||||||
pub mod cputime;
|
|
||||||
@@ -0,0 +1,25 @@
|
|||||||
|
use std::io;
|
||||||
|
use std::process::{Command, ExitStatus, Stdio};
|
||||||
|
|
||||||
|
/// Run a standard shell command
|
||||||
|
#[cfg(not(target_os = "windows"))]
|
||||||
|
pub fn run_shell_command(command: &str) -> io::Result<ExitStatus> {
|
||||||
|
Command::new("sh")
|
||||||
|
.arg("-c")
|
||||||
|
.arg(command)
|
||||||
|
.stdin(Stdio::null())
|
||||||
|
.stdout(Stdio::null())
|
||||||
|
.stderr(Stdio::null())
|
||||||
|
.status()
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Run a Windows shell command using cmd.exe
|
||||||
|
#[cfg(target_os = "windows")]
|
||||||
|
pub fn run_shell_command(command: &str) -> io::Result<ExitStatus> {
|
||||||
|
Command::new("cmd")
|
||||||
|
.arg(command)
|
||||||
|
.stdin(Stdio::null())
|
||||||
|
.stdout(Stdio::null())
|
||||||
|
.stderr(Stdio::null())
|
||||||
|
.status()
|
||||||
|
}
|
||||||
@@ -1,13 +1,10 @@
|
|||||||
#![cfg(not(target_os = "windows"))]
|
|
||||||
|
|
||||||
use libc::{getrusage, rusage, RUSAGE_CHILDREN};
|
|
||||||
|
|
||||||
use std::mem;
|
use std::mem;
|
||||||
|
|
||||||
use hyperfine::internal::Second;
|
use hyperfine::internal::Second;
|
||||||
|
use hyperfine::timer::Timer;
|
||||||
|
|
||||||
#[derive(Debug, Copy, Clone)]
|
#[derive(Debug, Copy, Clone)]
|
||||||
pub struct CPUTimes {
|
struct CPUTimes {
|
||||||
/// Total amount of time spent executing in user mode
|
/// Total amount of time spent executing in user mode
|
||||||
user_usec: i64,
|
user_usec: i64,
|
||||||
|
|
||||||
@@ -16,7 +13,7 @@ pub struct CPUTimes {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Copy, Clone)]
|
#[derive(Debug, Copy, Clone)]
|
||||||
pub struct CPUInterval {
|
struct CPUInterval {
|
||||||
/// Total amount of time spent executing in user mode
|
/// Total amount of time spent executing in user mode
|
||||||
pub user: Second,
|
pub user: Second,
|
||||||
|
|
||||||
@@ -25,7 +22,9 @@ pub struct CPUInterval {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Read CPU execution times ('user' and 'system')
|
/// Read CPU execution times ('user' and 'system')
|
||||||
pub fn get_cpu_times() -> CPUTimes {
|
fn get_cpu_times() -> CPUTimes {
|
||||||
|
use libc::{getrusage, rusage, RUSAGE_CHILDREN};
|
||||||
|
|
||||||
let result: rusage = unsafe {
|
let result: rusage = unsafe {
|
||||||
let mut buf = mem::zeroed();
|
let mut buf = mem::zeroed();
|
||||||
let success = getrusage(RUSAGE_CHILDREN, &mut buf);
|
let success = getrusage(RUSAGE_CHILDREN, &mut buf);
|
||||||
@@ -44,13 +43,34 @@ pub fn get_cpu_times() -> CPUTimes {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Compute the time intervals in between two `CPUTimes` snapshots
|
/// Compute the time intervals in between two `CPUTimes` snapshots
|
||||||
pub fn cpu_time_interval(start: &CPUTimes, end: &CPUTimes) -> CPUInterval {
|
fn cpu_time_interval(start: &CPUTimes, end: &CPUTimes) -> CPUInterval {
|
||||||
CPUInterval {
|
CPUInterval {
|
||||||
user: ((end.user_usec - start.user_usec) as f64) * 1e-6,
|
user: ((end.user_usec - start.user_usec) as f64) * 1e-6,
|
||||||
system: ((end.system_usec - start.system_usec) as f64) * 1e-6,
|
system: ((end.system_usec - start.system_usec) as f64) * 1e-6,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// A timer that measures system and user time
|
||||||
|
pub struct CPUTimer {
|
||||||
|
start_cpu: CPUTimes,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Timer for CPUTimer {
|
||||||
|
type Result = (Second, Second);
|
||||||
|
|
||||||
|
fn start() -> Self {
|
||||||
|
CPUTimer {
|
||||||
|
start_cpu: get_cpu_times(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn stop(&self) -> Self::Result {
|
||||||
|
let end_cpu = get_cpu_times();
|
||||||
|
let cpu_interval = cpu_time_interval(&self.start_cpu, &end_cpu);
|
||||||
|
(cpu_interval.user, cpu_interval.system)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_cpu_time_interval() {
|
fn test_cpu_time_interval() {
|
||||||
let t_a = CPUTimes {
|
let t_a = CPUTimes {
|
||||||
@@ -0,0 +1,10 @@
|
|||||||
|
pub mod wallclocktimer;
|
||||||
|
pub mod cputimer;
|
||||||
|
|
||||||
|
/// Defines a general timer with start/stop functionality.
|
||||||
|
pub trait Timer {
|
||||||
|
type Result;
|
||||||
|
|
||||||
|
fn start() -> Self;
|
||||||
|
fn stop(&self) -> Self::Result;
|
||||||
|
}
|
||||||
@@ -0,0 +1,23 @@
|
|||||||
|
use std::time::Instant;
|
||||||
|
|
||||||
|
use hyperfine::internal::Second;
|
||||||
|
use hyperfine::timer::Timer;
|
||||||
|
|
||||||
|
pub struct WallClockTimer {
|
||||||
|
start: Instant,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Timer for WallClockTimer {
|
||||||
|
type Result = Second;
|
||||||
|
|
||||||
|
fn start() -> WallClockTimer {
|
||||||
|
WallClockTimer {
|
||||||
|
start: Instant::now(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn stop(&self) -> Second {
|
||||||
|
let duration = self.start.elapsed();
|
||||||
|
duration.as_secs() as f64 + (duration.subsec_nanos() as f64) * 1e-9
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in new issue
Block a user