Implement calibration on full 4k page

This commit is contained in:
guillaume didier 2020-02-28 12:03:51 +01:00
parent 2ce9de1482
commit 60fe76e366
5 changed files with 126 additions and 68 deletions

7
Cargo.lock generated
View File

@ -1,5 +1,10 @@
# This file is automatically @generated by Cargo.
# It is not intended for manual editing.
[[package]]
name = "arrayref"
version = "0.3.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "bit_field"
version = "0.9.0"
@ -36,6 +41,7 @@ dependencies = [
name = "dendrobates_tinctoreus_azureus"
version = "0.1.0"
dependencies = [
"arrayref 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)",
"bootloader 0.8.6 (registry+https://github.com/rust-lang/crates.io-index)",
"cache_utils 0.1.0",
"lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
@ -121,6 +127,7 @@ dependencies = [
]
[metadata]
"checksum arrayref 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)" = "a4c527152e37cf757a3f78aae5a06fbeefdb07ccc535c980a3208ee3060dd544"
"checksum bit_field 0.10.0 (registry+https://github.com/rust-lang/crates.io-index)" = "a165d606cf084741d4ac3a28fb6e9b1eb0bd31f6cd999098cfddb0b2ab381dc0"
"checksum bit_field 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ed8765909f9009617974ab6b7d332625b320b33c326b1e9321382ef1999b5d56"
"checksum bitflags 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "cf1de2fe8c75bc145a2f577add951f8134889b4795d47466a54a5c846d691693"

View File

@ -30,6 +30,7 @@ polling_serial = { path = "polling_serial" }
volatile = "0.2.6"
linked_list_allocator = "0.7.0"
cache_utils = { path = "cache_utils" }
arrayref = "0.3.6"
[dependencies.lazy_static]
version = "1.4.0"

View File

@ -45,15 +45,15 @@ pub unsafe fn only_flush(p: *const u8) -> u64 {
const BUCKET_SIZE: usize = 5;
const BUCKET_NUMBER: usize = 250;
pub fn calibrate_access() -> u64 {
pub fn calibrate_access(array: &[u8; 4096]) -> u64 {
serial_println!("Calibrating...");
// Allocate a target array
// TBD why size, why the position in the array, why the type (usize)
let mut array = Vec::<usize>::with_capacity(5 << 10);
array.resize(5 << 10, 1);
// let mut array = Vec::<usize>::with_capacity(5 << 10);
// array.resize(5 << 10, 1);
let array = array.into_boxed_slice();
// let array = array.into_boxed_slice();
// Histograms bucket of 5 and max at 400 cycles
// Magic numbers to be justified
@ -64,20 +64,30 @@ pub fn calibrate_access() -> u64 {
let mut miss_histogram = hit_histogram.clone();
// the address in memory we are going to target
let pointer = (&array[2048] as *const usize) as *const u8;
let pointer = &array[0] as *const u8;
serial_println!("buffer start {:p}", pointer);
if pointer as usize & 0x3f != 0 {
panic!("not aligned nicely");
}
// do a large sample of accesses to a cached line
unsafe { maccess(pointer) };
for _ in 0..(4 << 20) {
let d = unsafe { only_reload(pointer) } as usize;
hit_histogram[min(BUCKET_NUMBER - 1, d / BUCKET_SIZE) as usize] += 1;
for i in 0..(4 << 10) {
for _ in 0..(1 << 10) {
let d = unsafe { only_reload(pointer.offset(i & (!0x3f))) } as usize;
hit_histogram[min(BUCKET_NUMBER - 1, d / BUCKET_SIZE) as usize] += 1;
}
}
// do a large numer of accesses to uncached line
unsafe { flush(pointer) };
for _ in 0..(4 << 20) {
let d = unsafe { flush_and_reload(pointer) } as usize;
miss_histogram[min(BUCKET_NUMBER - 1, d / BUCKET_SIZE) as usize] += 1;
for i in 0..(4 << 10) {
for _ in 0..(1 << 10) {
let d = unsafe { flush_and_reload(pointer.offset(i & (!0x3f))) } as usize;
miss_histogram[min(BUCKET_NUMBER - 1, d / BUCKET_SIZE) as usize] += 1;
}
}
let mut hit_max = 0;
@ -118,66 +128,76 @@ pub fn calibrate_access() -> u64 {
const CFLUSH_BUCKET_SIZE: usize = 1;
const CFLUSH_BUCKET_NUMBER: usize = 250;
pub fn calibrate_flush() -> u64 {
pub fn calibrate_flush(array: &[u8; 4096]) -> u64 {
serial_println!("Calibrating cflush...");
// Allocate a target array
// TBD why size, why the position in the array, why the type (usize)
let mut array = Vec::<usize>::with_capacity(5 << 10);
array.resize(5 << 10, 1);
//let mut array = Vec::<usize>::with_capacity(5 << 10);
//array.resize(5 << 10, 1);
let array = array.into_boxed_slice();
//let array = array.into_boxed_slice();
// Histograms bucket of 5 and max at 400 cycles
// Magic numbers to be justified
// 80 is a size of screen
let mut hit_histogram = vec![0; CFLUSH_BUCKET_NUMBER];
let mut miss_histogram = hit_histogram.clone();
// the address in memory we are going to target
let pointer = (&array[2048] as *const usize) as *const u8;
let pointer = (&array[0]) as *const u8;
if pointer as usize & 0x3f != 0 {
panic!("not aligned nicely");
}
// do a large sample of accesses to a cached line
for _ in 0..(4 << 20) {
let d = unsafe { load_and_flush(pointer) } as usize;
hit_histogram[min(CFLUSH_BUCKET_NUMBER - 1, d / CFLUSH_BUCKET_SIZE) as usize] += 1;
}
for i in 0..(4 << 10) {
let mut hit_histogram = vec![0; CFLUSH_BUCKET_NUMBER];
// do a large numer of accesses to uncached line
unsafe { flush(pointer) };
for _ in 0..(4 << 20) {
let d = unsafe { flush_and_flush(pointer) } as usize;
miss_histogram[min(CFLUSH_BUCKET_NUMBER - 1, d / CFLUSH_BUCKET_SIZE) as usize] += 1;
}
let mut hit_max: (usize, u32) = (0, 0);
let mut miss_max: (usize, u32) = (0, 0);
for i in 0..hit_histogram.len() {
serial_println!(
"{:3}: {:10} {:10}",
i * CFLUSH_BUCKET_SIZE,
hit_histogram[i],
miss_histogram[i]
);
if hit_max.1 < hit_histogram[i] {
hit_max = (i, hit_histogram[i]);
let mut miss_histogram = hit_histogram.clone();
serial_println!("Calibration for {:p}", unsafe { pointer.offset(i) });
unsafe { load_and_flush(pointer.offset(i)) }; // align down on 64 bytes
for _ in 1..(1 << 10) {
let d = unsafe { load_and_flush(pointer.offset(i)) } as usize;
hit_histogram[min(CFLUSH_BUCKET_NUMBER - 1, d / CFLUSH_BUCKET_SIZE) as usize] += 1;
}
if miss_max.1 < miss_histogram[i] {
miss_max = (i, miss_histogram[i]);
}
}
serial_println!("Miss max {}", miss_max.0 * CFLUSH_BUCKET_SIZE);
serial_println!("Max hit {}", hit_max.0 * CFLUSH_BUCKET_SIZE);
let mut threshold: (usize, u32) = (0, u32::max_value());
for i in miss_max.0..hit_max.0 {
if hit_histogram[i] + miss_histogram[i] < threshold.1 {
threshold = (i, hit_histogram[i] + miss_histogram[i]);
}
}
serial_println!("Threshold {}", threshold.0 * CFLUSH_BUCKET_SIZE);
serial_println!("Calibration done.");
(threshold.0 * CFLUSH_BUCKET_SIZE) as u64
// do a large numer of accesses to uncached line
unsafe { flush(pointer.offset(i)) };
unsafe { load_and_flush(pointer.offset(i)) };
for _ in 0..(1 << 10) {
let d = unsafe { flush_and_flush(pointer.offset(i)) } as usize;
miss_histogram[min(CFLUSH_BUCKET_NUMBER - 1, d / CFLUSH_BUCKET_SIZE) as usize] += 1;
}
let mut hit_max: (usize, u32) = (0, 0);
let mut miss_max: (usize, u32) = (0, 0);
for i in 0..hit_histogram.len() {
serial_println!(
"{:3}: {:10} {:10}",
i * CFLUSH_BUCKET_SIZE,
hit_histogram[i],
miss_histogram[i]
);
if hit_max.1 < hit_histogram[i] {
hit_max = (i, hit_histogram[i]);
}
if miss_max.1 < miss_histogram[i] {
miss_max = (i, miss_histogram[i]);
}
}
serial_println!("Miss max {}", miss_max.0 * CFLUSH_BUCKET_SIZE);
serial_println!("Max hit {}", hit_max.0 * CFLUSH_BUCKET_SIZE);
let mut threshold: (usize, u32) = (0, u32::max_value());
for i in miss_max.0..hit_max.0 {
if hit_histogram[i] + miss_histogram[i] < threshold.1 {
threshold = (i, hit_histogram[i] + miss_histogram[i]);
}
}
serial_println!("Threshold {}", threshold.0 * CFLUSH_BUCKET_SIZE);
serial_println!("Calibration done.");
}
//(threshold.0 * CFLUSH_BUCKET_SIZE) as u64
0
}

View File

@ -28,13 +28,17 @@ pub fn enable_prefetchers(status: bool) {
unsafe { msr.write(value) };
}
pub fn prefetcher_fun(victim4kaddr: *mut u8, victim2Maddr: *mut u8, threshold_ff: u64) -> Vec<i32> {
pub fn prefetcher_fun(
victim4k_addr: *mut u8,
victim2M_addr: *mut u8,
threshold_ff: u64,
) -> Vec<i32> {
let mut results = vec![0; 4096 / 64];
for _ in 0..N {
//unsafe { maccess(victim4kaddr) };
for j in (0..4096).step_by(64).rev() {
let t = unsafe { only_flush(victim4kaddr.offset(j)) };
let t = unsafe { only_flush(victim4k_addr.offset(j)) };
if threshold_ff < t {
// hit
results[(j / 64) as usize] += 1;

View File

@ -34,6 +34,8 @@ use x86_64::structures::paging::{
use x86_64::PhysAddr;
use x86_64::VirtAddr;
use arrayref;
// Custom panic handler, required for freestanding program
#[cfg(not(test))]
#[panic_handler]
@ -79,9 +81,9 @@ fn kernel_main(boot_info: &'static BootInfo) -> ! {
let mut victim = None;
for region in boot_info.memory_map.iter() {
if region.region_type == Usable {
/*if region.region_type == Usable {
serial_println!("Usable Region: {:?}", region);
}
}*/
let new_region = {
if victim.is_none()
&& region.region_type == Usable
@ -171,7 +173,7 @@ fn kernel_main(boot_info: &'static BootInfo) -> ! {
end: PhysFrame::containing_address(PhysAddr::new(victim.range.end_addr())),
})
{
serial_println!("Mapping page {:x} on frame {:?}", page, frame);
//serial_println!("Mapping page {:x} on frame {:?}", page, frame);
mapper
.map_to(
Page::<Size4KiB>::containing_address(VirtAddr::new(page)),
@ -182,12 +184,12 @@ fn kernel_main(boot_info: &'static BootInfo) -> ! {
.expect("Failed to map the experiment buffer")
.flush();
let phys = mapper.translate_addr(VirtAddr::new(page));
serial_println!(
/*serial_println!(
"Mapped page {:p}({:?}) on frame {:?}",
page as *mut u8,
VirtAddr::new(page),
phys
);
);*/
unsafe { maccess(page as *mut u8) };
}
@ -205,12 +207,36 @@ fn kernel_main(boot_info: &'static BootInfo) -> ! {
cache_utils::prefetcher::prefetcher_status()
);
let threshold_access_p = cache_utils::calibration::calibrate_access();
let threshold_flush_p = cache_utils::calibration::calibrate_flush();
let threshold_access_p = cache_utils::calibration::calibrate_access(unsafe {
arrayref::array_ref![
core::slice::from_raw_parts(victim4k_start as *mut u8, 4096),
0,
4096
]
});
let threshold_flush_p = cache_utils::calibration::calibrate_flush(unsafe {
arrayref::array_ref![
core::slice::from_raw_parts(victim4k_start as *mut u8, 4096),
0,
4096
]
});
cache_utils::prefetcher::enable_prefetchers(false);
serial_println!("Prefetcher disabled");
let threshold_access = cache_utils::calibration::calibrate_access();
let threshold_flush = cache_utils::calibration::calibrate_flush();
let threshold_access = cache_utils::calibration::calibrate_access(unsafe {
arrayref::array_ref![
core::slice::from_raw_parts(victim4k_start as *mut u8, 4096),
0,
4096
]
});
let threshold_flush = cache_utils::calibration::calibrate_flush(unsafe {
arrayref::array_ref![
core::slice::from_raw_parts(victim4k_start as *mut u8, 4096),
0,
4096
]
});
serial_println!("Please compare histograms for sanity");
if distance(threshold_access_p, threshold_access) > 10