phase 0+1: project scaffold + xserv-cuda crate

- Cargo workspace with xserv-cuda crate
- CUDA FFI bindings (cudart: memory, stream, device, error)
- GpuBuffer RAII wrapper with H2D/D2H/D2D copy
- CudaStream wrapper with RAII Drop
- CachingAllocator with size-bucketed free lists
- PinnedBuffer for page-locked host memory
- Device info query via cudaDeviceGetAttribute
- Vector-add CUDA kernel smoke test
- Integration test suite (11 tests)
- build.rs: cc crate compiles .cu for SM 12.0
- sync-and-build.sh for remote build on dash5
- Roadmap doc (docs/00-roadmap.md) and Phase 0+1 design doc

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-05-21 18:40:22 +08:00
commit 9806b4db35
16 changed files with 2629 additions and 0 deletions

View File

@@ -0,0 +1,43 @@
use crate::ffi;
use std::ffi::CStr;
use std::fmt;
#[derive(Debug)]
pub enum CudaError {
OutOfMemory,
InvalidDevice,
Raw { code: i32, message: String },
}
impl fmt::Display for CudaError {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
CudaError::OutOfMemory => write!(f, "CUDA out of memory"),
CudaError::InvalidDevice => write!(f, "CUDA invalid device"),
CudaError::Raw { code, message } => write!(f, "CUDA error {code}: {message}"),
}
}
}
impl std::error::Error for CudaError {}
pub type Result<T> = std::result::Result<T, CudaError>;
pub(crate) fn check(code: i32) -> Result<()> {
if code == ffi::CUDA_SUCCESS {
return Ok(());
}
let message = unsafe {
let ptr = ffi::cudaGetErrorString(code);
if ptr.is_null() {
"unknown error".to_string()
} else {
CStr::from_ptr(ptr).to_string_lossy().into_owned()
}
};
Err(match code {
ffi::CUDA_ERROR_OUT_OF_MEMORY => CudaError::OutOfMemory,
101 => CudaError::InvalidDevice,
_ => CudaError::Raw { code, message },
})
}