Add prefetcher experiments

This commit is contained in:
Guillume DIDIER 2021-11-24 11:52:23 +01:00
parent 0807d3bda9
commit 84eee25e5a
7 changed files with 177 additions and 56 deletions

View File

@ -1,18 +1,23 @@
use prefetcher_reverse::{Prober, PAGE_CACHELINE_LEN}; use prefetcher_reverse::ip_tool::{Function, TIMED_MACCESS};
use prefetcher_reverse::{pattern_helper, Prober, PAGE_CACHELINE_LEN};
pub const NUM_ITERATION: usize = 1 << 10; pub const NUM_ITERATION: usize = 1 << 10;
fn exp(delay: u64) { fn exp(delay: u64, reload: &Function) {
let mut prober = Prober::<2>::new(63).unwrap(); let mut prober = Prober::<2>::new(63).unwrap();
prober.set_delay(delay); prober.set_delay(delay);
let pattern = (0usize..(PAGE_CACHELINE_LEN * 2usize)).collect::<Vec<usize>>(); let pattern = (0usize..(PAGE_CACHELINE_LEN * 2usize)).collect::<Vec<usize>>();
let result = prober.full_page_probe(pattern, NUM_ITERATION as u32, 100); let p = pattern_helper(pattern, reload);
let result = prober.full_page_probe(p, NUM_ITERATION as u32, 100);
println!("{}", result); println!("{}", result);
} }
fn main() { fn main() {
let reload = Function::try_new(1, 0, TIMED_MACCESS).unwrap();
for delay in [0, 5, 10, 50] { for delay in [0, 5, 10, 50] {
println!("Delay after each access: {} us", delay); println!("Delay after each access: {} us", delay);
exp(delay); exp(delay, &reload);
} }
} }

View File

@ -10,7 +10,10 @@ use cache_utils::mmap;
use cache_utils::mmap::MMappedMemory; use cache_utils::mmap::MMappedMemory;
use flush_flush::{FFHandle, FFPrimitives, FlushAndFlush}; use flush_flush::{FFHandle, FFPrimitives, FlushAndFlush};
use nix::Error; use nix::Error;
use prefetcher_reverse::{reference_patterns, Prober, CACHE_LINE_LEN, PAGE_CACHELINE_LEN}; use prefetcher_reverse::ip_tool::{Function, TIMED_MACCESS};
use prefetcher_reverse::{
pattern_helper, reference_patterns, Prober, CACHE_LINE_LEN, PAGE_CACHELINE_LEN,
};
use rand::seq::SliceRandom; use rand::seq::SliceRandom;
use std::iter::Cycle; use std::iter::Cycle;
use std::ops::Range; use std::ops::Range;
@ -18,19 +21,21 @@ use std::ops::Range;
pub const NUM_ITERATION: usize = 1 << 10; pub const NUM_ITERATION: usize = 1 << 10;
pub const NUM_PAGES: usize = 256; pub const NUM_PAGES: usize = 256;
fn exp(delay: u64) { fn exp(delay: u64, reload: &Function) {
for (name, pattern) in reference_patterns() { for (name, pattern) in reference_patterns() {
let p = pattern_helper(pattern, reload);
let mut prober = Prober::<1>::new(63).unwrap(); let mut prober = Prober::<1>::new(63).unwrap();
println!("{}", name); println!("{}", name);
let result = prober.full_page_probe(pattern, NUM_ITERATION as u32, 100); let result = prober.full_page_probe(p, NUM_ITERATION as u32, 100);
println!("{}", result); println!("{}", result);
} }
} }
fn main() { fn main() {
let reload = Function::try_new(1, 0, TIMED_MACCESS).unwrap();
for delay in [0, 5, 10, 50] { for delay in [0, 5, 10, 50] {
println!("Delay after each access: {} us", delay); println!("Delay after each access: {} us", delay);
exp(delay); exp(delay, &reload);
} }
} }

View File

