use crate::cuda_ffi::{self, AllocationProp, MemGenericAllocationHandle};
use crate::error::{Result, VmmError};
use candle_core::{Device, DeviceLocation};
fn get_device_ordinal(device: &Device) -> Result<i32> {
match device.location() {
DeviceLocation::Cuda { gpu_id } => Ok(gpu_id as i32),
_ => Err(VmmError::other("Device must be a CUDA device")),
}
}
pub struct PhysicalMemoryHandle {
handle: MemGenericAllocationHandle,
size: usize,
device_ordinal: i32,
}
impl PhysicalMemoryHandle {
pub fn new(size: usize, device: &Device) -> Result<Self> {
let device_ordinal = get_device_ordinal(device)?;
let granularity = cuda_ffi::get_recommended_granularity(device_ordinal)?;
if size % granularity != 0 {
return Err(VmmError::InvalidAlignment {
actual: size,
required: granularity,
});
}
let prop = AllocationProp::device(device_ordinal);
let handle = unsafe { cuda_ffi::mem_create(size, &prop)? };
Ok(Self {
handle,
size,
device_ordinal,
})
}
pub unsafe fn from_raw(
handle: MemGenericAllocationHandle,
size: usize,
device_ordinal: i32,
) -> Self {
Self {
handle,
size,
device_ordinal,
}
}
pub fn size(&self) -> usize {
self.size
}
pub fn device_ordinal(&self) -> i32 {
self.device_ordinal
}
pub fn as_raw(&self) -> MemGenericAllocationHandle {
self.handle
}
pub fn into_raw(self) -> MemGenericAllocationHandle {
let handle = self.handle;
std::mem::forget(self); handle
}
}
impl Drop for PhysicalMemoryHandle {
fn drop(&mut self) {
unsafe {
if let Err(e) = cuda_ffi::mem_release(self.handle) {
eprintln!("Warning: Failed to release physical memory: {}", e);
}
}
}
}
unsafe impl Send for PhysicalMemoryHandle {}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_physical_memory_handle_properties() {
let handle = unsafe { PhysicalMemoryHandle::from_raw(12345, 2 * 1024 * 1024, 0) };
assert_eq!(handle.size(), 2 * 1024 * 1024);
assert_eq!(handle.device_ordinal(), 0);
assert_eq!(handle.as_raw(), 12345);
std::mem::forget(handle);
}
}