swage_core/memory/
timer.rs1#[cfg(target_arch = "x86_64")]
2use {core::arch::x86_64, core::ptr};
3
4#[cfg(target_arch = "aarch64")]
5use anyhow::bail;
6use log::trace;
7
8pub trait MemoryTupleTimer {
13 unsafe fn time_subsequent_access_from_ram(
18 &self,
19 a: *const u8,
20 b: *const u8,
21 rounds: usize,
22 ) -> u64;
23}
24
25#[derive(Debug, thiserror::Error)]
27pub enum TimerError {
28 #[error("Architecture not supported")]
30 ArchitectureNotSupported,
31}
32
33pub fn construct_memory_tuple_timer() -> Result<Box<dyn MemoryTupleTimer>, TimerError> {
39 #[cfg(target_arch = "x86_64")]
40 return Ok(Box::new(DefaultMemoryTupleTimer {}));
41 #[cfg(target_arch = "aarch64")]
42 return Err(ArchitectureNotSupported);
43}
44
45#[cfg(target_arch = "x86_64")]
47pub struct DefaultMemoryTupleTimer {}
48
49#[cfg(target_arch = "x86_64")]
50impl MemoryTupleTimer for DefaultMemoryTupleTimer {
51 unsafe fn time_subsequent_access_from_ram(
57 &self,
58 a: *const u8,
59 b: *const u8,
60 rounds: usize,
61 ) -> u64 {
62 unsafe {
63 let mut measurements = Vec::with_capacity(rounds);
64 x86_64::_mm_clflush(a);
66 x86_64::_mm_clflush(b);
67 let mut aux = 0;
68 let mut run_idx = 0;
69 let mut sum = 0;
70 while run_idx < rounds {
71 x86_64::_mm_mfence(); let before = x86_64::__rdtscp(&mut aux); x86_64::_mm_mfence(); ptr::read_volatile(a);
75 ptr::read_volatile(b);
76 let after = x86_64::__rdtscp(&mut aux); x86_64::_mm_mfence(); let time = after - before;
79 measurements.push(time);
80 sum += time;
81 run_idx += 1;
82 x86_64::_mm_clflush(a);
84 x86_64::_mm_clflush(b);
85 }
86 trace!("Measurements: {:?}", measurements);
87 let _mean = sum / rounds as u64;
88 median(measurements)
89 }
90 }
91}
92
93fn median(mut list: Vec<u64>) -> u64 {
94 list.sort();
95 let mid = list.len() / 2;
96 (list[mid] + list[mid + 1]) / 2
97}