mirror of
https://github.com/sharkdp/hyperfine.git
synced 2026-10-28 08:08:58 +00:00
Initial working version with child proc HANDLE.
Still very ugly, and more work needs to be done to make it all pretty again. Additionally, cleaned up all the cfg attrs to shor version
This commit is contained in:
1 parent
79c375af0f
commit
9753eed85b
5 files changed
+72
-23
No files matched your search
+3
-3
@@ -15,11 +15,11 @@ indicatif = "0.9"
|
||||
statistical = "0.1"
|
||||
atty = "0.2.2"
|
||||
|
||||
[target.'cfg(not(target_os = "windows"))'.dependencies]
|
||||
[target.'cfg(not(windows))'.dependencies]
|
||||
libc = "0.2"
|
||||
|
||||
[target.'cfg(target_os = "windows")'.dependencies]
|
||||
winapi = { version = "0.3.4", features = [ "processthreadsapi", "minwindef"] }
|
||||
[target.'cfg(windows)'.dependencies]
|
||||
winapi = { version = "0.3.4", features = ["processthreadsapi", "minwindef", "winnt"] }
|
||||
|
||||
[dependencies.clap]
|
||||
version = "2"
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
use std::io;
|
||||
use std::process::ExitStatus;
|
||||
|
||||
use colored::*;
|
||||
use statistical::{mean, standard_deviation};
|
||||
@@ -10,9 +11,10 @@ use hyperfine::format::{format_duration, format_duration_unit};
|
||||
use hyperfine::outlier_detection::{modified_zscores, OUTLIER_THRESHOLD};
|
||||
use hyperfine::timer::Timer;
|
||||
use hyperfine::timer::wallclocktimer::WallClockTimer;
|
||||
use hyperfine::timer::cputimer::CPUTimer;
|
||||
use hyperfine::timer::cputimer::get_process_times;
|
||||
use hyperfine::shell::run_shell_command;
|
||||
|
||||
|
||||
/// Results from timing a single shell command
|
||||
#[derive(Debug, Copy, Clone)]
|
||||
pub struct TimingResult {
|
||||
@@ -42,12 +44,13 @@ pub fn time_shell_command(
|
||||
shell_spawning_time: Option<TimingResult>,
|
||||
) -> io::Result<(TimingResult, bool)> {
|
||||
let wallclock_timer = WallClockTimer::start();
|
||||
let cpu_timer = CPUTimer::start();
|
||||
// let cpu_timer = CPUTimer::start();
|
||||
|
||||
let status = run_shell_command(shell_cmd)?;
|
||||
let (mut time_user, mut time_system, status) = execute_and_time(shell_cmd)?;
|
||||
// let status = run_shell_command(shell_cmd)?;
|
||||
|
||||
let mut time_real = wallclock_timer.stop();
|
||||
let (mut time_user, mut time_system) = cpu_timer.stop();
|
||||
// let (mut time_user, mut time_system) = cpu_timer.stop();
|
||||
|
||||
if failure_action == CmdFailureAction::RaiseError && !status.success() {
|
||||
return Err(io::Error::new(
|
||||
@@ -291,3 +294,34 @@ pub fn run_benchmark(
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[cfg(windows)]
|
||||
fn execute_and_time(command: &str) -> io::Result<(f64, f64, ExitStatus)> {
|
||||
use std::os::windows::io::AsRawHandle;
|
||||
|
||||
let mut child = run_shell_command(command)?;
|
||||
|
||||
let result = child.wait()?;
|
||||
let handle = child.as_raw_handle();
|
||||
|
||||
let (user_usec, system_usec) = get_process_times(handle);
|
||||
|
||||
// Temp, bypassing timer and the stop method
|
||||
let user = user_usec as f64 * 1e-6;
|
||||
let system = system_usec as f64 * 1e-6;
|
||||
|
||||
Ok((user, system, result))
|
||||
}
|
||||
|
||||
#[cfg(not(windows))]
|
||||
fn execute_and_time(command: &str) -> io::Result<(f64, f64, ExitStatus)> {
|
||||
use hyperfine::timer::cputimer::CPUTimer;
|
||||
|
||||
let cpu_timer = CPUTimer::start();
|
||||
|
||||
let status = run_shell_command(command)?;
|
||||
|
||||
let (mut time_user, mut time_system) = cpu_timer.stop();
|
||||
|
||||
Ok((time_user, time_system, status))
|
||||
}
|
||||
+11
-5
@@ -1,8 +1,14 @@
|
||||
use std::io;
|
||||
use std::process::{Command, ExitStatus, Stdio};
|
||||
use std::process::{Command, Stdio};
|
||||
|
||||
#[cfg(not(windows))]
|
||||
use std::process::ExitStatus;
|
||||
|
||||
#[cfg(windows)]
|
||||
use std::process::Child;
|
||||
|
||||
/// Run a standard shell command
|
||||
#[cfg(not(target_os = "windows"))]
|
||||
#[cfg(not(windows))]
|
||||
pub fn run_shell_command(command: &str) -> io::Result<ExitStatus> {
|
||||
Command::new("sh")
|
||||
.arg("-c")
|
||||
@@ -14,13 +20,13 @@ pub fn run_shell_command(command: &str) -> io::Result<ExitStatus> {
|
||||
}
|
||||
|
||||
/// Run a Windows shell command using cmd.exe
|
||||
#[cfg(target_os = "windows")]
|
||||
pub fn run_shell_command(command: &str) -> io::Result<ExitStatus> {
|
||||
#[cfg(windows)]
|
||||
pub fn run_shell_command(command: &str) -> io::Result<Child> {
|
||||
Command::new("cmd")
|
||||
.arg("/C")
|
||||
.arg(command)
|
||||
.stdin(Stdio::null())
|
||||
.stdout(Stdio::null())
|
||||
.stderr(Stdio::null())
|
||||
.status()
|
||||
.spawn()
|
||||
}
|
||||
@@ -1,6 +1,9 @@
|
||||
use hyperfine::internal::Second;
|
||||
use hyperfine::timer::Timer;
|
||||
|
||||
#[cfg(windows)]
|
||||
use std::os::windows::io::RawHandle;
|
||||
|
||||
#[derive(Debug, Copy, Clone)]
|
||||
struct CPUTimes {
|
||||
/// Total amount of time spent executing in user mode
|
||||
@@ -20,7 +23,7 @@ struct CPUInterval {
|
||||
}
|
||||
|
||||
/// Read CPU execution times ('user' and 'system')
|
||||
#[cfg(not(target_os = "windows"))]
|
||||
#[cfg(not(windows))]
|
||||
fn get_cpu_times() -> CPUTimes {
|
||||
use libc::{getrusage, rusage, RUSAGE_CHILDREN};
|
||||
use std::mem;
|
||||
@@ -45,8 +48,17 @@ fn get_cpu_times() -> CPUTimes {
|
||||
/// Read CPU execution times (dummy for now)
|
||||
#[cfg(windows)]
|
||||
fn get_cpu_times() -> CPUTimes {
|
||||
use winapi::um::processthreadsapi::{GetCurrentProcess, GetProcessTimes};
|
||||
CPUTimes {
|
||||
user_usec : 0,
|
||||
system_usec: 0,
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(windows)]
|
||||
pub fn get_process_times(handle: RawHandle) -> (i64, i64) {
|
||||
use winapi::um::processthreadsapi::GetProcessTimes;
|
||||
use winapi::shared::minwindef::FILETIME;
|
||||
use winapi::um::winnt::HANDLE;
|
||||
|
||||
// Winapi reports times as per 100 nanosecond
|
||||
const HUNDRED_NS_PER_MS: i64 = 10;
|
||||
@@ -69,9 +81,8 @@ fn get_cpu_times() -> CPUTimes {
|
||||
};
|
||||
|
||||
let (user_usec, system_usec) = unsafe {
|
||||
let handle = GetCurrentProcess();
|
||||
let res = GetProcessTimes(
|
||||
handle,
|
||||
handle as HANDLE,
|
||||
&mut _ctime,
|
||||
&mut _etime,
|
||||
&mut kernel_time,
|
||||
@@ -81,6 +92,7 @@ fn get_cpu_times() -> CPUTimes {
|
||||
// GetProcessTimes will exit with non-zero if success as per: https://msdn.microsoft.com/en-us/library/windows/desktop/ms683223(v=vs.85).aspx
|
||||
if res != 0 {
|
||||
// Extract times as laid out here: https://support.microsoft.com/en-us/help/188768/info-working-with-the-filetime-structure
|
||||
// Both user_time and kernel_time are spans that the proces spent in either.
|
||||
let user: i64 = (((user_time.dwHighDateTime as i64) << 32) + user_time.dwLowDateTime as i64) / HUNDRED_NS_PER_MS;
|
||||
let kernel: i64 = (((kernel_time.dwHighDateTime as i64) << 32) + kernel_time.dwLowDateTime as i64) / HUNDRED_NS_PER_MS;
|
||||
(user, kernel)
|
||||
@@ -89,10 +101,7 @@ fn get_cpu_times() -> CPUTimes {
|
||||
}
|
||||
};
|
||||
|
||||
CPUTimes {
|
||||
user_usec,
|
||||
system_usec,
|
||||
}
|
||||
(user_usec,system_usec)
|
||||
}
|
||||
|
||||
/// Compute the time intervals in between two `CPUTimes` snapshots
|
||||
|
||||
+3
-3
@@ -5,10 +5,10 @@ extern crate colored;
|
||||
extern crate indicatif;
|
||||
extern crate statistical;
|
||||
|
||||
#[cfg(not(target_os = "windows"))]
|
||||
#[cfg(not(windows))]
|
||||
extern crate libc;
|
||||
|
||||
#[cfg(target_os = "windows")]
|
||||
#[cfg(windows)]
|
||||
extern crate winapi;
|
||||
|
||||
#[cfg(test)]
|
||||
@@ -149,7 +149,7 @@ fn main() {
|
||||
OutputStyleOption::Basic
|
||||
},
|
||||
};
|
||||
|
||||
|
||||
if options.output_style == OutputStyleOption::Basic {
|
||||
colored::control::set_override(false);
|
||||
}
|
||||
|
||||
Reference in new issue
Block a user