Skip to main content

dial9_core/
clock.rs

1//! Monotonic and realtime clock readings, the single time base for all trace
2//! timestamps.
3
4/// Read monotonic time in nanoseconds for trace timestamps.
5pub fn clock_monotonic_ns() -> u64 {
6    clock_monotonic_ns_impl()
7}
8
9#[cfg(unix)]
10fn clock_monotonic_ns_impl() -> u64 {
11    clock_gettime_ns(MONOTONIC_CLOCK_ID)
12}
13
14// Matches Rust's Darwin `Instant` backend on Apple platforms.
15#[cfg(all(unix, target_vendor = "apple"))]
16const MONOTONIC_CLOCK_ID: libc::clockid_t = libc::CLOCK_UPTIME_RAW;
17
18// Matches Rust's Unix `Instant` backend on non-Apple platforms.
19#[cfg(all(unix, not(target_vendor = "apple")))]
20const MONOTONIC_CLOCK_ID: libc::clockid_t = libc::CLOCK_MONOTONIC;
21
22#[cfg(unix)]
23fn clock_gettime_ns(clock_id: libc::clockid_t) -> u64 {
24    let mut ts = libc::timespec {
25        tv_sec: 0,
26        tv_nsec: 0,
27    };
28    unsafe {
29        libc::clock_gettime(clock_id, &mut ts);
30    }
31    ts.tv_sec as u64 * 1_000_000_000 + ts.tv_nsec as u64
32}
33
34#[cfg(not(unix))]
35fn clock_monotonic_ns_impl() -> u64 {
36    use std::sync::OnceLock;
37    use std::time::Instant;
38    static EPOCH: OnceLock<Instant> = OnceLock::new();
39    (EPOCH.get_or_init(Instant::now).elapsed().as_nanos() as u64).saturating_add(1)
40}
41
42/// `CLOCK_REALTIME` in nanoseconds since the Unix epoch.
43#[cfg(unix)]
44pub(crate) fn clock_realtime_ns() -> u64 {
45    clock_gettime_ns(libc::CLOCK_REALTIME)
46}
47
48#[cfg(not(unix))]
49pub(crate) fn clock_realtime_ns() -> u64 {
50    use std::time::{SystemTime, UNIX_EPOCH};
51    SystemTime::now()
52        .duration_since(UNIX_EPOCH)
53        .expect("system clock should not be before the unix epoch")
54        .as_nanos() as u64
55}
56
57/// Snapshot `(monotonic_ns, realtime_ns)` as close together as possible.
58/// Reads M₁ -> R -> M₂ and pairs `R` with the midpoint of M₁ and M₂ so
59/// the correlation error is half the `clock_gettime` interval.
60pub(crate) fn clock_pair() -> (u64, u64) {
61    let m1 = clock_monotonic_ns();
62    let r = clock_realtime_ns();
63    let m2 = clock_monotonic_ns();
64    let mono = m1 + m2.saturating_sub(m1) / 2;
65    (mono, r)
66}