dendrobates-t-azureus/cache_slice/src/lib.rs

138 lines
3.7 KiB
Rust
Raw Normal View History

2024-06-24 15:53:45 +02:00
#![deny(unsafe_op_in_unsafe_fn)]
use std::arch::x86_64::_mm_clflush;
use crate::arch::CpuClass::{IntelCore, IntelXeon, IntelXeonSP};
use crate::arch::{get_performance_counters_core, get_performance_counters_xeon};
2024-06-24 15:53:45 +02:00
use crate::Error::UnsupportedCPU;
use crate::msr::{read_msr_on_cpu, write_msr_on_cpu};
pub mod msr;
2024-06-24 15:53:45 +02:00
pub mod utils;
mod arch;
#[derive(Debug)]
2024-06-24 15:53:45 +02:00
pub enum Error {
UnsupportedCPU,
InvalidParameter,
IO(std::io::Error),
}
impl From<std::io::Error> for Error {
fn from(value: std::io::Error) -> Self {
Error::IO(value)
}
}
const NUM_POKE: usize = 10000;
unsafe fn poke(addr: *const u8) {
for _i in 0..NUM_POKE {
unsafe { _mm_clflush(addr) };
}
}
unsafe fn monitor_xeon(addr: *const u8, cpu: u8, max_cbox: usize) -> Result<Vec<u64>, Error> {
2024-06-24 15:53:45 +02:00
let performance_counters = if let Some(p) = get_performance_counters_xeon() {
p
} else {
return Err(UnsupportedCPU);
};
if (performance_counters.max_slice as usize) < max_cbox {
return Err(Error::InvalidParameter);
}
// Freeze counters
for i in 0..max_cbox {
write_msr_on_cpu(performance_counters.msr_pmon_ctr0[i], cpu, performance_counters.val_box_freeze)?;
}
// Reset counters
for i in 0..max_cbox {
2024-06-24 17:37:14 +02:00
write_msr_on_cpu(performance_counters.msr_pmon_box_ctl[i], cpu, performance_counters.val_box_reset)?;
2024-06-24 15:53:45 +02:00
}
// Enable counting
for i in 0..max_cbox {
write_msr_on_cpu(performance_counters.msr_pmon_ctl0[i], cpu, performance_counters.val_enable_counting)?;
}
// Select event
for i in 0..max_cbox {
write_msr_on_cpu(performance_counters.msr_pmon_ctl0[i], cpu, performance_counters.val_select_event)?;
write_msr_on_cpu(performance_counters.msr_pmon_box_filter[i], cpu, performance_counters.val_filter)?;
}
2024-06-24 15:53:45 +02:00
// Unfreeze
for i in 0..max_cbox {
write_msr_on_cpu(performance_counters.msr_pmon_box_ctl[i], cpu, performance_counters.val_box_unfreeze)?;
}
unsafe { poke(addr) };
// Freeze counters
for i in 0..max_cbox {
2024-06-24 17:37:14 +02:00
write_msr_on_cpu(performance_counters.msr_pmon_box_ctl[i], cpu, performance_counters.val_box_freeze)?;
2024-06-24 15:53:45 +02:00
}
// Read counters
let mut results = Vec::new();
2024-06-24 15:53:45 +02:00
for i in 0..max_cbox {
let result = read_msr_on_cpu(performance_counters.msr_pmon_ctr0[i], cpu)?;
2024-06-24 17:37:14 +02:00
if (result - NUM_POKE as u64) < 0 {
results.push(0);
} else {
results.push(result - NUM_POKE as u64);
}
2024-06-24 15:53:45 +02:00
}
Ok(results)
2024-06-24 15:53:45 +02:00
}
fn monitor_core(addr: *const u8, cpu: u8, max_cbox: usize) -> Result<Vec<u64>, Error> {
2024-06-24 15:53:45 +02:00
// Note, we need to add the workaround for one missing perf counter here.
let performance_counters = if let Some(p) = get_performance_counters_core() {
p
} else {
return Err(UnsupportedCPU);
};
let workaround = if (performance_counters.max_slice as usize) + 1 == max_cbox {
true
} else if (performance_counters.max_slice as usize) >= max_cbox {
false
} else {
return Err(Error::InvalidParameter);
};
2024-06-24 15:53:45 +02:00
unimplemented!()
}
pub unsafe fn monitor_address(addr: *const u8, cpu: u8, max_cbox: u16) -> Result<Vec<u64>, Error> {
2024-06-24 15:53:45 +02:00
match arch::determine_cpu_class() {
Some(IntelCore) => {
unsafe { monitor_core(addr, cpu, max_cbox as usize) }
2024-06-24 15:53:45 +02:00
}
Some(IntelXeon) => {
unsafe { monitor_xeon(addr, cpu, max_cbox as usize) }
}
Some(IntelXeonSP) => { // TODO
Err(UnsupportedCPU)
}
None => {
Err(UnsupportedCPU)
}
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn it_works() {
2024-06-24 15:53:45 +02:00
let result = 2;
assert_eq!(result, 2);
}
}