我想使用CUDA运行时API函数接受带有内核模板的CUDA内核函数指针。
我可以在没有模板的情况下执行以下操作:
__global__ myKernel()
{
...
}
void myFunc(const char* kernel_ptr)
{
...
// use API functions like
cudaFuncGetAttributes(&attrib, kernel_ptr);
...
}
int main()
{
myFunc(myKernel);
}
但是,当内核是模板时,上述操作无效。
另一个例子:
#include "cuda_runtime.h"
#include "device_launch_parameters.h"
#include <stdio.h>
template<typename T>
__global__ void addKernel(T *c, const T *a, const T *b)
{
int i = threadIdx.x;
c[i] = a[i] + b[i];
}
int main()
{
cudaFuncAttributes attrib;
cudaError_t err;
//OK:
err = cudaFuncGetAttributes(&attrib, addKernel<float>); // works fine
printf("result: %s, reg1: %d\n", cudaGetErrorString(err), attrib.numRegs);
//NOT OK:
//try to get function ptr to pass as an argument:
const char* ptr = addKernel<float>; // compile error
err = cudaFuncGetAttributes(&attrib, ptr);
printf("result: %s, reg2: %d\n", cudaGetErrorString(err), attrib.numRegs);
}
以上结果导致编译错误:
错误:没有函数模板“addKernel”的实例匹配 所需类型
编辑: 到目前为止我发现的唯一解决方法是将myFunc中的内容(参见第一个代码示例)放入一个宏,这很丑,但它不需要传递指针参数,它工作正常:
#define MY_FUNC(kernel) \
{ \
...\
cudaFuncGetAttributes( &attrib, kernel ); \
...\
}
用法:
MY_FUNC( myKernel<float> )
答案 0 :(得分:2)
addKernel<void>
的类型不是char *
,它是一种函数类型。
相反,请获取addKernel<float>
的地址,如下所示:
typedef void (*fun_ptr)(float*,const float *, const float*);
fun_ptr ptr = addKernel<float>; // compile error
err = cudaFuncGetAttributes(&attrib, ptr);
答案 1 :(得分:2)
参考“另一个例子:”
中包含的代码改变这个:
const char* ptr = addKernel<float>; // compile error
到此:
void (*ptr)(float *, const float *, const float *) = addKernel<float>;
我相信它会编译并正确运行。
我不知道你在尝试的整体范围内是否有用。
编辑回复评论中的问题:
一旦我从函数中“提取”了指针,我就可以将其转换为另一种类型。试试吧。例如,以下代码也有效:
void (*ptr)(float *, const float *, const float *) = addKernel<float>;
const char *ptr1 = (char *)ptr;
err = cudaFuncGetAttributes(&attrib, ptr1);
所以,为了回答你的问题,一旦你有了函数指针,可以将你的函数指针强制转换为const char*
。
顺便说一句,你发布的代码作为答案会在gcc 4.1.2和gcc 4.4.6上为我抛出编译错误:
$ nvcc -arch=sm_20 -O3 -o t201 t201.cu
t201.cu: In function âint main()â:
t201.cu:25: error: address of overloaded function with no contextual type information
t201.cu:29: error: address of overloaded function with no contextual type information
$
如果我删除这两行中的&
,我也会收到错误:
$ nvcc -arch=sm_20 -O3 -o t201 t201.cu
t201.cu: In function âint main()â:
t201.cu:25: error: insufficient contextual information to determine type
t201.cu:29: error: insufficient contextual information to determine type
$
因此,根据从A点到B点需要采取哪些步骤,其中一些可能与编译器有关。
答案 2 :(得分:0)
编辑:添加了基于cuda运行时的模板版本和Robert Crovella的答案。
这是一个使用void函数指针和模板的完整工作示例。
#include "cuda_runtime.h"
#include "device_launch_parameters.h"
#include <stdio.h>
template <typename T>
__global__ void addKernel(T *c, const T *a, const T *b)
{
int i = threadIdx.x;
c[i] = a[i] + b[i];
}
cudaError_t func1( cudaFuncAttributes* attrib, void (*ptr)() )
{
return cudaFuncGetAttributes(attrib, ptr);
}
cudaError_t func2( cudaFuncAttributes* attrib, const char* ptr )
{
return cudaFuncGetAttributes(attrib, ptr);
}
template <typename T>
cudaError_t func2( cudaFuncAttributes* attrib, T ptr )
{
return func2( attrib, (const char*) ptr);
}
int main()
{
cudaFuncAttributes attrib;
cudaError_t err;
void (*ptr2)() = (void(*)())(addKernel<float>); // OK on Visual Studio
err = func1(&attrib, ptr2);
printf("result: %s, reg1: %d\n", cudaGetErrorString(err), attrib.numRegs);
err = func2(&attrib, addKernel<double> ); // OK nice and standard
printf("result: %s, reg2: %d\n", cudaGetErrorString(err), attrib.numRegs);
}