use std::fmt;
use crate::error::{CudaError, CudaResult};
use crate::ffi::CUdeviceptr;
pub const CU_MEMPOOL_ATTR_REUSE_FOLLOW_EVENT_DEPENDENCIES: u32 = 1;
pub const CU_MEMPOOL_ATTR_REUSE_ALLOW_OPPORTUNISTIC: u32 = 2;
pub const CU_MEMPOOL_ATTR_REUSE_ALLOW_INTERNAL_DEPENDENCIES: u32 = 3;
pub const CU_MEMPOOL_ATTR_RELEASE_THRESHOLD: u32 = 4;
pub const CU_MEMPOOL_ATTR_RESERVED_MEM_CURRENT: u32 = 5;
pub const CU_MEMPOOL_ATTR_RESERVED_MEM_HIGH: u32 = 6;
pub const CU_MEMPOOL_ATTR_USED_MEM_CURRENT: u32 = 7;
pub const CU_MEMPOOL_ATTR_USED_MEM_HIGH: u32 = 8;
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct StreamOrderedAllocConfig {
pub initial_pool_size: usize,
pub max_pool_size: usize,
pub release_threshold: usize,
pub device: i32,
}
impl StreamOrderedAllocConfig {
pub fn validate(&self) -> CudaResult<()> {
if self.device < 0 {
return Err(CudaError::InvalidValue);
}
if self.max_pool_size > 0 {
if self.initial_pool_size > self.max_pool_size {
return Err(CudaError::InvalidValue);
}
if self.release_threshold > self.max_pool_size {
return Err(CudaError::InvalidValue);
}
}
Ok(())
}
pub fn default_for_device(device: i32) -> Self {
Self {
initial_pool_size: 0,
max_pool_size: 0,
release_threshold: 0,
device,
}
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum PoolAttribute {
ReuseFollowEventDependencies,
ReuseAllowOpportunistic,
ReuseAllowInternalDependencies,
ReleaseThreshold(u64),
ReservedMemCurrent,
ReservedMemHigh,
UsedMemCurrent,
UsedMemHigh,
}
impl PoolAttribute {
pub fn to_raw(self) -> u32 {
match self {
Self::ReuseFollowEventDependencies => CU_MEMPOOL_ATTR_REUSE_FOLLOW_EVENT_DEPENDENCIES,
Self::ReuseAllowOpportunistic => CU_MEMPOOL_ATTR_REUSE_ALLOW_OPPORTUNISTIC,
Self::ReuseAllowInternalDependencies => {
CU_MEMPOOL_ATTR_REUSE_ALLOW_INTERNAL_DEPENDENCIES
}
Self::ReleaseThreshold(_) => CU_MEMPOOL_ATTR_RELEASE_THRESHOLD,
Self::ReservedMemCurrent => CU_MEMPOOL_ATTR_RESERVED_MEM_CURRENT,
Self::ReservedMemHigh => CU_MEMPOOL_ATTR_RESERVED_MEM_HIGH,
Self::UsedMemCurrent => CU_MEMPOOL_ATTR_USED_MEM_CURRENT,
Self::UsedMemHigh => CU_MEMPOOL_ATTR_USED_MEM_HIGH,
}
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
pub struct PoolUsageStats {
pub reserved_current: u64,
pub reserved_high: u64,
pub used_current: u64,
pub used_high: u64,
pub active_allocations: usize,
pub peak_allocations: usize,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
pub enum ShareableHandleType {
#[default]
None,
PosixFileDescriptor,
Win32Handle,
Win32KmtHandle,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct PoolExportDescriptor {
pub shareable_handle_type: ShareableHandleType,
pub pool_device: i32,
}
pub struct StreamAllocation {
ptr: CUdeviceptr,
size: usize,
stream: u64,
pool: u64,
freed: bool,
}
impl StreamAllocation {
#[inline]
pub fn as_ptr(&self) -> u64 {
self.ptr
}
#[inline]
pub fn size(&self) -> usize {
self.size
}
#[inline]
pub fn is_freed(&self) -> bool {
self.freed
}
#[inline]
pub fn stream(&self) -> u64 {
self.stream
}
#[inline]
pub fn pool(&self) -> u64 {
self.pool
}
}
impl fmt::Debug for StreamAllocation {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("StreamAllocation")
.field("ptr", &format_args!("0x{:016x}", self.ptr))
.field("size", &self.size)
.field("stream", &format_args!("0x{:016x}", self.stream))
.field("freed", &self.freed)
.finish()
}
}
pub struct StreamMemoryPool {
handle: u64,
device: i32,
config: StreamOrderedAllocConfig,
active_allocations: usize,
total_allocated: usize,
peak_allocated: usize,
peak_allocation_count: usize,
#[cfg_attr(not(target_os = "macos"), allow(dead_code))]
next_alloc_id: u64,
}
impl fmt::Debug for StreamMemoryPool {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("StreamMemoryPool")
.field("handle", &format_args!("0x{:016x}", self.handle))
.field("device", &self.device)
.field("active_allocations", &self.active_allocations)
.field("total_allocated", &self.total_allocated)
.field("peak_allocated", &self.peak_allocated)
.finish()
}
}
impl StreamMemoryPool {
pub fn new(config: StreamOrderedAllocConfig) -> CudaResult<Self> {
config.validate()?;
let pool = Self {
handle: 0,
device: config.device,
config,
active_allocations: 0,
total_allocated: 0,
peak_allocated: 0,
peak_allocation_count: 0,
next_alloc_id: 1,
};
#[cfg(not(target_os = "macos"))]
{
Self::gpu_create_pool(&pool)?;
}
Ok(pool)
}
pub fn alloc_async(&mut self, size: usize, stream: u64) -> CudaResult<StreamAllocation> {
if size == 0 {
return Err(CudaError::InvalidValue);
}
if self.config.max_pool_size > 0
&& self.total_allocated.saturating_add(size) > self.config.max_pool_size
{
return Err(CudaError::OutOfMemory);
}
let ptr = self.platform_alloc_async(size, stream)?;
self.active_allocations += 1;
self.total_allocated = self.total_allocated.saturating_add(size);
if self.total_allocated > self.peak_allocated {
self.peak_allocated = self.total_allocated;
}
if self.active_allocations > self.peak_allocation_count {
self.peak_allocation_count = self.active_allocations;
}
Ok(StreamAllocation {
ptr,
size,
stream,
pool: self.handle,
freed: false,
})
}
pub fn free_async(&mut self, alloc: &mut StreamAllocation) -> CudaResult<()> {
if alloc.freed {
return Err(CudaError::InvalidValue);
}
self.platform_free_async(alloc)?;
alloc.freed = true;
self.active_allocations = self.active_allocations.saturating_sub(1);
self.total_allocated = self.total_allocated.saturating_sub(alloc.size);
Ok(())
}
pub fn trim(&mut self, min_bytes_to_keep: usize) -> CudaResult<()> {
self.platform_trim(min_bytes_to_keep)
}
pub fn stats(&self) -> PoolUsageStats {
PoolUsageStats {
reserved_current: self.total_allocated as u64,
reserved_high: self.peak_allocated as u64,
used_current: self.total_allocated as u64,
used_high: self.peak_allocated as u64,
active_allocations: self.active_allocations,
peak_allocations: self.peak_allocation_count,
}
}
pub fn set_attribute(&mut self, attr: PoolAttribute) -> CudaResult<()> {
match attr {
PoolAttribute::ReservedMemCurrent
| PoolAttribute::UsedMemCurrent
| PoolAttribute::ReservedMemHigh
| PoolAttribute::UsedMemHigh => {
return Err(CudaError::InvalidValue);
}
_ => {}
}
if let PoolAttribute::ReleaseThreshold(val) = attr {
self.config.release_threshold = val as usize;
}
self.platform_set_attribute(attr)
}
pub fn enable_peer_access(&self, peer_device: i32) -> CudaResult<()> {
if peer_device == self.device {
return Err(CudaError::InvalidDevice);
}
self.platform_enable_peer_access(peer_device)
}
pub fn disable_peer_access(&self, peer_device: i32) -> CudaResult<()> {
if peer_device == self.device {
return Err(CudaError::InvalidDevice);
}
self.platform_disable_peer_access(peer_device)
}
pub fn reset_peak_stats(&mut self) {
self.peak_allocated = self.total_allocated;
self.peak_allocation_count = self.active_allocations;
}
pub fn default_pool(device: i32) -> CudaResult<Self> {
if device < 0 {
return Err(CudaError::InvalidValue);
}
let config = StreamOrderedAllocConfig::default_for_device(device);
Self::new(config)
}
#[inline]
pub fn handle(&self) -> u64 {
self.handle
}
#[inline]
pub fn device(&self) -> i32 {
self.device
}
#[inline]
pub fn config(&self) -> &StreamOrderedAllocConfig {
&self.config
}
fn platform_alloc_async(&mut self, size: usize, stream: u64) -> CudaResult<CUdeviceptr> {
#[cfg(target_os = "macos")]
{
let _ = stream;
let synthetic_ptr = 0x1000_0000_0000_u64 + self.next_alloc_id * 0x1000;
self.next_alloc_id = self.next_alloc_id.wrapping_add(1);
let _ = size;
Ok(synthetic_ptr)
}
#[cfg(not(target_os = "macos"))]
{
Self::gpu_alloc_async(self.handle, size, stream)
}
}
fn platform_trim(&mut self, min_bytes_to_keep: usize) -> CudaResult<()> {
#[cfg(target_os = "macos")]
{
let _ = min_bytes_to_keep;
Err(CudaError::NotSupported)
}
#[cfg(not(target_os = "macos"))]
{
Self::gpu_trim(self.handle, min_bytes_to_keep)
}
}
fn platform_set_attribute(&self, attr: PoolAttribute) -> CudaResult<()> {
#[cfg(target_os = "macos")]
{
match attr {
PoolAttribute::ReleaseThreshold(_) => Ok(()),
_ => Err(CudaError::NotSupported),
}
}
#[cfg(not(target_os = "macos"))]
{
Self::gpu_set_attribute(self.handle, attr)
}
}
fn platform_enable_peer_access(&self, peer_device: i32) -> CudaResult<()> {
#[cfg(target_os = "macos")]
{
let _ = peer_device;
Err(CudaError::NotSupported)
}
#[cfg(not(target_os = "macos"))]
{
Self::gpu_enable_peer_access(self.handle, peer_device)
}
}
fn platform_disable_peer_access(&self, peer_device: i32) -> CudaResult<()> {
#[cfg(target_os = "macos")]
{
let _ = peer_device;
Err(CudaError::NotSupported)
}
#[cfg(not(target_os = "macos"))]
{
Self::gpu_disable_peer_access(self.handle, peer_device)
}
}
fn platform_free_async(&self, alloc: &StreamAllocation) -> CudaResult<()> {
#[cfg(target_os = "macos")]
{
let _ = alloc;
Ok(())
}
#[cfg(not(target_os = "macos"))]
{
Self::gpu_free_async(alloc.ptr, alloc.stream)
}
}
#[cfg(not(target_os = "macos"))]
fn gpu_create_pool(_pool: &Self) -> CudaResult<()> {
Ok(())
}
#[cfg(not(target_os = "macos"))]
fn gpu_alloc_async(_pool_handle: u64, _size: usize, _stream: u64) -> CudaResult<CUdeviceptr> {
Err(CudaError::NotInitialized)
}
#[cfg(not(target_os = "macos"))]
fn gpu_free_async(_ptr: CUdeviceptr, _stream: u64) -> CudaResult<()> {
Err(CudaError::NotInitialized)
}
#[cfg(not(target_os = "macos"))]
fn gpu_trim(_pool_handle: u64, _min_bytes_to_keep: usize) -> CudaResult<()> {
Err(CudaError::NotInitialized)
}
#[cfg(not(target_os = "macos"))]
fn gpu_set_attribute(_pool_handle: u64, _attr: PoolAttribute) -> CudaResult<()> {
Err(CudaError::NotInitialized)
}
#[cfg(not(target_os = "macos"))]
fn gpu_enable_peer_access(_pool_handle: u64, _peer_device: i32) -> CudaResult<()> {
Err(CudaError::NotInitialized)
}
#[cfg(not(target_os = "macos"))]
fn gpu_disable_peer_access(_pool_handle: u64, _peer_device: i32) -> CudaResult<()> {
Err(CudaError::NotInitialized)
}
}
pub fn stream_alloc(size: usize, stream: u64) -> CudaResult<StreamAllocation> {
let mut pool = StreamMemoryPool::default_pool(0)?;
pool.alloc_async(size, stream)
}
pub fn stream_free(alloc: &mut StreamAllocation) -> CudaResult<()> {
if alloc.freed {
return Err(CudaError::InvalidValue);
}
#[cfg(target_os = "macos")]
{
alloc.freed = true;
Ok(())
}
#[cfg(not(target_os = "macos"))]
{
StreamMemoryPool::gpu_free_async(alloc.ptr, alloc.stream)?;
alloc.freed = true;
Ok(())
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn config_validate_valid_sizes() {
let config = StreamOrderedAllocConfig {
initial_pool_size: 1024,
max_pool_size: 4096,
release_threshold: 512,
device: 0,
};
assert!(config.validate().is_ok());
}
#[test]
fn config_validate_unlimited_max() {
let config = StreamOrderedAllocConfig {
initial_pool_size: 1024 * 1024,
max_pool_size: 0, release_threshold: 512,
device: 0,
};
assert!(config.validate().is_ok());
}
#[test]
fn config_validate_initial_exceeds_max() {
let config = StreamOrderedAllocConfig {
initial_pool_size: 8192,
max_pool_size: 4096,
release_threshold: 0,
device: 0,
};
assert_eq!(config.validate(), Err(CudaError::InvalidValue));
}
#[test]
fn config_validate_negative_device() {
let config = StreamOrderedAllocConfig {
initial_pool_size: 0,
max_pool_size: 0,
release_threshold: 0,
device: -1,
};
assert_eq!(config.validate(), Err(CudaError::InvalidValue));
}
#[test]
fn config_validate_threshold_exceeds_max() {
let config = StreamOrderedAllocConfig {
initial_pool_size: 0,
max_pool_size: 1024,
release_threshold: 2048,
device: 0,
};
assert_eq!(config.validate(), Err(CudaError::InvalidValue));
}
#[test]
fn default_config_for_device() {
let config = StreamOrderedAllocConfig::default_for_device(2);
assert_eq!(config.device, 2);
assert_eq!(config.initial_pool_size, 0);
assert_eq!(config.max_pool_size, 0);
assert_eq!(config.release_threshold, 0);
assert!(config.validate().is_ok());
}
#[test]
fn pool_creation() {
let config = StreamOrderedAllocConfig::default_for_device(0);
let pool = StreamMemoryPool::new(config);
assert!(pool.is_ok());
let pool = pool.ok();
assert!(pool.is_some());
let pool = pool.map(|p| {
assert_eq!(p.device(), 0);
assert_eq!(p.active_allocations, 0);
assert_eq!(p.total_allocated, 0);
});
let _ = pool;
}
#[test]
fn pool_creation_invalid_config() {
let config = StreamOrderedAllocConfig {
initial_pool_size: 0,
max_pool_size: 0,
release_threshold: 0,
device: -1,
};
let result = StreamMemoryPool::new(config);
assert!(matches!(result, Err(CudaError::InvalidValue)));
}
#[cfg(target_os = "macos")]
#[test]
fn alloc_async_creates_allocation() {
let config = StreamOrderedAllocConfig::default_for_device(0);
let mut pool = StreamMemoryPool::new(config).ok();
assert!(pool.is_some());
let pool = pool.as_mut().map(|p| {
let alloc = p.alloc_async(1024, 0);
assert!(alloc.is_ok());
let alloc = alloc.ok();
assert!(alloc.is_some());
if let Some(a) = &alloc {
assert_eq!(a.size(), 1024);
assert!(!a.is_freed());
assert_ne!(a.as_ptr(), 0);
assert_eq!(a.stream(), 0);
}
});
let _ = pool;
}
#[cfg(target_os = "macos")]
#[test]
fn free_async_marks_freed() {
let config = StreamOrderedAllocConfig::default_for_device(0);
let mut pool =
StreamMemoryPool::new(config).expect("pool creation should succeed on macOS");
let mut alloc = pool
.alloc_async(2048, 0)
.expect("alloc should succeed on macOS");
assert!(!alloc.is_freed());
assert!(pool.free_async(&mut alloc).is_ok());
assert!(alloc.is_freed());
assert_eq!(pool.active_allocations, 0);
}
#[cfg(target_os = "macos")]
#[test]
fn double_free_returns_error() {
let config = StreamOrderedAllocConfig::default_for_device(0);
let mut pool =
StreamMemoryPool::new(config).expect("pool creation should succeed on macOS");
let mut alloc = pool
.alloc_async(512, 0)
.expect("alloc should succeed on macOS");
assert!(pool.free_async(&mut alloc).is_ok());
assert_eq!(pool.free_async(&mut alloc), Err(CudaError::InvalidValue));
}
#[cfg(target_os = "macos")]
#[test]
fn trim_returns_not_supported_on_macos() {
let config = StreamOrderedAllocConfig::default_for_device(0);
let mut pool =
StreamMemoryPool::new(config).expect("pool creation should succeed on macOS");
assert_eq!(pool.trim(0), Err(CudaError::NotSupported));
}
#[cfg(target_os = "macos")]
#[test]
fn stats_tracking() {
let config = StreamOrderedAllocConfig::default_for_device(0);
let mut pool =
StreamMemoryPool::new(config).expect("pool creation should succeed on macOS");
let mut a1 = pool.alloc_async(1024, 0).expect("alloc should succeed");
let _a2 = pool.alloc_async(2048, 0).expect("alloc should succeed");
let stats = pool.stats();
assert_eq!(stats.active_allocations, 2);
assert_eq!(stats.used_current, 3072);
assert_eq!(stats.used_high, 3072);
assert_eq!(stats.peak_allocations, 2);
pool.free_async(&mut a1).expect("free should succeed");
let stats = pool.stats();
assert_eq!(stats.active_allocations, 1);
assert_eq!(stats.used_current, 2048);
assert_eq!(stats.used_high, 3072);
}
#[cfg(target_os = "macos")]
#[test]
fn set_attribute_release_threshold() {
let config = StreamOrderedAllocConfig::default_for_device(0);
let mut pool =
StreamMemoryPool::new(config).expect("pool creation should succeed on macOS");
let result = pool.set_attribute(PoolAttribute::ReleaseThreshold(4096));
assert!(result.is_ok());
assert_eq!(pool.config().release_threshold, 4096);
}
#[test]
fn set_attribute_readonly_returns_error() {
let config = StreamOrderedAllocConfig::default_for_device(0);
let mut pool = StreamMemoryPool::new(config).expect("pool creation should succeed");
assert_eq!(
pool.set_attribute(PoolAttribute::ReservedMemCurrent),
Err(CudaError::InvalidValue)
);
assert_eq!(
pool.set_attribute(PoolAttribute::UsedMemCurrent),
Err(CudaError::InvalidValue)
);
}
#[cfg(target_os = "macos")]
#[test]
fn allocation_accessors() {
let config = StreamOrderedAllocConfig::default_for_device(0);
let mut pool =
StreamMemoryPool::new(config).expect("pool creation should succeed on macOS");
let alloc = pool.alloc_async(4096, 42).expect("alloc should succeed");
assert_eq!(alloc.size(), 4096);
assert_eq!(alloc.stream(), 42);
assert!(!alloc.is_freed());
assert_ne!(alloc.as_ptr(), 0);
let _debug = format!("{alloc:?}");
}
#[cfg(target_os = "macos")]
#[test]
fn convenience_stream_alloc() {
let result = stream_alloc(256, 0);
assert!(result.is_ok());
let alloc = result.expect("should succeed on macOS");
assert_eq!(alloc.size(), 256);
assert!(!alloc.is_freed());
}
#[cfg(target_os = "macos")]
#[test]
fn convenience_stream_free() {
let mut alloc = stream_alloc(128, 0).expect("alloc should succeed on macOS");
assert!(stream_free(&mut alloc).is_ok());
assert!(alloc.is_freed());
assert_eq!(stream_free(&mut alloc), Err(CudaError::InvalidValue));
}
#[cfg(target_os = "macos")]
#[test]
fn large_allocation_size() {
let config = StreamOrderedAllocConfig {
initial_pool_size: 0,
max_pool_size: 0, release_threshold: 0,
device: 0,
};
let mut pool =
StreamMemoryPool::new(config).expect("pool creation should succeed on macOS");
let size = 16 * 1024 * 1024 * 1024_usize;
let alloc = pool.alloc_async(size, 0);
assert!(alloc.is_ok());
let alloc = alloc.expect("should succeed");
assert_eq!(alloc.size(), size);
}
#[cfg(target_os = "macos")]
#[test]
fn alloc_exceeds_max_pool_size() {
let config = StreamOrderedAllocConfig {
initial_pool_size: 0,
max_pool_size: 1024,
release_threshold: 0,
device: 0,
};
let mut pool = StreamMemoryPool::new(config).expect("pool creation should succeed");
assert!(matches!(
pool.alloc_async(2048, 0),
Err(CudaError::OutOfMemory)
));
}
#[test]
fn peer_access_same_device_error() {
let config = StreamOrderedAllocConfig::default_for_device(0);
let pool = StreamMemoryPool::new(config).expect("pool creation should succeed");
assert_eq!(pool.enable_peer_access(0), Err(CudaError::InvalidDevice));
assert_eq!(pool.disable_peer_access(0), Err(CudaError::InvalidDevice));
}
#[cfg(target_os = "macos")]
#[test]
fn peer_access_not_supported_on_macos() {
let config = StreamOrderedAllocConfig::default_for_device(0);
let pool = StreamMemoryPool::new(config).expect("pool creation should succeed on macOS");
assert_eq!(pool.enable_peer_access(1), Err(CudaError::NotSupported));
assert_eq!(pool.disable_peer_access(1), Err(CudaError::NotSupported));
}
#[cfg(target_os = "macos")]
#[test]
fn reset_peak_stats() {
let config = StreamOrderedAllocConfig::default_for_device(0);
let mut pool =
StreamMemoryPool::new(config).expect("pool creation should succeed on macOS");
let mut a1 = pool.alloc_async(1024, 0).expect("alloc ok");
let _a2 = pool.alloc_async(2048, 0).expect("alloc ok");
assert_eq!(pool.stats().peak_allocations, 2);
assert_eq!(pool.stats().used_high, 3072);
pool.free_async(&mut a1).expect("free ok");
pool.reset_peak_stats();
let stats = pool.stats();
assert_eq!(stats.used_high, 2048); assert_eq!(stats.peak_allocations, 1); }
#[test]
fn alloc_zero_size_returns_error() {
let config = StreamOrderedAllocConfig::default_for_device(0);
let mut pool = StreamMemoryPool::new(config).expect("pool creation should succeed");
assert!(matches!(
pool.alloc_async(0, 0),
Err(CudaError::InvalidValue)
));
}
#[test]
fn default_pool_valid_device() {
let pool = StreamMemoryPool::default_pool(0);
assert!(pool.is_ok());
}
#[test]
fn default_pool_negative_device() {
assert!(matches!(
StreamMemoryPool::default_pool(-1),
Err(CudaError::InvalidValue)
));
}
#[test]
fn pool_attribute_to_raw() {
assert_eq!(
PoolAttribute::ReuseFollowEventDependencies.to_raw(),
CU_MEMPOOL_ATTR_REUSE_FOLLOW_EVENT_DEPENDENCIES
);
assert_eq!(
PoolAttribute::ReuseAllowOpportunistic.to_raw(),
CU_MEMPOOL_ATTR_REUSE_ALLOW_OPPORTUNISTIC
);
assert_eq!(
PoolAttribute::ReuseAllowInternalDependencies.to_raw(),
CU_MEMPOOL_ATTR_REUSE_ALLOW_INTERNAL_DEPENDENCIES
);
assert_eq!(
PoolAttribute::ReleaseThreshold(0).to_raw(),
CU_MEMPOOL_ATTR_RELEASE_THRESHOLD
);
assert_eq!(
PoolAttribute::ReservedMemCurrent.to_raw(),
CU_MEMPOOL_ATTR_RESERVED_MEM_CURRENT
);
assert_eq!(
PoolAttribute::ReservedMemHigh.to_raw(),
CU_MEMPOOL_ATTR_RESERVED_MEM_HIGH
);
assert_eq!(
PoolAttribute::UsedMemCurrent.to_raw(),
CU_MEMPOOL_ATTR_USED_MEM_CURRENT
);
assert_eq!(
PoolAttribute::UsedMemHigh.to_raw(),
CU_MEMPOOL_ATTR_USED_MEM_HIGH
);
}
#[test]
fn shareable_handle_type_default() {
assert_eq!(ShareableHandleType::default(), ShareableHandleType::None);
}
#[test]
fn pool_export_descriptor() {
let desc = PoolExportDescriptor {
shareable_handle_type: ShareableHandleType::PosixFileDescriptor,
pool_device: 0,
};
assert_eq!(
desc.shareable_handle_type,
ShareableHandleType::PosixFileDescriptor
);
assert_eq!(desc.pool_device, 0);
}
}