#[cfg(unix)]
#[repr(C)]
struct Timespec {
tv_sec: i64,
tv_nsec: i64,
}
#[cfg(unix)]
const _: () = assert!(
std::mem::size_of::<usize>() == 8,
"cpu-time requires a 64-bit target"
);
#[cfg(all(unix, target_os = "linux"))]
const CLOCK_THREAD_CPUTIME_ID: i32 = 3;
#[cfg(all(unix, target_os = "macos"))]
const CLOCK_THREAD_CPUTIME_ID: i32 = 16;
#[cfg(all(unix, not(any(target_os = "linux", target_os = "macos"))))]
compile_error!("cpu-time is only supported on Linux and macOS");
#[cfg(unix)]
extern "C" {
fn clock_gettime(clk_id: i32, tp: *mut Timespec) -> i32;
}
#[cfg(unix)]
use std::sync::atomic::{compiler_fence, Ordering};
#[cfg(unix)]
pub fn calibrate_bias() -> u64 {
const SAMPLES: usize = 100_000;
let start = cpu_now_ns();
for _ in 0..SAMPLES {
compiler_fence(Ordering::SeqCst);
crate::time::read();
}
let end = cpu_now_ns();
let bias = (end - start) as f64 / SAMPLES as f64;
bias.to_bits()
}
#[cfg(unix)]
pub fn cpu_now_ns() -> u64 {
let mut ts = Timespec {
tv_sec: 0,
tv_nsec: 0,
};
let ret = unsafe { clock_gettime(CLOCK_THREAD_CPUTIME_ID, &mut ts) };
if ret != 0 {
return 0;
}
const NS_PER_SEC: u64 = 1_000_000_000;
ts.tv_sec as u64 * NS_PER_SEC + ts.tv_nsec as u64
}
#[cfg(not(unix))]
pub(crate) fn cpu_now_ns() -> u64 {
unreachable!("cpu_now_ns called on non-Unix; gated by cpu_time_enabled bool")
}
#[cfg(not(unix))]
pub fn calibrate_bias() -> u64 {
0
}