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