precision/
cpucounter.rs

1#[cfg(asm)]
2#[allow(unused_imports)]
3use core::arch::asm;
4
5#[cfg(all(
6    any(target_arch = "wasm32", target_arch = "wasm64"),
7    target_os = "unknown"
8))]
9use wasm_bindgen::prelude::*;
10
11use super::timestamp::*;
12
13pub(crate) struct CPUCounter;
14
15#[cfg(asm)]
16#[inline]
17#[cfg(target_arch = "x86_64")]
18unsafe fn cpucounter() -> u64 {
19    let (low, high): (u64, u64);
20    asm!("rdtscp", out("eax") low, out("edx") high, out("ecx") _);
21    (high << 32) | low
22}
23
24#[cfg(asm)]
25#[inline]
26#[cfg(target_arch = "x86")]
27unsafe fn cpucounter() -> u64 {
28    let (low, high): (u32, u32);
29    asm!("rdtscp", out("eax") low, out("edx") high, out("ecx") _);
30    ((high as u64) << 32) | (low as u64)
31}
32
33#[cfg(asm)]
34#[inline]
35#[cfg(target_arch = "aarch64")]
36unsafe fn cpucounter() -> u64 {
37    let vtm: u64;
38    asm!("mrs {}, cntvct_el0", out(reg) vtm);
39    vtm
40}
41
42#[cfg(asm)]
43#[inline]
44#[cfg(target_arch = "riscv64")]
45unsafe fn cpucounter() -> u64 {
46    let time: u64;
47    asm!("rdtime {}", out(reg) time);
48    time
49}
50
51#[cfg(all(not(asm), not(any(target_arch = "wasm32", target_arch = "wasm64"))))]
52extern "C" {
53    fn cpucounter() -> u64;
54}
55
56#[cfg(any(
57    target_os = "wasix",
58    all(target_os = "wasi", not(feature = "wasi-abi2"))
59))]
60#[inline]
61fn cpucounter() -> u64 {
62    use wasix::{clock_time_get, CLOCKID_MONOTONIC, CLOCKID_REALTIME};
63    unsafe { clock_time_get(CLOCKID_MONOTONIC, 1_000_000) }
64        .or_else(|_| unsafe { clock_time_get(CLOCKID_REALTIME, 1_000_000) })
65        .expect("Clock not available")
66}
67
68#[cfg(all(target_os = "wasi", feature = "wasi-abi2"))]
69fn cpucounter() -> u64 {
70    let nsec = wasi_abi2::clocks::monotonic_clock::now();
71    nsec
72}
73
74#[cfg(all(
75    any(target_arch = "wasm32", target_arch = "wasm64"),
76    target_os = "unknown"
77))]
78#[wasm_bindgen]
79extern "C" {
80    #[allow(non_camel_case_types)]
81    type performance;
82
83    #[wasm_bindgen(static_method_of = performance)]
84    pub fn now() -> f64;
85}
86
87#[cfg(all(
88    any(target_arch = "wasm32", target_arch = "wasm64"),
89    target_os = "unknown"
90))]
91fn cpucounter() -> u64 {
92    (performance::now() * 1_000_000.0) as u64
93}
94
95impl CPUCounter {
96    #[inline]
97    pub fn current() -> Timestamp {
98        #[allow(unused_unsafe)]
99        Timestamp(unsafe { cpucounter() })
100    }
101}