#[inline(always)]
pub fn prefetch_read<T>(ptr: *const T) {
#[cfg(target_arch = "x86_64")]
{
unsafe {
core::arch::x86_64::_mm_prefetch(ptr as *const i8, core::arch::x86_64::_MM_HINT_T0);
}
}
#[cfg(not(target_arch = "x86_64"))]
{
let _ = ptr; }
}
#[inline(always)]
pub fn prefetch_write<T>(ptr: *const T) {
#[cfg(target_arch = "x86_64")]
{
unsafe {
core::arch::x86_64::_mm_prefetch(ptr as *const i8, core::arch::x86_64::_MM_HINT_T0);
}
}
#[cfg(not(target_arch = "x86_64"))]
{
let _ = ptr; }
}
pub fn prefetch_range_read<T>(ptr: *const T, bytes: usize) {
const CACHE_LINE_SIZE: usize = 64;
let start = ptr as usize;
let end = start.saturating_add(bytes);
let mut addr = start & !(CACHE_LINE_SIZE - 1); while addr < end {
prefetch_read(addr as *const u8);
match addr.checked_add(CACHE_LINE_SIZE) {
Some(next) => addr = next,
None => break,
}
}
}
pub fn prefetch_slice_read<T>(slice: &[T]) {
if !slice.is_empty() {
let bytes = core::mem::size_of_val(slice);
prefetch_range_read(slice.as_ptr(), bytes);
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_prefetch_slice() {
let data = vec![1, 2, 3, 4, 5];
prefetch_slice_read(&data);
let empty: &[i32] = &[];
prefetch_slice_read(empty);
}
#[test]
fn test_prefetch_functions() {
let data = 42;
let ptr = &data as *const i32;
prefetch_read(ptr);
prefetch_write(ptr);
prefetch_range_read(ptr, 4);
}
}