让我们说我想要一个需要做很多事情的CUDA内核,但是有些圆顶参数对所有内核都是不变的。这些参数作为输入传递给主程序,因此无法在#DEFINE
中定义它们。
内核将运行多次(大约65K)并且需要这些参数(以及一些其他输入)来进行数学运算。
我的问题是:将这些常量传递给内核的最快(或最优雅)方式是什么?
常量是2或3个元素长度float*
或int*
数组。它们将在5到10个左右。
玩具示例:2个常量const1
和const2
__global__ void kernelToyExample(int inputdata, ?????){
value=inputdata*const1[0]+const2[1]/const1[2];
}
更好吗
__global__ void kernelToyExample(int inputdata, float* const1, float* const2){
value=inputdata*const1[0]+const2[1]/const1[2];
}
或
__global__ void kernelToyExample(int inputdata, float const1x, float const1y, float const1z, float const2x, float const2y){
value=inputdata*const1x+const2y/const1z;
}
或者可能在一些全局只读内存中声明它们并让内核从那里读取?如果是这样,L1,L2,全球?哪一个?
有没有更好的方法我不知道?
在特斯拉K40上跑步。
答案 0 :(得分:12)
按价值传递它们。编译器将自动将它们放在最佳位置,以便于缓存广播到每个块中的所有线程 - 计算能力1.x设备中的共享内存,或计算能力中的常量内存/常量缓存> = 2.0设备。
例如,如果你有一长串要传递给内核的参数,那么按值传递的结构是一个干净的方法:
struct arglist {
float magicfloat_1;
float magicfloat_2;
//......
float magicfloat_19;
int magicint1;
//......
};
__global__ void kernel(...., const arglist args)
{
// you get the idea
}
[标准免责声明:用浏览器编写,不是真正的代码,告诫者]
如果事实证明你的一个magicint
实际上只取了一个你事先知道的少量值之一,那么模板是一个非常强大的工具:
template<int magiconstant1>
__global__ void kernel(....)
{
for(int i=0; i < magconstant1; ++i) {
// .....
}
}
template kernel<3>(....);
template kernel<4>(....);
template kernel<5>(....);
编译器非常智能,可以识别magconstant
使循环行程在编译时已知,并将自动为您循环循环。模板是一个very powerful technique,用于构建快速,灵活的代码库,如果您还没有这样做,建议您尽量使用它。