mirror of
https://github.com/edera-dev/sprout.git
synced 2025-12-19 15:40:16 +00:00
fix(platform/timer): on x86_64, elide usage of asm!() and use _rdtsc() intrinsic
This commit is contained in:
@@ -17,7 +17,7 @@ pub enum TickFrequency {
|
|||||||
/// The platform provides the tick frequency.
|
/// The platform provides the tick frequency.
|
||||||
Hardware(u64),
|
Hardware(u64),
|
||||||
/// The tick frequency is measured internally.
|
/// The tick frequency is measured internally.
|
||||||
Measured(u64, Duration),
|
Measured(u64),
|
||||||
}
|
}
|
||||||
|
|
||||||
impl TickFrequency {
|
impl TickFrequency {
|
||||||
@@ -25,7 +25,7 @@ impl TickFrequency {
|
|||||||
fn ticks(&self) -> u64 {
|
fn ticks(&self) -> u64 {
|
||||||
match self {
|
match self {
|
||||||
TickFrequency::Hardware(frequency) => *frequency,
|
TickFrequency::Hardware(frequency) => *frequency,
|
||||||
TickFrequency::Measured(frequency, _) => *frequency,
|
TickFrequency::Measured(frequency) => *frequency,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -10,16 +10,6 @@ pub fn ticks() -> u64 {
|
|||||||
counter
|
counter
|
||||||
}
|
}
|
||||||
|
|
||||||
/// We can use the actual ticks value as our start value.
|
|
||||||
pub fn start() -> u64 {
|
|
||||||
ticks()
|
|
||||||
}
|
|
||||||
|
|
||||||
/// We can use the actual ticks value as our stop value.
|
|
||||||
pub fn stop() -> u64 {
|
|
||||||
ticks()
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Our frequency is provided by cntfrq_el0 on the platform.
|
/// Our frequency is provided by cntfrq_el0 on the platform.
|
||||||
pub fn frequency() -> TickFrequency {
|
pub fn frequency() -> TickFrequency {
|
||||||
let frequency: u64;
|
let frequency: u64;
|
||||||
|
|||||||
@@ -1,5 +1,4 @@
|
|||||||
use crate::platform::timer::TickFrequency;
|
use crate::platform::timer::TickFrequency;
|
||||||
use core::arch::asm;
|
|
||||||
use core::time::Duration;
|
use core::time::Duration;
|
||||||
|
|
||||||
/// We will measure the frequency of the timer based on 1000 microseconds.
|
/// We will measure the frequency of the timer based on 1000 microseconds.
|
||||||
@@ -8,52 +7,16 @@ const MEASURE_FREQUENCY_DURATION: Duration = Duration::from_micros(1000);
|
|||||||
|
|
||||||
/// Read the number of ticks from the platform timer.
|
/// Read the number of ticks from the platform timer.
|
||||||
pub fn ticks() -> u64 {
|
pub fn ticks() -> u64 {
|
||||||
let mut eax: u32;
|
// SAFETY: Reads the platform timer, which is safe in any context.
|
||||||
let mut edx: u32;
|
unsafe { core::arch::x86_64::_rdtsc() }
|
||||||
|
|
||||||
unsafe {
|
|
||||||
asm!("rdtsc", out("eax") eax, out("edx") edx);
|
|
||||||
}
|
|
||||||
|
|
||||||
(edx as u64) << 32 | eax as u64
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Read the starting number of ticks from the platform timer.
|
|
||||||
pub fn start() -> u64 {
|
|
||||||
let rax: u64;
|
|
||||||
unsafe {
|
|
||||||
asm!(
|
|
||||||
"mfence",
|
|
||||||
"lfence",
|
|
||||||
"rdtsc",
|
|
||||||
"shl rdx, 32",
|
|
||||||
"or rax, rdx",
|
|
||||||
out("rax") rax
|
|
||||||
);
|
|
||||||
}
|
|
||||||
rax
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Read the ending number of ticks from the platform timer.
|
|
||||||
pub fn stop() -> u64 {
|
|
||||||
let rax: u64;
|
|
||||||
unsafe {
|
|
||||||
asm!(
|
|
||||||
"rdtsc",
|
|
||||||
"lfence",
|
|
||||||
"shl rdx, 32",
|
|
||||||
"or rax, rdx",
|
|
||||||
out("rax") rax
|
|
||||||
);
|
|
||||||
}
|
|
||||||
rax
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Measure the frequency of the platform timer.
|
/// Measure the frequency of the platform timer.
|
||||||
|
/// NOTE: Intentionally, we do not synchronize rdtsc during measurement to match systemd behavior.
|
||||||
fn measure_frequency() -> u64 {
|
fn measure_frequency() -> u64 {
|
||||||
let start = start();
|
let start = ticks();
|
||||||
uefi::boot::stall(MEASURE_FREQUENCY_DURATION);
|
uefi::boot::stall(MEASURE_FREQUENCY_DURATION);
|
||||||
let stop = stop();
|
let stop = ticks();
|
||||||
let elapsed = stop.wrapping_sub(start) as f64;
|
let elapsed = stop.wrapping_sub(start) as f64;
|
||||||
(elapsed / MEASURE_FREQUENCY_DURATION.as_secs_f64()) as u64
|
(elapsed / MEASURE_FREQUENCY_DURATION.as_secs_f64()) as u64
|
||||||
}
|
}
|
||||||
@@ -62,5 +25,5 @@ fn measure_frequency() -> u64 {
|
|||||||
/// On x86_64, this is slightly expensive, so it should be done once.
|
/// On x86_64, this is slightly expensive, so it should be done once.
|
||||||
pub fn frequency() -> TickFrequency {
|
pub fn frequency() -> TickFrequency {
|
||||||
let frequency = measure_frequency();
|
let frequency = measure_frequency();
|
||||||
TickFrequency::Measured(frequency, MEASURE_FREQUENCY_DURATION)
|
TickFrequency::Measured(frequency)
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user