os_clock/
lib.rs

1//! Access various operating system clocks (such as per-thread CPU Time, system clock, monotomic, etc) on Unix-family systems.
2//!
3//! ## Thread clocks:
4//!
5//! Sendable per-thread CPU clocks are unique to this crate:
6//!
7//! ```
8//! # use std::time::Duration;
9//! # use os_clock::{self, Clock};
10//! #
11//! let clock = os_clock::cpu_clock_for_current_thread().unwrap();
12//!
13//! let start_time = clock.get_time().unwrap();
14//! // Do some work for 5ms...
15//! # loop {
16//! #     if clock.get_time().unwrap() > (start_time + Duration::from_millis(5)) {
17//! #         break;
18//! #     }
19//! # }
20//! assert!(clock.get_time().unwrap() > start_time + Duration::from_millis(5));
21//!
22//! // Notably, a clock for the CPU time of one thread can be accessed from another thread:
23//! std::thread::spawn(move || {
24//!     assert!(clock.get_time().unwrap() > Duration::from_millis(5));
25//!
26//!     let self_clock = os_clock::cpu_clock_for_current_thread().unwrap();
27//!     assert!(self_clock.get_time().unwrap() < Duration::from_millis(1));
28//! })
29//! .join()
30//! # .unwrap();
31//!
32//! // Clocks count from the thread's spawn time
33//! let new_clock = os_clock::cpu_clock_for_current_thread().unwrap();
34//! assert!(new_clock.get_time().unwrap() > Duration::from_millis(5));
35//!
36//! // Use a timer to start counting from the moment the timer is created
37//! let timer = new_clock.start_timer().unwrap();
38//! assert!(timer.elapsed().unwrap() < Duration::from_millis(1));
39//! // Do some work for 5ms...
40//! # loop {
41//! #     if timer.elapsed().unwrap() > Duration::from_millis(5) {
42//! #         break;
43//! #     }
44//! # }
45//! assert!(timer.elapsed().unwrap() > Duration::from_millis(5));
46//!
47//! ```
48
49use std::io::Result;
50use std::time::Duration;
51
52#[cfg_attr(any(target_os = "macos", target_os = "ios"), path = "mach/mod.rs")]
53#[allow(unused_attributes)] // in order to allow #[path = "pthread.rs"] to work
54#[path = "pthread.rs"]
55mod os;
56
57pub use os::{cpu_clock_for_current_thread, ThreadCPUClock};
58
59#[cfg(any(target_os = "macos", target_os = "ios"))]
60pub use os::Thread;
61
62mod posix_clock;
63mod timer;
64pub use posix_clock::{
65    get_current_thread_cpu_time, PosixClock, MONOTONIC_CLOCK, PROCESS_CLOCK, REALTIME_CLOCK,
66};
67
68pub use timer::Timer;
69
70pub trait Clock: Sized + Send {
71    /// Get the current time value of the clock.
72    ///
73    /// Note that the meaning of the `Duration` differs depending on implementation.
74    /// Sometimes the clock represents CPU time, sometimes wall time, etc.
75    fn get_time(&self) -> Result<Duration>;
76
77    /// Start a timer at the current time
78    fn start_timer<'s>(&'s self) -> Result<Timer<'s, Self>> {
79        Ok(Timer {
80            clock: &self,
81            start: self.get_time()?,
82        })
83    }
84}
85
86#[cfg(test)]
87mod tests {
88    use super::{cpu_clock_for_current_thread, Clock};
89
90    #[test]
91    fn valid_measurement() {
92        let clock = cpu_clock_for_current_thread().unwrap();
93
94        let mut samples = std::iter::repeat::<()>(())
95            .map(|_| clock.get_time().unwrap())
96            .step_by(50000);
97
98        let mut last_time = samples.next().unwrap();
99
100        let samples = samples
101            .take(5)
102            .map(|this_time| {
103                assert!(this_time > last_time);
104                let diff = (this_time - last_time).as_secs_f64();
105                last_time = this_time;
106                diff
107            })
108            .collect::<Vec<f64>>();
109
110        let avg = samples.iter().sum::<f64>() / (samples.len() as f64);
111
112        let mean_abs_dev_scaled = samples
113            .iter()
114            .map(|sample| (sample - avg).abs())
115            .sum::<f64>()
116            / (samples.len() as f64)
117            / avg;
118
119        println!(
120            "
121durations of timing 50000 samples
122==================================
123{:#?}
124----------------------------------
125avg: {}, mad scaled: {}",
126            samples, avg, mean_abs_dev_scaled
127        );
128
129        assert!(mean_abs_dev_scaled < 0.1); // test that samples are on average within 10% of the mean
130    }
131}