cpu_time/
clock_gettime.rs

1use std::io::{Result, Error};
2use std::marker::PhantomData;
3use std::rc::Rc;
4use std::time::Duration;
5
6use libc::{clock_gettime, timespec};
7use libc::{CLOCK_PROCESS_CPUTIME_ID, CLOCK_THREAD_CPUTIME_ID};
8
9/// CPU Time Used by The Whole Process
10///
11/// This is an opaque type similar to `std::time::Instant`.
12/// Use `elapsed()` or `duration_since()` to get meaningful time deltas.
13#[derive(Copy, Clone, PartialEq, Eq, Debug, Hash)]
14pub struct ProcessTime(Duration);
15
16/// CPU Time Used by The Current Thread
17///
18/// This is an opaque type similar to `std::time::Instant`.
19/// Use `elapsed()` or `duration_since()` to get meaningful time deltas.
20///
21/// This type is non-thread-shareable (!Sync, !Send) because otherwise it's
22/// to easy to mess up times from different threads. However, you can freely
23/// send Duration's returned by `elapsed()` and `duration_since()`.
24#[derive(Copy, Clone, PartialEq, Eq, Debug, Hash)]
25pub struct ThreadTime(
26    Duration,
27    // makes type non-sync and non-send
28    PhantomData<Rc<()>>,
29);
30
31impl ProcessTime {
32    /// Get current CPU time used by a process process
33    pub fn try_now() -> Result<Self> {
34        let mut time = timespec {
35            tv_sec: 0,
36            tv_nsec: 0,
37        };
38        if unsafe { clock_gettime(CLOCK_PROCESS_CPUTIME_ID, &mut time) } == -1
39        {
40            return Err(Error::last_os_error());
41        }
42        Ok(ProcessTime(Duration::new(
43            time.tv_sec as u64,
44            time.tv_nsec as u32,
45        )))
46    }
47
48    /// Get current CPU time used by a process
49    ///
50    /// # Panics
51    ///
52    /// If `CLOCK_THREAD_CPUTIME_ID` is not supported by the kernel.
53    ///
54    /// On Linux, it was added in version 2.6.12 (year 2005). \
55    /// [On OpenBSD][openbsd] & [FreeBSD][freebsd] support was added in 2013. \
56    /// [On MacOS][macos], `clock_gettime` was not supported until Sierra (2016).
57    ///
58    /// [openbsd]: https://github.com/openbsd/src/commit/7b36c281ba1c99d528efca950572c207acd2e184
59    /// [freebsd]: https://github.com/freebsd/freebsd/commit/e8cf8aab231fe1b1ae82eff6e64af146514eea71
60    /// [macos]: http://www.manpagez.com/man/3/clock_gettime/
61    pub fn now() -> Self {
62        Self::try_now().expect("CLOCK_PROCESS_CPUTIME_ID unsupported")
63    }
64
65    /// Returns the amount of CPU time used from the previous timestamp to now.
66    pub fn try_elapsed(&self) -> Result<Duration> {
67        Ok(Self::try_now()?.duration_since(*self))
68    }
69
70    /// Returns the amount of CPU time used from the previous timestamp to now.
71    ///
72    /// # Panics
73    ///
74    /// If `ProcessTime::now()` panics.
75    pub fn elapsed(&self) -> Duration {
76        Self::now().duration_since(*self)
77    }
78
79    /// Returns the amount of CPU time used from the previous timestamp.
80    pub fn duration_since(&self, timestamp: Self) -> Duration {
81        self.0 - timestamp.0
82    }
83
84    /// Returns the total amount of CPU time used from the program start.
85    pub fn as_duration(&self) -> Duration {
86        self.0
87    }
88}
89
90impl ThreadTime {
91    /// Get current CPU time used by a process process
92    pub fn try_now() -> Result<Self> {
93        let mut time = timespec {
94            tv_sec: 0,
95            tv_nsec: 0,
96        };
97        if unsafe { clock_gettime(CLOCK_THREAD_CPUTIME_ID, &mut time) } == -1
98        {
99            return Err(Error::last_os_error());
100        }
101        Ok(ThreadTime(
102            Duration::new(time.tv_sec as u64, time.tv_nsec as u32),
103            PhantomData,
104        ))
105    }
106
107    /// Get current CPU time used by a process
108    ///
109    /// # Panics
110    ///
111    /// If `CLOCK_THREAD_CPUTIME_ID` is not supported by the kernel.
112    ///
113    /// On Linux, it was added in version 2.6.12 (year 2005). \
114    /// [On OpenBSD][openbsd] & [FreeBSD][freebsd] support was added in 2013. \
115    /// [On MacOS][macos], `clock_gettime` was not supported until Sierra (2016).
116    ///
117    /// [openbsd]: https://github.com/openbsd/src/commit/7b36c281ba1c99d528efca950572c207acd2e184
118    /// [freebsd]: https://github.com/freebsd/freebsd/commit/e8cf8aab231fe1b1ae82eff6e64af146514eea71
119    /// [macos]: http://www.manpagez.com/man/3/clock_gettime/
120    pub fn now() -> Self {
121        Self::try_now().expect("CLOCK_PROCESS_CPUTIME_ID unsupported")
122    }
123
124    /// Returns the amount of CPU time used by the current thread
125    /// from the previous timestamp to now.
126    pub fn try_elapsed(&self) -> Result<Duration> {
127        Ok(ThreadTime::try_now()?.duration_since(*self))
128    }
129
130    /// Returns the amount of CPU time used from the previous timestamp to now.
131    ///
132    /// # Panics
133    ///
134    /// If `ThreadTime::now()` panics.
135    pub fn elapsed(&self) -> Duration {
136        Self::now().duration_since(*self)
137    }
138
139    /// Returns the amount of CPU time used by the current thread
140    /// from the previous timestamp.
141    pub fn duration_since(&self, timestamp: ThreadTime) -> Duration {
142        self.0 - timestamp.0
143    }
144
145    /// Returns the total amount of CPU time used from the program start.
146    pub fn as_duration(&self) -> Duration {
147        self.0
148    }
149}