From c84aefa2e8961e052d77b3e580bf71b32414e571 Mon Sep 17 00:00:00 2001 From: GuillaumeDIDIER Date: Thu, 28 May 2020 11:22:50 +0200 Subject: [PATCH] Make calibration able to autodetect micro architecture - still hacky for number of cores --- cache_utils/src/calibration.rs | 56 +++++++++++++++------------ cache_utils/src/complex_addressing.rs | 48 ++++++++++++++--------- 2 files changed, 61 insertions(+), 43 deletions(-) diff --git a/cache_utils/src/calibration.rs b/cache_utils/src/calibration.rs index cdc99f1..803f292 100644 --- a/cache_utils/src/calibration.rs +++ b/cache_utils/src/calibration.rs @@ -1,11 +1,21 @@ #![allow(clippy::missing_safety_doc)] +use crate::complex_addressing::{cache_slicing, CacheSlicing}; use crate::{flush, maccess, rdtsc_fence}; +use cpuid::MicroArchitecture; + use core::arch::x86_64 as arch_x86; #[cfg(feature = "no_std")] use polling_serial::{serial_print as print, serial_println as println}; +extern crate alloc; +use crate::calibration::Verbosity::*; +use alloc::vec; +use alloc::vec::Vec; +use core::cmp::min; +use itertools::Itertools; + #[derive(Ord, PartialOrd, Eq, PartialEq)] pub enum Verbosity { NoOutput, @@ -20,14 +30,6 @@ pub struct HistParams { bucket_number: usize, } -extern crate alloc; -use crate::calibration::Verbosity::*; -use crate::complex_addressing::AddressHasher; -use alloc::vec; -use alloc::vec::Vec; -use core::cmp::min; -use itertools::Itertools; - pub unsafe fn only_reload(p: *const u8) -> u64 { let t = rdtsc_fence(); maccess(p); @@ -194,7 +196,6 @@ pub fn calibrate_flush( iterations: CFLUSH_NUM_ITER, }, verbose_level, - None, ) } @@ -234,7 +235,6 @@ pub unsafe fn calibrate( iterations: num_iterations, }, verbosity_level, - None, ) } @@ -246,18 +246,7 @@ fn calibrate_impl_fixed_freq( operations: &[CalibrateOperation], hist_params: HistParams, verbosity_level: Verbosity, - hasher: Option<&AddressHasher>, ) -> Vec { - // TODO : adapt this to detect CPU generation and grab the correct masks. - // These are the skylake masks. - /*let masks: [usize; 3] = [ - 0b1111_0011_0011_0011_0010_0100_1100_0100_000000, - 0b1011_1010_1101_0111_1110_1010_1010_0010_000000, - 0b0110_1101_0111_1101_0101_1101_0101_0001_000000, - ]; - - let hasher = AddressHasher::new(&masks); - */ if verbosity_level >= Thresholds { println!( "Calibrating {}...", @@ -270,10 +259,28 @@ fn calibrate_impl_fixed_freq( let to_bucket = |time: u64| -> usize { time as usize / hist_params.bucket_size }; let from_bucket = |bucket: usize| -> u64 { (bucket * hist_params.bucket_size) as u64 }; + + let slicing = if let Some(uarch) = MicroArchitecture::get_micro_architecture() { + Some(cache_slicing(uarch, 8)) + } else { + None + }; + + let h = if let Some(s) = slicing { + if s.can_hash() { + Some(|addr: usize| -> usize { slicing.unwrap().hash(addr).unwrap() }) + } else { + None + } + } else { + None + }; + // TODO fix the GROSS hack of using max cpu core supported + let mut ret = Vec::new(); if verbosity_level >= Thresholds { print!("CSV: address, "); - if hasher.is_some() { + if h.is_some() { print!("hash, "); } println!( @@ -294,7 +301,7 @@ fn calibrate_impl_fixed_freq( } if verbosity_level >= RawResult { print!("RESULT:address,"); - if hasher.is_some() { + if h.is_some() { print!("hash,"); } println!( @@ -308,7 +315,7 @@ fn calibrate_impl_fixed_freq( for i in (0..len).step_by(increment) { let pointer = unsafe { p.offset(i) }; - let hash = hasher.map(|h| h.hash(pointer as usize)); + let hash = h.map(|h| h(pointer as usize)); if verbosity_level >= Thresholds { print!("Calibration for {:p}", pointer); @@ -437,7 +444,6 @@ pub fn calibrate_L3_miss_hit( iterations: 1 << 11, }, verbose_level, - None, ); r.into_iter().next().unwrap() diff --git a/cache_utils/src/complex_addressing.rs b/cache_utils/src/complex_addressing.rs index 2c550a1..7e11b93 100644 --- a/cache_utils/src/complex_addressing.rs +++ b/cache_utils/src/complex_addressing.rs @@ -1,16 +1,20 @@ -use crate::complex_addressing::CacheSlicing::{ComplexAddressing, Unsupported}; +use crate::complex_addressing::CacheSlicing::{ + ComplexAddressing, NoSlice, SimpleAddressing, Unsupported, +}; use cpuid::MicroArchitecture; +#[derive(Debug, Copy, Clone)] pub enum CacheSlicing { Unsupported, ComplexAddressing(&'static [usize]), SimpleAddressing(&'static usize), NoSlice, } -const SANDYBRIDGE_TO_SKYLAKE_FUNCTIONS: [usize; 3] = [ +const SANDYBRIDGE_TO_SKYLAKE_FUNCTIONS: [usize; 4] = [ 0b0110_1101_0111_1101_0101_1101_0101_0001_000000, 0b1011_1010_1101_0111_1110_1010_1010_0010_000000, 0b1111_0011_0011_0011_0010_0100_1100_0100_000000, + 0b0, // TODO ]; // missing functions for more than 8 cores. @@ -26,28 +30,36 @@ pub fn cache_slicing(uarch: MicroArchitecture, physical_cores: u8) -> CacheSlici | MicroArchitecture::CoffeeLake => { ComplexAddressing(&SANDYBRIDGE_TO_SKYLAKE_FUNCTIONS[0..((trailing_zeros + 1) as usize)]) } + MicroArchitecture::SandyBridge => { + ComplexAddressing(&SANDYBRIDGE_TO_SKYLAKE_FUNCTIONS[0..((trailing_zeros) as usize)]) + } _ => Unsupported, } } -pub struct AddressHasher<'a> { - masks: &'a [usize], +fn hash(addr: usize, mask: usize) -> usize { + ((addr & mask).count_ones() & 1) as usize } -fn hash(addr: usize, mask: usize) -> u32 { - (addr & mask).count_ones() & 1 -} - -impl AddressHasher<'_> { - pub fn new(masks: &[usize]) -> AddressHasher { - AddressHasher { masks } - } - pub fn hash(&self, addr: usize) -> u32 { - let mut res = 0; - for mask in self.masks { - res <<= 1; - res |= hash(addr, *mask); +impl CacheSlicing { + pub fn can_hash(&self) -> bool { + match self { + Unsupported | NoSlice => false, + ComplexAddressing(_) | SimpleAddressing(_) => true, + } + } + pub fn hash(&self, addr: usize) -> Option { + match self { + SimpleAddressing(&mask) => Some((addr & mask)), + ComplexAddressing(masks) => { + let mut res = 0; + for mask in *masks { + res <<= 1; + res |= hash(addr, *mask); + } + Some(res) + } + _ => None, } - res } }