Skip to main content

ic_host_process/observation/clock/
mod.rs

1//! Native clocks and thread identity. No sampling, retention or application policy.
2#![allow(
3    unsafe_code,
4    reason = "reviewed clock_gettime and native thread identity calls imported from Profiler"
5)]
6
7/// Host monotonic nanoseconds, falling back to a process-local Instant epoch.
8#[must_use]
9#[allow(
10    clippy::cast_sign_loss,
11    reason = "successful native monotonic clocks have nonnegative seconds and nanoseconds"
12)]
13pub fn monotonic_ns() -> u64 {
14    static START: std::sync::OnceLock<std::time::Instant> = std::sync::OnceLock::new();
15    #[cfg(unix)]
16    {
17        let mut value = libc::timespec {
18            tv_sec: 0,
19            tv_nsec: 0,
20        };
21        // SAFETY: points to an initialized timespec; clock_gettime does not retain it.
22        if unsafe { libc::clock_gettime(libc::CLOCK_MONOTONIC, &raw mut value) } == 0 {
23            return (value.tv_sec as u64)
24                .saturating_mul(1_000_000_000)
25                .saturating_add(value.tv_nsec as u64);
26        }
27    }
28    u64::try_from(
29        START
30            .get_or_init(std::time::Instant::now)
31            .elapsed()
32            .as_nanos(),
33    )
34    .unwrap_or(u64::MAX)
35}
36
37/// CPU nanoseconds of the current thread; zero when the native clock is unavailable.
38#[must_use]
39#[allow(
40    clippy::cast_sign_loss,
41    reason = "successful native CPU clocks have nonnegative seconds and nanoseconds"
42)]
43pub fn thread_cpu_ns() -> u64 {
44    #[cfg(unix)]
45    {
46        let mut value = libc::timespec {
47            tv_sec: 0,
48            tv_nsec: 0,
49        };
50        // SAFETY: valid writable timespec; this clock describes only the current thread.
51        if unsafe { libc::clock_gettime(libc::CLOCK_THREAD_CPUTIME_ID, &raw mut value) } == 0 {
52            return (value.tv_sec as u64)
53                .saturating_mul(1_000_000_000)
54                .saturating_add(value.tv_nsec as u64);
55        }
56    }
57    0
58}
59
60/// Current native thread identity; zero on unsupported hosts or query failure.
61#[must_use]
62pub fn tid() -> u64 {
63    #[cfg(target_os = "linux")]
64    {
65        // SAFETY: gettid has no pointer arguments.
66        u64::try_from(unsafe { libc::syscall(libc::SYS_gettid) }).unwrap_or_default()
67    }
68    #[cfg(target_os = "macos")]
69    {
70        let mut id = 0;
71        // SAFETY: a null thread selects the current thread; id is writable.
72        if unsafe { libc::pthread_threadid_np(0, &raw mut id) } == 0 {
73            id
74        } else {
75            0
76        }
77    }
78    #[cfg(not(any(target_os = "linux", target_os = "macos")))]
79    {
80        0
81    }
82}