Skip to content

Commit

Permalink
wip
Browse files Browse the repository at this point in the history
  • Loading branch information
tobz committed Sep 17, 2023
1 parent ff7abb9 commit f4985a0
Show file tree
Hide file tree
Showing 6 changed files with 104 additions and 41 deletions.
19 changes: 0 additions & 19 deletions src/clocks/counter.rs

This file was deleted.

22 changes: 22 additions & 0 deletions src/clocks/counter/aarch64.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
use core::arch::asm;

#[derive(Clone, Debug, Default)]
pub struct ArmCounter;

impl ArmCounter {
pub fn now(&self) -> u64 {
let count: u64;

unsafe { asm!("mrs {}, cntvct_el0", out(reg) count); }

count
}

pub fn freq_hz(&self) -> Option<u64> {
let freq_hz: u64;

unsafe { asm!("mrs {}, cntfrq_el0", out(reg) freq_hz); }

Some(freq_hz)
}
}
25 changes: 25 additions & 0 deletions src/clocks/counter/mod.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
#[cfg(target_arch = "aarch64")]
mod aarch64;

#[cfg(target_arch = "aarch64")]
pub use self::aarch64::Counter;

#[cfg(all(target_arch = "x86_64", target_feature = "sse2"))]
mod x86_64;

#[cfg(all(target_arch = "x86_64", target_feature = "sse2"))]
pub use self::x86_64::Counter;

#[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 (x86_64) or system counter (ARM) support");
}

pub fn freq_hz(&self) -> Option<u64> {
None
}
}
18 changes: 18 additions & 0 deletions src/clocks/counter/x86_64.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
use core::arch::x86_64::_rdtsc;

#[derive(Clone, Debug, Default)]
pub struct Counter;

impl Counter {
pub fn now(&self) -> u64 {
unsafe { _rdtsc() }
}

pub fn freq_hz(&self) -> Option<u64> {
// TODO: This is where we could potentially query the CPU or add model/arch-specific
// overrides where the TSC frequency is known. From what I remember reading through the
// Intel SDM, some processors _do_ have a fixed TSC frequency? Needs more investigation,
// especially to also consider AMD, and so on.
None
}
}
28 changes: 28 additions & 0 deletions src/detection.rs
Original file line number Diff line number Diff line change
@@ -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
}
33 changes: 11 additions & 22 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -201,7 +202,7 @@ impl Calibration {
ref_time: 0,
src_time: 0,
scale_factor: 1,
scale_shift: 1,
scale_shift: 0,
}
}

Expand All @@ -217,6 +218,14 @@ impl Calibration {
}

fn calibrate(&mut self, reference: Monotonic, source: &Counter) {
// This is a fast path for ARM, as on ARMv8.6-A and later, the system counter ticks at a
// fixed rate of 1GHz, which means we can skip the calibration process entirely and use the
// raw counter measurements as they're already in the reference timebase.
if let Some(1_000_000_000) = source.freq_hz() {
self.reset_timebases(reference, source);
return;
}

let mut variance = Variance::default();
let deadline = reference.now() + MAXIMUM_CAL_TIME_NS;

Expand Down Expand Up @@ -314,7 +323,7 @@ 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 inner = if detection::has_counter_support() {
let source = Counter::default();
let calibration = GLOBAL_CALIBRATION.get_or_init(|| {
let mut calibration = Calibration::new();
Expand Down Expand Up @@ -540,26 +549,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};
Expand Down

0 comments on commit f4985a0

Please sign in to comment.