1use std::{ops::Sub, time::Duration};
2
3pub use active_platform::rusage;
5
6#[derive(Debug)]
8pub struct RUsage {
9 pub user_time: Duration,
11
12 pub system_time: Duration,
14}
15
16impl Sub for RUsage {
17 type Output = Self;
18
19 fn sub(self, other: Self) -> Self {
20 Self {
21 user_time: self.user_time - other.user_time,
22 system_time: self.system_time - other.system_time,
23 }
24 }
25}
26
27#[cfg(target_os = "macos")]
28pub use macos as active_platform;
29
30#[cfg(target_os = "linux")]
31pub use linux as active_platform;
32
33#[cfg(target_os = "windows")]
34pub use windows as active_platform;
35
36#[cfg(target_os = "linux")]
37pub mod linux {
38 pub use super::unix::rusage;
39}
40
41#[cfg(target_os = "macos")]
42pub mod macos {
43 pub use super::unix::rusage;
44}
45
46#[cfg(target_family = "unix")]
47pub mod unix {
48 use super::RUsage;
49 use std::{mem::MaybeUninit, time::Duration};
50
51 pub fn rusage() -> RUsage {
52 use libc::{getrusage, rusage, RUSAGE_SELF};
53
54 let mut usage = unsafe { MaybeUninit::<rusage>::zeroed().assume_init() };
56 let err_code = unsafe { getrusage(RUSAGE_SELF, &mut usage as *mut _) };
57 assert!(err_code == 0, "getrusage() failed with code: {err_code}");
58
59 usage.into()
60 }
61
62 impl From<libc::rusage> for RUsage {
63 fn from(usage: libc::rusage) -> Self {
64 fn timeval_to_duration(tv: libc::timeval) -> Duration {
65 Duration::from_secs(tv.tv_sec as u64) + Duration::from_micros(tv.tv_usec as u64)
66 }
67 Self {
68 user_time: timeval_to_duration(usage.ru_utime),
69 system_time: timeval_to_duration(usage.ru_stime),
70 }
71 }
72 }
73}
74
75#[cfg(target_os = "windows")]
76pub mod windows {
77 use super::*;
78 use ::windows::Win32::{
79 Foundation::FILETIME,
80 System::Threading::{GetCurrentProcess, GetProcessTimes},
81 };
82
83 pub fn rusage() -> RUsage {
84 let mut dummy = FILETIME::default();
85 let mut kernel_time = FILETIME::default();
86 let mut user_time = FILETIME::default();
87 unsafe {
88 GetProcessTimes(
89 GetCurrentProcess(),
90 &mut dummy as *mut _,
91 &mut dummy as *mut _,
92 &mut kernel_time as *mut _,
93 &mut user_time as *mut _,
94 )
95 }
96 .unwrap();
97
98 RUsage {
99 user_time: filetime_to_duration(user_time),
100 system_time: filetime_to_duration(kernel_time),
101 }
102 }
103
104 fn filetime_to_duration(time: FILETIME) -> Duration {
105 Duration::from_micros(time.dwLowDateTime as u64 / 10)
107 }
108}