use crate::time::{Duration, Instant};
mod fallback;
cfg_select! {
target_arch = "x86_64" => {
mod x86_64;
use x86_64::now;
use x86_64::clock_fence;
use x86_64::is_hw_supported;
use x86_64::tick_frequency;
},
target_arch = "aarch64" => {
mod aarch64;
use aarch64::now;
use aarch64::clock_fence;
use aarch64::is_hw_supported;
use aarch64::tick_frequency;
},
_ => {
use fallback::now;
use fallback::clock_fence;
use fallback::is_hw_supported;
use fallback::tick_frequency;
}
}
#[derive(Copy, Clone, Debug, PartialEq)]
#[allow(dead_code, reason = "Some variants aren't used on some architectures.")]
enum TscFrequency {
CpuMetadata(u64), Estimate(u64), }
#[derive(Debug, PartialEq, Eq, Clone, Copy, Hash)]
pub enum GuardedArch {
Fallback,
Hardware,
}
impl GuardedArch {
pub fn best() -> GuardedArch {
if is_hw_supported() {
GuardedArch::Hardware
} else {
GuardedArch::Fallback
}
}
pub fn is_hw_supported(&self) -> bool {
match self {
GuardedArch::Hardware => true,
GuardedArch::Fallback => false,
}
}
pub fn now(&self) -> Instant {
match self {
GuardedArch::Hardware => now(),
GuardedArch::Fallback => fallback::now(),
}
}
pub fn clock_fence(&self) {
match self {
GuardedArch::Hardware => clock_fence(),
GuardedArch::Fallback => fallback::clock_fence(),
}
}
pub fn elapsed(&self, start: Instant, end: Instant) -> Duration {
match (start, end, *self) {
(
Instant::Ticks(start_ticks),
Instant::Ticks(end_ticks),
GuardedArch::Hardware,
) => {
let freq = match tick_frequency() {
TscFrequency::CpuMetadata(freq) => freq,
TscFrequency::Estimate(freq) => freq,
};
Duration::from_ticks(end_ticks.saturating_sub(start_ticks), freq)
},
(
Instant::Std(start_instant),
Instant::Std(end_instant),
GuardedArch::Fallback,
) => Duration::from_nanos(
end_instant.duration_since(start_instant).as_nanos() as u64,
),
_ => unreachable!("other type combinations should never happen"),
}
}
}