Flat directory/module structure

This commit is contained in:
David Peter authored and David Peter committed 2021-08-24 22:44:08 +02:00
1 parent d31936ec28
commit 30c381fe2a
27 files changed
+70 -71

No files matched your search

+19
View File
@@ -0,0 +1,19 @@
use crate::units::Second;
#[derive(Debug, Copy, Clone)]
pub struct CPUTimes {
/// Total amount of time spent executing in user mode
pub user_usec: i64,
/// Total amount of time spent executing in kernel mode
pub system_usec: i64,
}
#[derive(Debug, Copy, Clone)]
pub struct CPUInterval {
/// Total amount of time spent executing in user mode
pub user: Second,
/// Total amount of time spent executing in kernel mode
pub system: Second,
}
+28
View File
@@ -0,0 +1,28 @@
mod internal;
pub mod wallclocktimer;
use cfg_if::cfg_if;
cfg_if! {
if #[cfg(windows)] {
mod windows_timer;
pub use self::windows_timer::get_cpu_timer;
} else {
mod unix_timer;
pub use self::unix_timer::get_cpu_timer;
}
}
use std::process::Child;
/// 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;
}
+96
View File
@@ -0,0 +1,96 @@
#![cfg(not(windows))]
use super::internal::{CPUInterval, CPUTimes};
use crate::timer::{TimerStart, TimerStop};
use crate::units::Second;
use std::mem;
use std::process::Child;
pub fn get_cpu_timer() -> Box<dyn TimerStop<Result = (Second, Second)>> {
Box::new(CPUTimer::start())
}
struct CPUTimer {
start_cpu: CPUTimes,
}
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);
(cpu_interval.user, cpu_interval.system)
}
}
/// Read CPU execution times ('user' and 'system')
fn get_cpu_times() -> CPUTimes {
use libc::{getrusage, rusage, RUSAGE_CHILDREN};
let result: rusage = unsafe {
let mut buf = mem::zeroed();
let success = getrusage(RUSAGE_CHILDREN, &mut buf);
assert_eq!(0, success);
buf
};
const MICROSEC_PER_SEC: i64 = 1000 * 1000;
#[allow(clippy::useless_conversion)]
CPUTimes {
user_usec: i64::from(result.ru_utime.tv_sec) * MICROSEC_PER_SEC
+ i64::from(result.ru_utime.tv_usec),
system_usec: i64::from(result.ru_stime.tv_sec) * MICROSEC_PER_SEC
+ i64::from(result.ru_stime.tv_usec),
}
}
/// Compute the time intervals in between two `CPUTimes` snapshots
fn cpu_time_interval(start: &CPUTimes, end: &CPUTimes) -> CPUInterval {
CPUInterval {
user: ((end.user_usec - start.user_usec) as f64) * 1e-6,
system: ((end.system_usec - start.system_usec) as f64) * 1e-6,
}
}
#[cfg(test)]
use approx::assert_relative_eq;
#[test]
fn test_cpu_time_interval() {
let t_a = CPUTimes {
user_usec: 12345,
system_usec: 54321,
};
let t_b = CPUTimes {
user_usec: 20000,
system_usec: 70000,
};
let t_zero = cpu_time_interval(&t_a, &t_a);
assert!(t_zero.user.abs() < f64::EPSILON);
assert!(t_zero.system.abs() < f64::EPSILON);
let t_ab = cpu_time_interval(&t_a, &t_b);
assert_relative_eq!(0.007655, t_ab.user);
assert_relative_eq!(0.015679, t_ab.system);
let t_ba = cpu_time_interval(&t_b, &t_a);
assert_relative_eq!(-0.007655, t_ba.user);
assert_relative_eq!(-0.015679, t_ba.system);
}
+30
View File
@@ -0,0 +1,30 @@
use std::process::Child;
use std::time::Instant;
use crate::timer::{TimerStart, TimerStop};
use crate::units::Second;
pub struct WallClockTimer {
start: Instant,
}
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 + f64::from(duration.subsec_nanos()) * 1e-9
}
}
+83
View File
@@ -0,0 +1,83 @@
#![cfg(windows)]
use super::internal::CPUTimes;
use crate::timer::{TimerStart, TimerStop};
use crate::units::Second;
use winapi::um::processthreadsapi::GetProcessTimes;
use winapi::um::winnt::HANDLE;
use std::mem;
use std::os::windows::io::{AsRawHandle, RawHandle};
use std::process::Child;
const HUNDRED_NS_PER_MS: i64 = 10;
pub fn get_cpu_timer(process: &Child) -> Box<dyn TimerStop<Result = (Second, Second)>> {
Box::new(CPUTimer::start_for_process(process))
}
struct CPUTimer {
handle: RawHandle,
}
impl TimerStart for CPUTimer {
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,
)
}
}
/// Read CPU execution times (dummy for now)
fn get_cpu_times(handle: RawHandle) -> CPUTimes {
let (user_usec, system_usec) = unsafe {
let mut _ctime = mem::zeroed();
let mut _etime = mem::zeroed();
let mut kernel_time = mem::zeroed();
let mut user_time = mem::zeroed();
let res = GetProcessTimes(
handle as HANDLE,
&mut _ctime,
&mut _etime,
&mut kernel_time,
&mut user_time,
);
// 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)
} else {
(0, 0)
}
};
CPUTimes {
user_usec,
system_usec,
}
}