diff --git a/src/clocks/counter.rs b/src/clocks/counter.rs index 0288df6..b3e86a3 100644 --- a/src/clocks/counter.rs +++ b/src/clocks/counter.rs @@ -1,19 +1,32 @@ -#[cfg(all(target_arch = "x86_64", target_feature = "sse2"))] -use core::arch::x86_64::_rdtsc; - #[derive(Clone, Debug, Default)] pub struct Counter; #[cfg(all(target_arch = "x86_64", target_feature = "sse2"))] impl Counter { pub fn now(&self) -> u64 { - unsafe { _rdtsc() } + unsafe { ::core::arch::x86_64::_rdtsc() } + } +} + +#[cfg(target_arch = "aarch64")] +impl Counter { + pub fn now(&self) -> u64 { + let count: u64; + + unsafe { + ::core::arch::asm!("mrs {}, cntvct_el0", out(reg) count); + } + + count } } -#[cfg(not(all(target_arch = "x86_64", target_feature = "sse2")))] +#[cfg(not(any( + all(target_arch = "x86_64", target_feature = "sse2"), + target_arch = "aarch64", +)))] impl Counter { pub fn now(&self) -> u64 { - panic!("can't use counter without TSC support"); + panic!("can't use counter without TSC (x86_64) or system counter (ARM) support"); } } diff --git a/src/detection.rs b/src/detection.rs new file mode 100644 index 0000000..4071eae --- /dev/null +++ b/src/detection.rs @@ -0,0 +1,28 @@ +#[allow(dead_code)] +#[cfg(all(target_arch = "x86_64", target_feature = "sse2"))] +pub fn has_counter_support() -> bool { + let cpuid = raw_cpuid::CpuId::new(); + let has_invariant_tsc = cpuid + .get_advanced_power_mgmt_info() + .map_or(false, |apm| apm.has_invariant_tsc()); + let has_rdtscp = cpuid + .get_extended_processor_and_feature_identifiers() + .map_or(false, |epf| epf.has_rdtscp()); + + has_invariant_tsc && has_rdtscp +} + +#[cfg(target_arch = "aarch64")] +pub fn has_counter_support() -> bool { + // AArch64 implies ARMv8 or above, where the system counter is always present. + true +} + +#[allow(dead_code)] +#[cfg(not(any( + all(target_arch = "x86_64", target_feature = "sse2"), + target_arch = "aarch64", +)))] +pub fn has_counter_support() -> bool { + false +} diff --git a/src/lib.rs b/src/lib.rs index d5277ff..bcb71fd 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -148,6 +148,7 @@ use once_cell::sync::OnceCell; mod clocks; use self::clocks::{Counter, Monotonic}; +mod detection; mod mock; pub use self::mock::{IntoNanoseconds, Mock}; mod instant; @@ -201,7 +202,7 @@ impl Calibration { ref_time: 0, src_time: 0, scale_factor: 1, - scale_shift: 1, + scale_shift: 0, } } @@ -314,8 +315,8 @@ impl Clock { /// Support for TSC, etc, are checked at the time of creation, not compile-time. pub fn new() -> Clock { let reference = Monotonic::default(); - let inner = if has_tsc_support() { - let source = Counter::default(); + let inner = if detection::has_counter_support() { + let source = Counter; let calibration = GLOBAL_CALIBRATION.get_or_init(|| { let mut calibration = Calibration::new(); calibration.calibrate(reference, &source); @@ -540,26 +541,6 @@ fn mul_div_po2_u64(value: u64, numer: u64, denom: u32) -> u64 { v as u64 } -#[allow(dead_code)] -#[cfg(all(target_arch = "x86_64", target_feature = "sse2"))] -fn has_tsc_support() -> bool { - let cpuid = raw_cpuid::CpuId::new(); - let has_invariant_tsc = cpuid - .get_advanced_power_mgmt_info() - .map_or(false, |apm| apm.has_invariant_tsc()); - let has_rdtscp = cpuid - .get_extended_processor_and_feature_identifiers() - .map_or(false, |epf| epf.has_rdtscp()); - - has_invariant_tsc && has_rdtscp -} - -#[allow(dead_code)] -#[cfg(not(all(target_arch = "x86_64", target_feature = "sse2")))] -fn has_tsc_support() -> bool { - false -} - #[cfg(test)] pub mod tests { use super::{Clock, Counter, Monotonic};