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:
77
crates/xserv-cuda/src/device.rs
Normal file
77
crates/xserv-cuda/src/device.rs
Normal file
@@ -0,0 +1,77 @@
|
||||
use crate::error::{self, Result};
|
||||
use crate::ffi;
|
||||
use std::ffi::CStr;
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct DeviceInfo {
|
||||
pub index: u32,
|
||||
pub name: String,
|
||||
pub total_memory: usize,
|
||||
pub compute_major: i32,
|
||||
pub compute_minor: i32,
|
||||
pub sm_count: i32,
|
||||
pub shared_mem_per_block: usize,
|
||||
pub warp_size: i32,
|
||||
pub max_threads_per_block: i32,
|
||||
}
|
||||
|
||||
extern "C" {
|
||||
fn cudaDeviceGetAttribute(value: *mut i32, attr: i32, device: i32) -> i32;
|
||||
}
|
||||
|
||||
fn get_attr(attr: i32, device: u32) -> Result<i32> {
|
||||
let mut value = 0;
|
||||
error::check(unsafe { cudaDeviceGetAttribute(&mut value, attr, device as i32) })?;
|
||||
Ok(value)
|
||||
}
|
||||
|
||||
pub fn device_count() -> Result<i32> {
|
||||
let mut count = 0;
|
||||
error::check(unsafe { ffi::cudaGetDeviceCount(&mut count) })?;
|
||||
Ok(count)
|
||||
}
|
||||
|
||||
pub fn set_device(device: u32) -> Result<()> {
|
||||
error::check(unsafe { ffi::cudaSetDevice(device as i32) })
|
||||
}
|
||||
|
||||
pub fn current_device() -> Result<u32> {
|
||||
let mut dev = 0;
|
||||
error::check(unsafe { ffi::cudaGetDevice(&mut dev) })?;
|
||||
Ok(dev as u32)
|
||||
}
|
||||
|
||||
pub fn device_info(device: u32) -> Result<DeviceInfo> {
|
||||
// Use cudaGetDeviceProperties only for the name (first field, always stable).
|
||||
let mut prop = unsafe { std::mem::zeroed::<ffi::CudaDeviceProp>() };
|
||||
error::check(unsafe { ffi::cudaGetDeviceProperties(&mut prop, device as i32) })?;
|
||||
let name = unsafe { CStr::from_ptr(prop.name.as_ptr()) }
|
||||
.to_string_lossy()
|
||||
.into_owned();
|
||||
|
||||
// Use cudaDeviceGetAttribute for everything else (layout-independent).
|
||||
// Attribute IDs from cuda_runtime_api.h:
|
||||
const TOTAL_GLOBAL_MEM: i32 = 0; // not available via attribute, use prop
|
||||
const SHARED_MEM_PER_BLOCK: i32 = 8;
|
||||
const WARP_SIZE: i32 = 10;
|
||||
const MAX_THREADS_PER_BLOCK: i32 = 1;
|
||||
const MULTI_PROCESSOR_COUNT: i32 = 16;
|
||||
const COMPUTE_MAJOR: i32 = 75;
|
||||
const COMPUTE_MINOR: i32 = 76;
|
||||
|
||||
Ok(DeviceInfo {
|
||||
index: device,
|
||||
name,
|
||||
total_memory: prop.total_global_mem,
|
||||
compute_major: get_attr(COMPUTE_MAJOR, device)?,
|
||||
compute_minor: get_attr(COMPUTE_MINOR, device)?,
|
||||
sm_count: get_attr(MULTI_PROCESSOR_COUNT, device)?,
|
||||
shared_mem_per_block: get_attr(SHARED_MEM_PER_BLOCK, device)? as usize,
|
||||
warp_size: get_attr(WARP_SIZE, device)?,
|
||||
max_threads_per_block: get_attr(MAX_THREADS_PER_BLOCK, device)?,
|
||||
})
|
||||
}
|
||||
|
||||
pub fn synchronize() -> Result<()> {
|
||||
error::check(unsafe { ffi::cudaDeviceSynchronize() })
|
||||
}
|
||||
Reference in New Issue
Block a user