@ -1,8 +1,41 @@
use prefetcher_reverse::{Prober, PAGE_CACHELINE_LEN}; use cache_utils::{flush, maccess};
use prefetcher_reverse::ip_tool::{Function, TIMED_MACCESS};
use prefetcher_reverse::{pattern_helper, Prober, PAGE_CACHELINE_LEN};
use std::arch::x86_64 as arch_x86;
pub const NUM_ITERATION: usize = 1 << 10; pub const NUM_ITERATION: usize = 1 << 10;
fn exp(stride: usize, num_steps: i32, delay: u64) { unsafe extern "C" fn prefetch_l2(p: *const u8) -> u64 {
maccess(p);
arch_x86::_mm_mfence();
flush(p);
arch_x86::_mm_mfence();
arch_x86::_mm_prefetch::<{ arch_x86::_MM_HINT_T1 }>(p as *const i8);
arch_x86::__cpuid_count(0, 0);
0
}
unsafe extern "C" fn prefetch_l3(p: *const u8) -> u64 {
maccess(p);
arch_x86::_mm_mfence();
flush(p);
arch_x86::_mm_mfence();
arch_x86::_mm_prefetch::<{ arch_x86::_MM_HINT_T2 }>(p as *const i8);
arch_x86::__cpuid_count(0, 0);
0
}
unsafe extern "C" fn prefetch_l1(p: *const u8) -> u64 {
maccess(p);
arch_x86::_mm_mfence();
flush(p);
arch_x86::_mm_mfence();
arch_x86::_mm_prefetch::<{ arch_x86::_MM_HINT_T0 }>(p as *const i8);
arch_x86::__cpuid_count(0, 0);
0
}
fn exp(stride: usize, num_steps: i32, delay: u64, reload: &Function) {
let mut prober = Prober::<2>::new(63).unwrap(); let mut prober = Prober::<2>::new(63).unwrap();
prober.set_delay(delay); prober.set_delay(delay);
let limit = if num_steps < 0 { let limit = if num_steps < 0 {
@ -11,23 +44,71 @@ fn exp(stride: usize, num_steps: i32, delay: u64) {
stride * num_steps as usize stride * num_steps as usize
}; };
let pattern = (2usize..limit).step_by(stride).collect::<Vec<_>>(); let pattern = (2usize..limit).step_by(stride).collect::<Vec<_>>();
let result = prober.full_page_probe(pattern, NUM_ITERATION as u32, 100); let p = pattern_helper(pattern, reload);
let pl2 = Function {
fun: prefetch_l2,
ip: prefetch_l2 as *const u8,
end: prefetch_l2 as *const u8,
size: 0,
};
let pl3 = Function {
fun: prefetch_l3,
ip: prefetch_l3 as *const u8,
end: prefetch_l3 as *const u8,
size: 0,
};
let pl1 = Function {
fun: prefetch_l1,
ip: prefetch_l1 as *const u8,
end: prefetch_l1 as *const u8,
size: 0,
};
let mut pattern_pl2 = pattern_helper((0..(2 * PAGE_CACHELINE_LEN)).collect(), &pl2);
pattern_pl2.extend(p.iter().cloned());
let mut pattern_pl3 = pattern_helper((0..(2 * PAGE_CACHELINE_LEN)).collect(), &pl3);
pattern_pl3.extend(p.iter().cloned());
let mut pattern_pl1 = pattern_helper((0..(2 * PAGE_CACHELINE_LEN)).collect(), &pl1);
pattern_pl1.extend(p.iter().cloned());
println!("With no sw prefetch");
let result = prober.full_page_probe(p, NUM_ITERATION as u32, 100);
println!("{}", result);
println!("With L2 sw prefetch");
let result = prober.full_page_probe(pattern_pl2, NUM_ITERATION as u32, 100);
println!("{}", result);
println!("With L3 sw prefetch");
let result = prober.full_page_probe(pattern_pl3, NUM_ITERATION as u32, 100);
println!("{}", result);
println!("With L1 sw prefetch");
let result = prober.full_page_probe(pattern_pl1, NUM_ITERATION as u32, 100);
println!("{}", result); println!("{}", result);
} }
fn main() { fn main() {
for stride in [3, 4] { //let reload = Function::try_new(1, 0, TIMED_MACCESS).unwrap();
let mut reloads = Vec::new();
for i in 0..3 {
reloads.push(Function::try_new(4, i, TIMED_MACCESS).unwrap());
}
for (index, stride) in [2, 3, 4].iter().enumerate() {
let reload = &reloads[index];
for delay_shift in [5, 12] { for delay_shift in [5, 12] {
let limit = ((PAGE_CACHELINE_LEN + 32) / stride) as i32; let limit = ((PAGE_CACHELINE_LEN + 32) / stride) as i32;
//for num_steps in -1..limit { //for num_steps in -1..limit {
let num_steps = limit; let num_steps = limit;
println!( println!(
"Stride: {}, Limit: {}, Delay: {}", "Stride: {}, Limit: {}, Delay: {}",
stride, *stride,
num_steps, num_steps,
1 << delay_shift 1 << delay_shift
); );
exp(stride, num_steps, 1 << delay_shift); exp(*stride, num_steps, 1 << delay_shift, &reload);
//} //}
} }
} }

View File

@ -1,8 +1,9 @@
use prefetcher_reverse::{Prober, PAGE_CACHELINE_LEN}; use prefetcher_reverse::ip_tool::{Function, TIMED_MACCESS};
use prefetcher_reverse::{pattern_helper, Prober, PAGE_CACHELINE_LEN};
pub const NUM_ITERATION: usize = 1 << 10; pub const NUM_ITERATION: usize = 1 << 10;
fn exp(stride: usize, num_steps: i32, delay: u64) { fn exp(stride: usize, num_steps: i32, delay: u64, reload: &Function) {
let mut prober = Prober::<2>::new(63).unwrap(); let mut prober = Prober::<2>::new(63).unwrap();
prober.set_delay(delay); prober.set_delay(delay);
let limit = if num_steps < 0 { let limit = if num_steps < 0 {
@ -11,11 +12,15 @@ fn exp(stride: usize, num_steps: i32, delay: u64) {
stride * num_steps as usize stride * num_steps as usize
}; };
let pattern = (2usize..limit).step_by(stride).collect::<Vec<_>>(); let pattern = (2usize..limit).step_by(stride).collect::<Vec<_>>();
let result = prober.full_page_probe(pattern, NUM_ITERATION as u32, 100); let p = pattern_helper(pattern, reload);
let result = prober.full_page_probe(p, NUM_ITERATION as u32, 100);
println!("{}", result); println!("{}", result);
} }
fn main() { fn main() {
let reload = Function::try_new(1, 0, TIMED_MACCESS).unwrap();
for stride in [5, 7, 8] { for stride in [5, 7, 8] {
for delay_shift in [5, 12, 20] { for delay_shift in [5, 12, 20] {
//let stride = 8; //let stride = 8;
@ -28,7 +33,7 @@ fn main() {
num_steps, num_steps,
1 << delay_shift 1 << delay_shift
); );
exp(stride, num_steps, 1 << delay_shift); exp(stride, num_steps, 1 << delay_shift, &reload);
//} //}
} }
} }

View File

@ -32,22 +32,25 @@ pub struct FunctionTemplate {
end: *const u8, end: *const u8,
} }
// Note those fields should not be public
// We need a way to also take care of non allocated functions.
#[derive(Debug)]
pub struct Function { pub struct Function {
fun: unsafe extern "C" fn(*const u8) -> u64, pub fun: unsafe extern "C" fn(*const u8) -> u64,
ip: *const u8, pub ip: *const u8,
end: *const u8, pub end: *const u8,
size: usize, pub size: usize,
} }
lazy_static! { lazy_static! {
static ref wx_allocator: Mutex<WXAllocator> = Mutex::new(WXAllocator::new()); static ref wx_allocator: Mutex<WXAllocator> = Mutex::new(WXAllocator::new());
} }
const TIMED_MACCESS: FunctionTemplate = FunctionTemplate { pub const TIMED_MACCESS: FunctionTemplate = FunctionTemplate {
start: timed_maccess_template, start: timed_maccess_template,
ip: timed_maccess_template_ip as *const u8, ip: timed_maccess_template_ip as *const u8,
end: timed_maccess_template_end as *const u8, end: timed_maccess_template_end as *const u8,
}; };
const TIMED_CLFLUSH: FunctionTemplate = FunctionTemplate { pub const TIMED_CLFLUSH: FunctionTemplate = FunctionTemplate {
start: timed_clflush_template, start: timed_clflush_template,
ip: timed_clflush_template_ip as *const u8, ip: timed_clflush_template_ip as *const u8,
end: timed_clflush_template_end as *const u8, end: timed_clflush_template_end as *const u8,

View File

@ -26,6 +26,8 @@ use std::{thread, time};
pub mod ip_tool; pub mod ip_tool;
use ip_tool::Function;
// NB these may need to be changed / dynamically measured. // NB these may need to be changed / dynamically measured.
pub const CACHE_LINE_LEN: usize = 64; pub const CACHE_LINE_LEN: usize = 64;
pub const PAGE_CACHELINE_LEN: usize = PAGE_LEN / CACHE_LINE_LEN; pub const PAGE_CACHELINE_LEN: usize = PAGE_LEN / CACHE_LINE_LEN;
@ -58,9 +60,15 @@ pub enum ProbeType {
FullFlush, FullFlush,
} }
#[derive(Debug, Clone)]
pub struct PatternAccess<'a> {
pub function: &'a Function,
pub offset: usize,
}
#[derive(Debug)] #[derive(Debug)]
pub struct ProbePattern { pub struct ProbePattern<'a> {
pub pattern: Vec<usize>, pub pattern: Vec<PatternAccess<'a>>,
pub probe: Probe, pub probe: Probe,
} }
@ -105,8 +113,8 @@ pub struct DualProbeResult {
} }
#[derive(Debug)] #[derive(Debug)]
pub struct FullPageDualProbeResults { pub struct FullPageDualProbeResults<'a> {
pub pattern: Vec<usize>, pub pattern: Vec<PatternAccess<'a>>,
pub num_iteration: u32, pub num_iteration: u32,
pub single_probe_results: Vec<DualProbeResult>, pub single_probe_results: Vec<DualProbeResult>,
pub full_flush_results: DPRItem<FullPR>, pub full_flush_results: DPRItem<FullPR>,
@ -120,8 +128,8 @@ pub struct SingleProbeResult {
} }
#[derive(Debug)] #[derive(Debug)]
pub struct FullPageSingleProbeResult<const GS: usize> { pub struct FullPageSingleProbeResult<'a, const GS: usize> {
pub pattern: Vec<usize>, pub pattern: Vec<PatternAccess<'a>>,
pub probe_type: ProbeType, pub probe_type: ProbeType,
pub num_iteration: u32, pub num_iteration: u32,
pub results: Vec<SingleProbeResult>, pub results: Vec<SingleProbeResult>,
@ -243,15 +251,14 @@ impl<const GS: usize> Prober<GS> {
unsafe { self.ff_channel.prepare(&mut ff_handles) }; unsafe { self.ff_channel.prepare(&mut ff_handles) };
let mut pattern_res = vec![0; pattern.pattern.len()]; let mut pattern_res = vec![0; pattern.pattern.len()];
for (i, offset) in pattern.pattern.iter().enumerate() { for (i, access) in pattern.pattern.iter().enumerate() {
let h = &mut self.fr_handles[page_index][*offset]; let h = &mut self.fr_handles[page_index][access.offset];
pattern_res[i] = unsafe { self.fr_channel.test_debug(h, false) }.unwrap().1; let pointer: *const u8 = h.to_const_u8_pointer();
pattern_res[i] = unsafe { (access.function.fun)(pointer) };
// TODO IP : This is where the pattern access need to be done using pattern.function instead.
//pattern_res[i] = unsafe { self.fr_channel.test_debug(h, false) }.unwrap().1;
delay(self.delay); delay(self.delay);
/*if self.delay > 0 { //pattern_res[i] = unsafe { self.fr_channel.test_single(h, false) }.unwrap();
thread::sleep(time::Duration::from_nanos(self.delay)); // FIXME parameter magic
}*/
//pattern_res[i] = unsafe { self.fr_channel.test_single(h, false) }.unwrap()
//pattern_res[i] = Miss;
//unsafe { only_reload(h.to_const_u8_pointer()) }; //unsafe { only_reload(h.to_const_u8_pointer()) };
} }
@ -329,13 +336,13 @@ impl<const GS: usize> Prober<GS> {
result result
} }
fn full_page_probe_helper( fn full_page_probe_helper<'a>(
&mut self, &mut self,
pattern: &mut ProbePattern, pattern: &mut ProbePattern<'a>,
probe_type: ProbeType, probe_type: ProbeType,
num_iteration: u32, num_iteration: u32,
warmup: u32, warmup: u32,
) -> FullPageSingleProbeResult<GS> { ) -> FullPageSingleProbeResult<'a, GS> {
let mut result = FullPageSingleProbeResult { let mut result = FullPageSingleProbeResult {
pattern: pattern.pattern.clone(), pattern: pattern.pattern.clone(),
probe_type, probe_type,
@ -362,12 +369,12 @@ impl<const GS: usize> Prober<GS> {
result result
} }
pub fn full_page_probe( pub fn full_page_probe<'a>(
&mut self, &mut self,
pattern: Vec<usize>, pattern: Vec<PatternAccess<'a>>,
num_iteration: u32, num_iteration: u32,
warmup: u32, warmup: u32,
) -> FullPageDualProbeResults { ) -> FullPageDualProbeResults<'a> {
let mut probe_pattern = ProbePattern { let mut probe_pattern = ProbePattern {
pattern: pattern, pattern: pattern,
probe: Probe::FullFlush, probe: Probe::FullFlush,
@ -417,13 +424,13 @@ impl<const GS: usize> Prober<GS> {
} }
} }
impl Display for FullPageDualProbeResults { impl<'a> Display for FullPageDualProbeResults<'a> {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
let mut indices = vec![None; self.single_probe_results.len()]; let mut indices = vec![None; self.single_probe_results.len()];
let pat_len = self.pattern.len(); let pat_len = self.pattern.len();
let divider = (self.single_probe_results.len() * self.num_iteration as usize) as f32; let divider = (self.single_probe_results.len() * self.num_iteration as usize) as f32;
for (i, &offset) in self.pattern.iter().enumerate() { for (i, access) in self.pattern.iter().enumerate() {
indices[offset] = Some(i); indices[access.offset] = Some(i);
} }
// Display header // Display header
let mut r = writeln!( let mut r = writeln!(
@ -529,3 +536,13 @@ pub fn reference_patterns() -> [(&'static str, Vec<usize>); 9] {
("Pattern 5 (IV)", vec![0, 1, 2, 63, 62, 61, 19]), ("Pattern 5 (IV)", vec![0, 1, 2, 63, 62, 61, 19]),
] ]
} }
pub fn pattern_helper<'a>(offsets: Vec<usize>, function: &'a Function) -> Vec<PatternAccess<'a>> {
offsets
.into_iter()
.map(|i| PatternAccess {
function,
offset: i,
})
.collect()
}

View File

@ -10,7 +10,10 @@ use cache_utils::mmap;
use cache_utils::mmap::MMappedMemory; use cache_utils::mmap::MMappedMemory;
use flush_flush::{FFHandle, FFPrimitives, FlushAndFlush}; use flush_flush::{FFHandle, FFPrimitives, FlushAndFlush};
use nix::Error; use nix::Error;
use prefetcher_reverse::{Prober, CACHE_LINE_LEN, PAGE_CACHELINE_LEN}; use prefetcher_reverse::ip_tool::{Function, TIMED_MACCESS};
use prefetcher_reverse::{
pattern_helper, PatternAccess, Prober, CACHE_LINE_LEN, PAGE_CACHELINE_LEN,
};
use rand::seq::SliceRandom; use rand::seq::SliceRandom;
use std::iter::Cycle; use std::iter::Cycle;
@ -196,8 +199,10 @@ fn main() {
} }
}*/ }*/
let pattern = generate_pattern(0, 3, 12).unwrap(); let reload = Function::try_new(1, 0, TIMED_MACCESS).unwrap();
let pattern4 = generate_pattern(0, 4, 12).unwrap();
let pattern = pattern_helper(generate_pattern(0, 3, 12).unwrap(), &reload);
let pattern4 = pattern_helper(generate_pattern(0, 4, 12).unwrap(), &reload);
let mut new_prober = Prober::<1>::new(63).unwrap(); let mut new_prober = Prober::<1>::new(63).unwrap();
let result = new_prober.full_page_probe(pattern.clone(), NUM_ITERATION as u32, 100); let result = new_prober.full_page_probe(pattern.clone(), NUM_ITERATION as u32, 100);
println!("{}", result); println!("{}", result);
@ -207,27 +212,27 @@ fn main() {
println!("{}", result2); println!("{}", result2);
let result4 = new_prober.full_page_probe(pattern4, NUM_ITERATION as u32, 100); let result4 = new_prober.full_page_probe(pattern4, NUM_ITERATION as u32, 100);
println!("{}", result4); println!("{}", result4);
let pattern5 = generate_pattern(0, 5, 8).unwrap(); let pattern5 = pattern_helper(generate_pattern(0, 5, 8).unwrap(), &reload);
let result5 = new_prober.full_page_probe(pattern5, NUM_ITERATION as u32, 100); let result5 = new_prober.full_page_probe(pattern5, NUM_ITERATION as u32, 100);
println!("{}", result5); println!("{}", result5);
let pattern5 = generate_pattern(0, 5, 4).unwrap(); let pattern5 = pattern_helper(generate_pattern(0, 5, 4).unwrap(), &reload);
let result5 = new_prober.full_page_probe(pattern5, NUM_ITERATION as u32, 100); let result5 = new_prober.full_page_probe(pattern5, NUM_ITERATION as u32, 100);
println!("{}", result5); println!("{}", result5);
let pattern = generate_pattern(0, 10, 4).unwrap(); let pattern = pattern_helper(generate_pattern(0, 10, 4).unwrap(), &reload);
let result = new_prober.full_page_probe(pattern, NUM_ITERATION as u32, 100); let result = new_prober.full_page_probe(pattern, NUM_ITERATION as u32, 100);
println!("{}", result); println!("{}", result);
let pattern = generate_pattern(0, 6, 8).unwrap(); let pattern = pattern_helper(generate_pattern(0, 6, 8).unwrap(), &reload);
let result = new_prober.full_page_probe(pattern, NUM_ITERATION as u32, 100); let result = new_prober.full_page_probe(pattern, NUM_ITERATION as u32, 100);
println!("{}", result); println!("{}", result);
let pattern = generate_pattern(2, 6, 0).unwrap(); let pattern = pattern_helper(generate_pattern(2, 6, 0).unwrap(), &reload);
let result = new_prober.full_page_probe(pattern, NUM_ITERATION as u32, 100); let result = new_prober.full_page_probe(pattern, NUM_ITERATION as u32, 100);
println!("{}", result); println!("{}", result);
let pattern = vec![0, 0, 8, 8, 16, 16, 24, 24]; let pattern = pattern_helper(vec![0, 0, 8, 8, 16, 16, 24, 24], &reload);
let result = new_prober.full_page_probe(pattern, NUM_ITERATION as u32, 100); let result = new_prober.full_page_probe(pattern, NUM_ITERATION as u32, 100);
println!("{}", result); println!("{}", result);