Files
foxhunt/testing/integration/gpu/cuda_initialization_test.rs
jgrusewski 450c23a6d0 refactor(cuda): eliminate all CPU fallbacks — CUDA mandatory across ML stack
- Remove ALL #[cfg(feature = "cuda")] guards (~400+ occurrences)
- Remove ALL #[cfg_attr(not(feature = "cuda"), ignore)] test annotations (~250)
- Make cuda default feature in 9 ML crates (ml, ml-core, ml-dqn, ml-ppo, etc.)
- Convert nvrtc JIT compilation to precompiled nvcc (searchsorted, prefix_sum)
- Move compile_ptx_for_device() to ml-core for shared access
- Delete dead CPU code: multi_step.rs, self_supervised_pretraining.rs,
  training_guard_gpu_tests.rs, CPU PER buffer paths, CPU Q-diagnostics
- Replace unwrap_or(Device::Cpu) with hard errors everywhere
- Remove dead is_cuda() else branches in DQN/PPO/hyperopt trainers
- Change config defaults from "cpu" to "cuda" (rainbow, tlob, pipeline)
- Port IQL value network to GPU kernel (5 CUDA entry points)
- Port HER goal relabeling to GPU kernel (warp-per-sample)
- Wire DSR GPU-to-CPU sync in training loop
- cfg!(feature = "cuda") → true in inference_validator

Zero warnings, zero errors across entire workspace.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-16 21:01:28 +01:00

164 lines
5.7 KiB
Rust

//! CUDA Initialization and Device Detection Tests
//!
//! Tests CUDA device availability, initialization, and basic functionality
use super::utils::*;
use candle_core::{Device, DType, Tensor};
use log::{info, warn};
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_cuda_device_detection() {
init_gpu_test_env();
info!("🔍 Testing CUDA device detection");
// Test CUDA availability detection
let cuda_available = cuda_available();
info!("CUDA available: {}", cuda_available);
if cuda_available {
info!("✅ CUDA device detected successfully");
} else {
warn!("⚠️ CUDA device not available - running in CPU-only mode");
}
// This test always passes, but logs the detection result
assert!(true, "CUDA detection test completed");
}
#[test]
fn test_candle_cuda_device_creation() {
init_gpu_test_env();
info!("🔧 Testing Candle CUDA device creation");
match Device::cuda_if_available(0) {
Ok(device) => {
info!("✅ Candle CUDA device created: {:?}", device);
assert!(device.is_cuda(), "Device should be CUDA");
// Test basic tensor creation on CUDA device
let tensor = Tensor::zeros((2, 2), DType::F32, &device)
.expect("Should create tensor on CUDA device");
assert_eq!(tensor.device(), &device);
assert_eq!(tensor.shape().dims(), &[2, 2]);
info!("✅ Basic tensor creation on CUDA device successful");
}
Err(e) => {
warn!("⚠️ Candle CUDA device creation failed: {}", e);
info!("Falling back to CPU device for testing");
let cpu_device = Device::Cpu;
let tensor = Tensor::zeros((2, 2), DType::F32, &cpu_device)
.expect("Should create tensor on CPU device");
assert!(!tensor.device().is_cuda(), "Fallback device should be CPU");
}
}
}
#[test]
fn test_cuda_device_properties() {
init_gpu_test_env();
if !cuda_available() {
info!("⚠️ Skipping CUDA device properties test - CUDA not available");
return;
}
info!("📊 Testing CUDA device properties");
match cudarc::driver::CudaDevice::new(0) {
Ok(device) => {
info!("✅ CUDA device initialized successfully");
// Test device properties
let device_name = device.name().unwrap_or("Unknown".to_string());
let total_memory = device.total_memory().unwrap_or(0);
info!("Device name: {}", device_name);
info!("Total memory: {} bytes ({:.2} GB)",
total_memory, total_memory as f64 / (1024.0 * 1024.0 * 1024.0));
// Basic validation
assert!(!device_name.is_empty(), "Device should have a name");
assert!(total_memory > 0, "Device should have memory");
info!("✅ CUDA device properties validation passed");
}
Err(e) => {
warn!("⚠️ CUDA device initialization failed: {}", e);
}
}
}
#[test]
fn test_multiple_cuda_devices() {
init_gpu_test_env();
info!("🔢 Testing multiple CUDA device detection");
let mut cuda_devices = Vec::new();
// Try to detect up to 8 CUDA devices
for device_id in 0..8 {
match Device::cuda_if_available(device_id) {
Ok(device) => {
info!("✅ CUDA device {} available: {:?}", device_id, device);
cuda_devices.push((device_id, device));
}
Err(_) => {
// Stop at first unavailable device
break;
}
}
}
info!("Found {} CUDA device(s)", cuda_devices.len());
if cuda_devices.is_empty() {
warn!("⚠️ No CUDA devices found");
} else {
info!("✅ CUDA device enumeration successful");
// Test basic operations on each device
for (device_id, device) in cuda_devices {
let test_tensor = Tensor::ones((10, 10), DType::F32, &device)
.expect(&format!("Should create tensor on device {}", device_id));
assert!(test_tensor.device().is_cuda());
info!("✅ Device {} tensor creation test passed", device_id);
}
}
}
#[test]
fn test_cuda_error_handling() {
init_gpu_test_env();
info!("🚨 Testing CUDA error handling");
// Test invalid device ID
match Device::cuda_if_available(99) {
Ok(_) => {
warn!("⚠️ Unexpected: Device 99 should not be available");
}
Err(e) => {
info!("✅ Expected error for invalid device ID: {}", e);
}
}
// Test graceful fallback
let device = get_test_device();
info!("✅ Graceful device fallback: {:?}", device);
// Ensure we can always create tensors on the fallback device
let tensor = Tensor::zeros((5, 5), DType::F32, &device)
.expect("Should create tensor on fallback device");
assert_eq!(tensor.shape().dims(), &[5, 5]);
info!("✅ Error handling and fallback test passed");
}
}