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}