cuda编程笔记(25)-- 如何像函数对象一样使用核函数
在C++中,函数可以被归类为可调用对象,可以像参数一样传给其他函数。那么cuda里的核函数想要实现这样的效果应该怎么办呢?
很明显,核函数不可以像普通函数一样被抽象成可调用对象传给std::function,那应该怎么实现?
既然高级语言的抽象用不了,只能使用低级的方式了,那就是宏定义
#define CUDA_KERNEL_CALL(kernel, nblks, nthrs, shmem, stream, ...) \{ \(kernel)<<<(nblks), (nthrs), (shmem), (stream)>>>(__VA_ARGS__);\cudaError_t e = cudaGetLastError(); \if (!(e == cudaSuccess || e == cudaErrorCudartUnloading)) { \std::cerr << "CUDA kernel launch error: " << cudaGetErrorString(e) << std::endl;\} \} \
这个其实和 C/C++ 宏(macro)里的可变参数语法有关,和 CUDA 本身没关系。
宏里的 ...
和 __VA_ARGS__
在宏定义里,如果最后写上 ...
,就表示这个宏可以接收可变数量的参数。
例如:
#define PRINTF(fmt, ...) printf(fmt, __VA_ARGS__)
调用时:
PRINTF("a=%d, b=%d\n", 1, 2);
展开后就是:
printf("a=%d, b=%d\n", 1, 2);
这里 ...
就是占位符,__VA_ARGS__
是一个特殊的标识符,表示“把传进来的所有可变参数原封不动填进去”。
必须成对用 ...
和 __VA_ARGS__
...
是宏定义时的“声明”__VA_ARGS__
是宏展开时的“使用”
就像函数声明参数,然后函数体里使用参数一样。
例子
#define CUDA_KERNEL_CALL(kernel, nblks, nthrs, shmem, stream, ...) \{ \(kernel)<<<(nblks), (nthrs), (shmem), (stream)>>>(__VA_ARGS__);\cudaError_t e = cudaGetLastError(); \if (!(e == cudaSuccess || e == cudaErrorCudartUnloading)) { \std::cerr << "CUDA kernel launch error: " << cudaGetErrorString(e) << std::endl;\} \} \__global__ void globalCopy(const float* data, float* out,const int N) {int idx = threadIdx.x + blockIdx.x * blockDim.x;if (idx < N) {out[idx] = data[idx];}
}//调用端
CUDA_KERNEL_CALL(globalCopy,1,32,0,0,d_data,d_out,32)
这样想调用哪个核函数,都可以用这个宏