use crate::{Buffer, BufferOptions, CpuAllocator};
use std::sync::Arc;
use svod_dtype::DType;
#[cfg(feature = "cuda")]
use crate::CudaAllocator;
#[test]
fn test_lazy_allocation() {
let allocator = Arc::new(CpuAllocator);
let buffer = Buffer::new(allocator, DType::Float32, vec![10], BufferOptions::default());
assert!(!buffer.is_allocated());
buffer.ensure_allocated().unwrap();
assert!(buffer.is_allocated());
}
#[test]
fn test_buffer_view() {
let allocator = Arc::new(CpuAllocator);
let buffer = Buffer::allocate(allocator, DType::Float32, vec![10], BufferOptions::default()).unwrap();
let view = buffer.view(4, 16).unwrap();
assert_eq!(view.offset(), 4);
assert_eq!(view.size(), 16);
}
#[test]
fn test_view_has_distinct_handle_id() {
let allocator = Arc::new(CpuAllocator);
let buffer = Buffer::allocate(allocator, DType::Float32, vec![16], BufferOptions::default()).unwrap();
let view_a = buffer.view(0, 16).unwrap();
let view_b = buffer.view(16, 16).unwrap();
assert_ne!(buffer.id(), view_a.id(), "view must have a fresh handle id distinct from its base");
assert_ne!(view_a.id(), view_b.id(), "two distinct views must have distinct handle ids");
}
#[test]
fn test_view_shares_storage_id() {
let allocator = Arc::new(CpuAllocator);
let buffer = Buffer::allocate(allocator, DType::Float32, vec![16], BufferOptions::default()).unwrap();
let view = buffer.view(8, 16).unwrap();
assert_eq!(buffer.storage_id(), view.storage_id(), "view must share its base's storage id");
}
#[test]
fn test_independent_buffers_have_distinct_storage_ids() {
let allocator = Arc::new(CpuAllocator);
let a = Buffer::allocate(allocator.clone(), DType::Float32, vec![8], BufferOptions::default()).unwrap();
let b = Buffer::allocate(allocator, DType::Float32, vec![8], BufferOptions::default()).unwrap();
assert_ne!(a.storage_id(), b.storage_id(), "independent allocations must have distinct storage ids");
assert_ne!(a.id(), b.id());
}
#[test]
fn test_invalid_view() {
let allocator = Arc::new(CpuAllocator);
let buffer = Buffer::allocate(allocator, DType::Float32, vec![10], BufferOptions::default()).unwrap();
let result = buffer.view(36, 16);
assert!(result.is_err());
}
#[cfg(feature = "cuda")]
#[test]
fn test_unified_memory_allocation() {
let allocator = match CudaAllocator::new(0) {
Ok(alloc) => Arc::new(alloc),
Err(_) => {
eprintln!("CUDA not available, skipping test");
return;
}
};
let options = BufferOptions { cpu_accessible: true, zero_init: false };
let buffer = Buffer::allocate(allocator, DType::Float32, vec![10], options).unwrap();
assert!(buffer.is_allocated());
assert!(buffer.allocator().name() == "CUDA");
}
#[cfg(feature = "cuda")]
#[test]
fn test_unified_memory_cpu_access() {
let allocator = match CudaAllocator::new(0) {
Ok(alloc) => Arc::new(alloc),
Err(_) => {
eprintln!("CUDA not available, skipping test");
return;
}
};
let options = BufferOptions { cpu_accessible: true, zero_init: false };
let mut buffer = Buffer::allocate(allocator, DType::Float32, vec![10], options).unwrap();
let input_data: Vec<f32> = (0..10).map(|i| i as f32).collect();
let input_bytes: &[u8] = unsafe { std::slice::from_raw_parts(input_data.as_ptr() as *const u8, 40) };
buffer.copyin(input_bytes).unwrap();
let mut output_data = vec![0f32; 10];
let output_bytes: &mut [u8] = unsafe { std::slice::from_raw_parts_mut(output_data.as_mut_ptr() as *mut u8, 40) };
buffer.copyout(output_bytes).unwrap();
assert_eq!(input_data, output_data);
}
#[cfg(feature = "cuda")]
#[test]
fn test_unified_memory_view() {
let allocator = match CudaAllocator::new(0) {
Ok(alloc) => Arc::new(alloc),
Err(_) => {
eprintln!("CUDA not available, skipping test");
return;
}
};
let options = BufferOptions { cpu_accessible: true, zero_init: false };
let buffer = Buffer::allocate(allocator, DType::Float32, vec![10], options).unwrap();
let view = buffer.view(8, 16).unwrap();
assert_eq!(view.offset(), 8);
assert_eq!(view.size(), 16);
}
#[cfg(feature = "cuda")]
#[test]
fn test_copy_device_to_unified() {
let allocator = match CudaAllocator::new(0) {
Ok(alloc) => Arc::new(alloc),
Err(_) => {
eprintln!("CUDA not available, skipping test");
return;
}
};
let device_opts = BufferOptions { cpu_accessible: false, zero_init: false };
let mut device_buf = Buffer::allocate(allocator.clone(), DType::Float32, vec![10], device_opts).unwrap();
let unified_opts = BufferOptions { cpu_accessible: true, zero_init: false };
let mut unified_buf = Buffer::allocate(allocator, DType::Float32, vec![10], unified_opts).unwrap();
let input_data: Vec<f32> = (0..10).map(|i| i as f32 * 2.0).collect();
let input_bytes: &[u8] = unsafe { std::slice::from_raw_parts(input_data.as_ptr() as *const u8, 40) };
device_buf.copyin(input_bytes).unwrap();
unified_buf.copy_from(&device_buf).unwrap();
let mut output_data = vec![0f32; 10];
let output_bytes: &mut [u8] = unsafe { std::slice::from_raw_parts_mut(output_data.as_mut_ptr() as *mut u8, 40) };
unified_buf.copyout(output_bytes).unwrap();
assert_eq!(input_data, output_data);
}
#[cfg(feature = "cuda")]
#[test]
fn test_copy_unified_to_device() {
let allocator = match CudaAllocator::new(0) {
Ok(alloc) => Arc::new(alloc),
Err(_) => {
eprintln!("CUDA not available, skipping test");
return;
}
};
let unified_opts = BufferOptions { cpu_accessible: true, zero_init: false };
let mut unified_buf = Buffer::allocate(allocator.clone(), DType::Float32, vec![10], unified_opts).unwrap();
let device_opts = BufferOptions { cpu_accessible: false, zero_init: false };
let mut device_buf = Buffer::allocate(allocator, DType::Float32, vec![10], device_opts).unwrap();
let input_data: Vec<f32> = (0..10).map(|i| i as f32 * 3.0).collect();
let input_bytes: &[u8] = unsafe { std::slice::from_raw_parts(input_data.as_ptr() as *const u8, 40) };
unified_buf.copyin(input_bytes).unwrap();
device_buf.copy_from(&unified_buf).unwrap();
let mut output_data = vec![0f32; 10];
let output_bytes: &mut [u8] = unsafe { std::slice::from_raw_parts_mut(output_data.as_mut_ptr() as *mut u8, 40) };
device_buf.copyout(output_bytes).unwrap();
assert_eq!(input_data, output_data);
}
#[cfg(feature = "cuda")]
#[test]
fn test_copy_unified_to_unified() {
let allocator = match CudaAllocator::new(0) {
Ok(alloc) => Arc::new(alloc),
Err(_) => {
eprintln!("CUDA not available, skipping test");
return;
}
};
let options = BufferOptions { cpu_accessible: true, zero_init: false };
let mut src_buf = Buffer::allocate(allocator.clone(), DType::Float32, vec![10], options.clone()).unwrap();
let mut dst_buf = Buffer::allocate(allocator, DType::Float32, vec![10], options).unwrap();
let input_data: Vec<f32> = (0..10).map(|i| i as f32 + 5.0).collect();
let input_bytes: &[u8] = unsafe { std::slice::from_raw_parts(input_data.as_ptr() as *const u8, 40) };
src_buf.copyin(input_bytes).unwrap();
dst_buf.copy_from(&src_buf).unwrap();
let mut output_data = vec![0f32; 10];
let output_bytes: &mut [u8] = unsafe { std::slice::from_raw_parts_mut(output_data.as_mut_ptr() as *mut u8, 40) };
dst_buf.copyout(output_bytes).unwrap();
assert_eq!(input_data, output_data);
}
#[cfg(feature = "cuda")]
#[test]
fn test_unified_memory_zero_init() {
let allocator = match CudaAllocator::new(0) {
Ok(alloc) => Arc::new(alloc),
Err(_) => {
eprintln!("CUDA not available, skipping test");
return;
}
};
let options = BufferOptions { cpu_accessible: true, zero_init: true };
let buffer = Buffer::allocate(allocator, DType::Float32, vec![10], options).unwrap();
let mut output_data = vec![1f32; 10]; let output_bytes: &mut [u8] = unsafe { std::slice::from_raw_parts_mut(output_data.as_mut_ptr() as *mut u8, 40) };
buffer.copyout(output_bytes).unwrap();
assert_eq!(output_data, vec![0f32; 10]);
}