Skip to main content

tango_bench/
platform.rs

1use std::{ops::Sub, time::Duration};
2
3/// Reexports
4pub use active_platform::rusage;
5
6/// Describes how much resources current process spent
7#[derive(Debug)]
8pub struct RUsage {
9    /// CPU time spent in user mode
10    pub user_time: Duration,
11
12    /// CPU time spent in a system/kernel mode
13    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        // SAFETY: rusage contains no references, so zeroed struct pose no UB
55        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        // FILETIME is expressed in 100ns time units
106        Duration::from_micros(time.dwLowDateTime as u64 / 10)
107    }
108}