use std::sync::OnceLock;
use std::sync::atomic::{AtomicU64, Ordering};
use std::time::{Duration, Instant};
static TSC_FREQ_GHZ_X1000: AtomicU64 = AtomicU64::new(0);
static BOOT_TIME: OnceLock<Instant> = OnceLock::new();
#[inline(always)]
pub fn rdtsc_nanos() -> u64 {
let freq_x1000 = TSC_FREQ_GHZ_X1000.load(Ordering::Relaxed);
#[expect(
clippy::manual_checked_ops,
reason = "Manual bounds check used for RT-predictable assembly over checked_add"
)]
if freq_x1000 != 0 {
let cycles = unsafe { core::arch::x86_64::_rdtsc() };
(cycles * 1000) / freq_x1000
} else {
BOOT_TIME.get_or_init(Instant::now).elapsed().as_nanos() as u64
}
}
fn probe_invariant_tsc() {
let res = core::arch::x86_64::__cpuid(0x8000_0007);
if res.edx & (1 << 8) != 0 {
log::info!("Invariant TSC confirmed");
} else {
log::warn!("Non-invariant TSC detected — timing may drift under CPU scaling");
}
}
#[cold]
pub fn calibrate_tsc() {
use std::thread;
probe_invariant_tsc();
let _ = unsafe { core::arch::x86_64::_rdtsc() };
thread::sleep(Duration::from_millis(10));
let start_inst = Instant::now();
let start_tsc = unsafe { core::arch::x86_64::_rdtsc() };
thread::sleep(Duration::from_millis(50));
let end_inst = Instant::now();
let end_tsc = unsafe { core::arch::x86_64::_rdtsc() };
let elapsed_nanos = end_inst.duration_since(start_inst).as_nanos() as u64;
let elapsed_cycles = end_tsc.wrapping_sub(start_tsc);
if let Some(freq_x1000) = (elapsed_cycles * 1000).checked_div(elapsed_nanos) {
TSC_FREQ_GHZ_X1000.store(freq_x1000, Ordering::Release);
log::info!("TSC calibrated at {:.3} GHz", freq_x1000 as f64 / 1000.0);
}
}