perf_timer/
arch.rs

1use core::u64;
2
3#[cfg(target_arch = "x86_64")]
4pub use x64::X64 as Arch;
5
6#[cfg(target_arch = "aarch64")]
7pub use aarch64::Aarch64 as Arch;
8
9pub trait ArchFunctionality {
10    /// Value of the counter.
11    fn cpu_count() -> u64;
12    /// Value in Hz of how often the counter increment.
13    fn cpu_count_frequency() -> u64;
14    /// Value the performance counter starts with when it rolls over.
15    fn cpu_count_start() -> u64 {
16        0
17    }
18    /// Value that the performance counter ends with before it rolls over.
19    fn cpu_count_end() -> u64 {
20        u64::MAX
21    }
22}
23
24#[cfg(target_arch = "x86_64")]
25pub(crate) mod x64 {
26    use super::*;
27    use core::arch::x86_64::{self, CpuidResult};
28
29    pub struct X64;
30    impl ArchFunctionality for X64 {
31        fn cpu_count() -> u64 {
32            #[cfg(feature = "validate_cpu_features")]
33            {
34                // TSC support in bit 4.
35                if (unsafe { x86_64::__cpuid(0x01) }.edx & 0x10) != 0x10 {
36                    panic!("CPU does not support TSC");
37                }
38                // Invariant TSC support in bit 8.
39                if (unsafe { x86_64::__cpuid(0x80000007) }.edx & 0x100) != 0x100 {
40                    panic!("CPU does not support Invariant TSC");
41                }
42            }
43            unsafe { x86_64::_rdtsc() }
44        }
45
46        fn cpu_count_frequency() -> u64 {
47            // https://en.wikipedia.org/wiki/CPUID
48            let CpuidResult {
49                eax, // Ratio of TSC frequency to Core Crystal Clock frequency, denominator.
50                ebx, // Ratio of TSC frequency to Core Crystal Clock frequency, numerator.
51                ecx, // Core Crystal Clock frequency, in units of Hz.
52                ..
53            } = unsafe { x86_64::__cpuid(0x15) };
54
55            #[cfg(feature = "validate_cpu_features")]
56            if ecx == 0 {
57                panic!("CPU does not support CPUID-based frequency determination");
58            }
59
60            (ecx * (ebx / eax)) as u64
61        }
62    }
63}
64
65#[cfg(target_arch = "aarch64")]
66pub(crate) mod aarch64 {
67    use super::*;
68    use aarch64_cpu::registers::{self, Readable};
69    pub struct Aarch64;
70    impl ArchFunctionality for Aarch64 {
71        fn cpu_count() -> u64 {
72            registers::CNTPCT_EL0.get()
73        }
74
75        fn cpu_count_frequency() -> u64 {
76            registers::CNTFRQ_EL0.get()
77        }
78    }
79}