1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
// use cuda_core::{CudaContext, DeviceBuffer, LaunchConfig};
// use cuda_device::{kernel, thread, DisjointSlice};
// use cuda_host::{cuda_launch, load_kernel_module};
// /// Plain helper function -- no annotation needed.
// /// The compiler discovers it automatically because `vecadd` calls it.
// fn add(a: f32, b: f32) -> f32 {
// a + b
// }
// #[kernel]
// pub fn vecadd(a: &[f32], b: &[f32], mut c: DisjointSlice<f32>) {
// let idx = thread::index_1d();
// if let Some(c_elem) = c.get_mut(idx) {
// *c_elem = add(a[idx.get()], b[idx.get()]);
// }
// }
// #[cfg(test)]
// mod test {
// use super::*;
// #[test]
// fn test_vecadd_kernel() -> Result<(), Box<dyn std::error::Error>> {
// let ctx = CudaContext::new(0).unwrap();
// let stream = ctx.default_stream();
// const N: usize = 1024;
// let a_host: Vec<f32> = (0..N).map(|i| i as f32).collect();
// let b_host: Vec<f32> = (0..N).map(|i| (i * 2) as f32).collect();
// let a_dev = DeviceBuffer::from_host(&stream, &a_host).unwrap();
// let b_dev = DeviceBuffer::from_host(&stream, &b_host).unwrap();
// let mut c_dev = DeviceBuffer::<f32>::zeroed(&stream, N).unwrap();
// // Loads `my_first_kernel.ptx` directly when cuda-oxide produced PTX, or
// // builds a cubin from `my_first_kernel.ll` when cuda-oxide auto-detected
// // CUDA libdevice math (`sin`, `pow`, `exp`, ...). Either way one call.
// let module =
// load_kernel_module(&ctx, "xndarray").expect("Failed to load kernel module");
// cuda_launch! {
// kernel: vecadd,
// stream: stream,
// module: module,
// config: LaunchConfig::for_num_elems(N as u32),
// args: [slice(a_dev), slice(b_dev), slice_mut(c_dev)]
// }
// .unwrap();
// let c_host = c_dev.to_host_vec(&stream).unwrap();
// let errors = (0..N)
// .filter(|&i| (c_host[i] - (a_host[i] + b_host[i])).abs() > 1e-5)
// .count();
// assert_eq!(errors, 0, "向量加法内核输出不正确");
// Ok(())
// }
// }