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}