use crate::unified::{DeviceId, UnifiedBuffer, UnifiedError};
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum Advice {
ReadMostly,
PreferredLocation(DeviceId),
AccessedBy(DeviceId),
UnsetPreferredLocation,
UnsetAccessedBy(DeviceId),
}
impl Advice {
pub fn name(&self) -> &'static str {
match self {
Advice::ReadMostly => "read_mostly",
Advice::PreferredLocation(_) => "preferred_location",
Advice::AccessedBy(_) => "accessed_by",
Advice::UnsetPreferredLocation => "unset_preferred_location",
Advice::UnsetAccessedBy(_) => "unset_accessed_by",
}
}
}
pub fn apply(_buffer: &UnifiedBuffer, _advice: Advice) -> Result<(), UnifiedError> {
#[cfg(feature = "unified-memory")]
{
apply_cuda(_buffer, _advice)
}
#[cfg(not(feature = "unified-memory"))]
{
Ok(())
}
}
#[cfg(feature = "unified-memory")]
fn apply_cuda(buffer: &UnifiedBuffer, advice: Advice) -> Result<(), UnifiedError> {
use cust::sys as cuda_sys;
let ptr = buffer.as_ptr() as cuda_sys::CUdeviceptr;
let size = buffer.len();
let (advice_kind, device) = match advice {
Advice::ReadMostly => (cuda_sys::CUmem_advise::CU_MEM_ADVISE_SET_READ_MOSTLY, 0i32),
Advice::PreferredLocation(d) => (
cuda_sys::CUmem_advise::CU_MEM_ADVISE_SET_PREFERRED_LOCATION,
d.0 as i32,
),
Advice::AccessedBy(d) => (
cuda_sys::CUmem_advise::CU_MEM_ADVISE_SET_ACCESSED_BY,
d.0 as i32,
),
Advice::UnsetPreferredLocation => (
cuda_sys::CUmem_advise::CU_MEM_ADVISE_UNSET_PREFERRED_LOCATION,
0i32,
),
Advice::UnsetAccessedBy(d) => (
cuda_sys::CUmem_advise::CU_MEM_ADVISE_UNSET_ACCESSED_BY,
d.0 as i32,
),
};
let res = unsafe { cuda_sys::cuMemAdvise(ptr, size, advice_kind, device) };
if res == cuda_sys::CUresult::CUDA_SUCCESS {
Ok(())
} else {
Err(UnifiedError::Cuda(format!("cuMemAdvise -> {res:?}")))
}
}
pub fn set_read_mostly(buffer: &UnifiedBuffer) -> Result<(), UnifiedError> {
apply(buffer, Advice::ReadMostly)
}
pub fn set_preferred_location(
buffer: &UnifiedBuffer,
device_id: DeviceId,
) -> Result<(), UnifiedError> {
apply(buffer, Advice::PreferredLocation(device_id))
}
pub fn set_accessed_by(buffer: &UnifiedBuffer, device_id: DeviceId) -> Result<(), UnifiedError> {
apply(buffer, Advice::AccessedBy(device_id))
}
#[cfg(test)]
mod tests {
use super::*;
use crate::unified::UnifiedBuffer;
#[test]
fn names_are_stable() {
assert_eq!(Advice::ReadMostly.name(), "read_mostly");
assert_eq!(
Advice::PreferredLocation(DeviceId(0)).name(),
"preferred_location"
);
assert_eq!(Advice::AccessedBy(DeviceId(0)).name(), "accessed_by");
assert_eq!(
Advice::UnsetPreferredLocation.name(),
"unset_preferred_location"
);
assert_eq!(
Advice::UnsetAccessedBy(DeviceId(0)).name(),
"unset_accessed_by"
);
}
#[test]
fn apply_no_op_without_cuda() {
let b = UnifiedBuffer::new(64).unwrap();
apply(&b, Advice::ReadMostly).expect("no-op should succeed");
set_read_mostly(&b).expect("convenience helper should also succeed");
set_preferred_location(&b, DeviceId(0)).expect("set_preferred_location");
set_accessed_by(&b, DeviceId(1)).expect("set_accessed_by");
}
#[test]
fn advice_is_copy_and_eq() {
let a = Advice::AccessedBy(DeviceId(2));
let b = a;
assert_eq!(a, b);
}
}