Skip to main content

clock_tour/
clock-tour.rs

1//! Each clock side by side: what it reads, and what a reading costs on this machine.
2//!
3//! It runs where the OS clocks and a counter are: 64-bit Linux or macOS, on Arm or x86.
4//!
5//! ```text
6//! cargo run --release -p t2t --features std --example clock-tour
7//! ```
8
9#![expect(clippy::print_stdout, reason = "a tour prints what it finds")]
10
11use core::fmt::Display;
12use core::hint::black_box;
13use std::process::ExitCode;
14
15use t2t::Timedelta;
16#[cfg(target_os = "linux")]
17use t2t::clock::TaiClock;
18use t2t::clock::{
19    BootClock, Clock, CoarseMonotonicClock, CoarseSystemClock, Counter, MonotonicClock,
20    ProcessCpuClock, RawMonotonicClock, SystemClock, ThreadCpuClock,
21};
22
23/// The readings taken back to back to time one.
24const READINGS: i64 = 100_000;
25
26fn main() -> ExitCode {
27    let counter = match Counter::discover() {
28        Ok(counter) => counter,
29        Err(error) => {
30            #[expect(clippy::print_stderr, reason = "the person running the tour reads why")]
31            {
32                eprintln!("clock-tour: {error}");
33            }
34            return ExitCode::FAILURE;
35        },
36    };
37    println!("{:<21} {}\n", "Counter's rate", counter.rate());
38    report(&counter, "SystemClock", &SystemClock);
39    report(&counter, "CoarseSystemClock", &CoarseSystemClock);
40    #[cfg(target_os = "linux")]
41    report(&counter, "TaiClock", &TaiClock);
42    report(&counter, "MonotonicClock", &MonotonicClock);
43    report(&counter, "CoarseMonotonicClock", &CoarseMonotonicClock);
44    report(&counter, "RawMonotonicClock", &RawMonotonicClock);
45    report(&counter, "BootClock", &BootClock);
46    report(&counter, "ProcessCpuClock", &ProcessCpuClock);
47    report(&counter, "ThreadCpuClock", &ThreadCpuClock);
48    report(&counter, "Counter", &counter);
49    ExitCode::SUCCESS
50}
51
52/// Prints what `clock` reads now, and what one reading of it costs, timed on `counter`.
53fn report<C: Clock<Reading: Display>>(counter: &Counter, name: &str, clock: &C) {
54    println!("{name:<21} {:<36} {} a reading", clock.now(), cost(counter, clock));
55}
56
57/// What one reading of `clock` costs, timed on `counter` over [`READINGS`] readings.
58fn cost<C: Clock>(counter: &Counter, clock: &C) -> Timedelta {
59    let start = counter.now();
60    for _ in 0..READINGS {
61        black_box(clock.now());
62    }
63    let total = (counter.now() - start).to_timedelta(counter.rate());
64    total.checked_div(READINGS).unwrap_or(Timedelta::ZERO)
65}