teeny_cuda/testing/
mod.rs1use teeny_core::device::{
18 context::{Context, DeviceInfo},
19 program::Kernel,
20};
21
22use crate::{
23 compiler::target::{Capability, capability_from_device_info},
24 device::context::Cuda,
25 device::program::CudaProgram,
26 device::{CudaDevice, CudaLaunchConfig},
27 errors::Result,
28};
29
30pub struct CudaTestEnv {
32 pub device: CudaDevice<'static>,
34 pub capability: Capability,
36}
37
38pub fn setup_cuda_env() -> Result<CudaTestEnv> {
42 let cuda_available = Cuda::is_available()?;
43 assert!(cuda_available, "CUDA is not available");
44 println!("[1/9] CUDA available");
45
46 let cuda = Cuda::try_new()?;
47 let devices = cuda.list_devices()?;
48 assert!(!devices.is_empty(), "No CUDA devices found");
49 println!("[2/9] found {} device(s)", devices.len());
50
51 let device = cuda.device(&devices[0].id())?;
52 let device_capability = capability_from_device_info(&device.info)?;
53
54 let capability = if let Ok(val) = std::env::var("TEENYC_CAPABILITY") {
55 let parsed = val
56 .strip_prefix("sm_")
57 .and_then(|s| s.parse::<i32>().ok())
58 .and_then(|n| Capability::from_major_minor(n / 10, n % 10))
59 .ok_or_else(|| {
60 crate::errors::Error::UnknownCapability(format!(
61 "TEENYC_CAPABILITY={val:?} is not a recognised sm version"
62 ))
63 })?;
64 println!(
65 "[3/9] device: {} (capability overridden: {device_capability} → {parsed})",
66 device.info.name
67 );
68 parsed
69 } else {
70 println!(
71 "[3/9] device: {} (capability: {device_capability})",
72 device.info.name
73 );
74 device_capability
75 };
76
77 Ok(CudaTestEnv { device, capability })
78}
79
80pub fn launch_config_from_program<K: Kernel>(
85 n_elements: usize,
86 program: &CudaProgram<'_, K>,
87) -> CudaLaunchConfig {
88 let threads = program.metadata.threads_per_block().max(1);
89 CudaLaunchConfig {
90 grid: [(n_elements as u32).div_ceil(threads), 1, 1],
91 block: [threads, 1, 1],
92 cluster: [program.metadata.num_ctas.max(1), 1, 1],
93 }
94}
95
96pub fn launch_config(n_elements: usize, block_size: i32) -> CudaLaunchConfig {
101 CudaLaunchConfig {
102 grid: [(n_elements as u32).div_ceil(block_size as u32), 1, 1],
103 block: [block_size as u32, 1, 1],
104 cluster: [1, 1, 1],
105 }
106}
107
108pub fn launch_config_with_grid<K: Kernel>(
114 grid_x: usize,
115 program: &CudaProgram<'_, K>,
116) -> CudaLaunchConfig {
117 let threads = program.metadata.threads_per_block().max(1);
118 CudaLaunchConfig {
119 grid: [grid_x as u32, 1, 1],
120 block: [threads, 1, 1],
121 cluster: [program.metadata.num_ctas.max(1), 1, 1],
122 }
123}
124
125pub fn load_program_from_ptx<K: Kernel>(ptx: &[u8]) -> Result<CudaProgram<'static, K>> {
128 println!(" loading PTX directly via driver JIT...");
129 let program = CudaProgram::<K>::try_from_ptx(ptx)?;
130 println!(
131 "[7/9] loaded PTX: module={:#x} function={:#x} num_warps={} num_ctas={}",
132 program.module_ptr(),
133 program.function_ptr(),
134 program.metadata.num_warps,
135 program.metadata.num_ctas,
136 );
137 Ok(program)
138}