1use std::io::Result;
26use std::process::{Command, ExitStatus};
27use std::time::{Duration, Instant};
28
29#[derive(Clone, Copy, PartialEq, Debug)]
30pub struct Timings {
31 pub wall_time: Duration,
32 pub user_time: f64,
33 pub sys_time: f64,
34}
35
36pub fn time_cmd(cmd: Command) -> Result<(Timings, ExitStatus)> {
43 #[cfg(unix)]
44 let ret = time_cmd_posix(cmd)?;
45 #[cfg(not(unix))]
46 let ret = time_cmd_fallback(cmd)?;
47 Ok(ret)
48}
49
50#[cfg(not(unix))]
51fn time_cmd_fallback(mut cmd: Command) -> Result<(Timings, ExitStatus)> {
52 let ts = Instant::now();
53 let status = cmd.spawn()?.wait()?;
54 let d = ts.elapsed();
55 Ok((
56 Timings {
57 wall_time: d,
58 user_time: std::f64::NAN,
59 sys_time: std::f64::NAN,
60 },
61 status,
62 ))
63}
64
65#[cfg(unix)]
66fn time_cmd_posix(mut cmd: Command) -> Result<(Timings, ExitStatus)> {
67 let mut tms_before = libc::tms {
69 tms_utime: 0,
70 tms_stime: 0,
71 tms_cutime: 0,
72 tms_cstime: 0,
73 };
74 let mut tms_after = tms_before;
75
76 unsafe { libc::times(&mut tms_before as *mut libc::tms) };
77 let ts = Instant::now();
78 let status = cmd.spawn()?.wait()?;
79 let d = ts.elapsed();
80 unsafe { libc::times(&mut tms_after as *mut libc::tms) };
81
82 let ticks_per_sec = unsafe { libc::sysconf(libc::_SC_CLK_TCK) } as f64;
83 let utime = (tms_after.tms_cutime - tms_before.tms_cutime) as f64 / ticks_per_sec;
84 let stime = (tms_after.tms_cstime - tms_before.tms_cstime) as f64 / ticks_per_sec;
85
86 Ok((
87 Timings {
88 wall_time: d,
89 user_time: utime,
90 sys_time: stime,
91 },
92 status,
93 ))
94}