Files
hyperfine/src/timer/unix_timer.rs
T

80 lines
2.2 KiB
Rust
Raw Normal View History

2018-02-05 18:22:59 -05:00
#![cfg(not(windows))]
2026-10-05 14:14:25 +02:00
use std::convert::TryFrom;
use std::io;
use std::mem::MaybeUninit;
use std::os::unix::process::ExitStatusExt;
use std::process::{Child, ExitStatus};
2021-08-24 21:33:48 +02:00
use anyhow::Result;
2026-10-05 14:14:25 +02:00
use crate::util::units::Second;
2018-02-05 18:22:59 -05:00
2022-02-22 11:34:30 +01:00
#[derive(Debug, Copy, Clone)]
struct ResourceUsage {
2022-02-22 11:34:30 +01:00
/// Total amount of time spent executing in user mode
2026-10-05 14:14:25 +02:00
pub user_usec: Second,
2022-02-22 11:34:30 +01:00
/// Total amount of time spent executing in kernel mode
2026-10-05 14:14:25 +02:00
pub system_usec: Second,
/// Maximum amount of memory used by the process, in bytes
2026-10-05 14:14:25 +02:00
pub memory_usage_byte: i64,
2022-02-22 11:34:30 +01:00
}
#[allow(clippy::useless_conversion)]
2026-10-05 14:14:25 +02:00
fn timeval_to_seconds(tv: libc::timeval) -> Second {
const MICROSEC_PER_SEC: i64 = 1000 * 1000;
(i64::from(tv.tv_sec) * MICROSEC_PER_SEC + i64::from(tv.tv_usec)) as f64 * 1e-6
2018-02-05 18:22:59 -05:00
}
#[allow(clippy::useless_conversion)]
fn wait4(mut child: Child) -> io::Result<(ExitStatus, ResourceUsage)> {
drop(child.stdin.take());
let pid = child.id() as i32;
let mut status = 0;
let mut rusage = MaybeUninit::zeroed();
2026-10-05 14:14:25 +02:00
let result = unsafe { libc::wait4(pid, &mut status, 0, rusage.as_mut_ptr()) };
2018-02-05 18:22:59 -05:00
2026-10-05 14:14:25 +02:00
if result < 0 {
Err(io::Error::last_os_error())
2024-06-23 13:29:05 +02:00
} else {
2026-10-05 14:14:25 +02:00
let rusage = unsafe { rusage.assume_init() };
2024-06-23 13:29:05 +02:00
2026-10-05 14:14:25 +02:00
let memory_usage_byte = if cfg!(target_os = "macos") || cfg!(target_os = "ios") {
// Linux and *BSD return the value in KibiBytes, Darwin flavors in bytes
rusage.ru_maxrss
} else {
rusage.ru_maxrss * 1024
};
Ok((
ExitStatus::from_raw(status),
ResourceUsage {
user_usec: timeval_to_seconds(rusage.ru_utime),
system_usec: timeval_to_seconds(rusage.ru_stime),
memory_usage_byte: memory_usage_byte.into(),
},
))
}
}
pub struct CPUTimer {}
impl CPUTimer {
pub fn start() -> Self {
Self {}
}
2026-10-05 14:14:25 +02:00
pub fn stop(&self, child: Child) -> Result<(ExitStatus, Second, Second, u64)> {
let (status, usage) = wait4(child)?;
Ok((
status,
2026-10-05 14:14:25 +02:00
usage.user_usec,
usage.system_usec,
u64::try_from(usage.memory_usage_byte).unwrap_or(0),
))
2018-02-05 18:22:59 -05:00
}
}