将常量参数传递给CUDA内核的最快(或最优雅)方式

And*_*uri 8 c++ cuda

假设我想要一个需要做很多事情的CUDA内核,但是有些圆顶参数对所有内核都是不变的.这个参数作为输入传递给主程序,因此它们不能在a中定义#DEFINE.

内核将运行多次(大约65K)并且需要这些参数(以及一些其他输入)来进行数学运算.

我的问题是:将这些常量传递给内核的最快(或者最优雅)方式是什么?

常量是2或3个元素长度float*int*数组.它们将在这些中约5~10个.


玩具示例:2个常数const1const2

__global__ void kernelToyExample(int inputdata, ?????){
        value=inputdata*const1[0]+const2[1]/const1[2];
}
Run Code Online (Sandbox Code Playgroud)

好点吗

__global__ void kernelToyExample(int inputdata, float* const1, float* const2){
        value=inputdata*const1[0]+const2[1]/const1[2];
}
Run Code Online (Sandbox Code Playgroud)

要么

__global__ void kernelToyExample(int inputdata, float const1x, float const1y, float const1z, float const2x, float const2y){
        value=inputdata*const1x+const2y/const1z;
}
Run Code Online (Sandbox Code Playgroud)

或者可能在一些全局只读内存中声明它们并让内核从那里读取?如果是这样,L1,L2,全球?哪一个?

有没有更好的方法我不知道?

在特斯拉K40上运行.

tal*_*ies 13

只需按值传递它们.编译器将自动将它们放在最佳位置,以便于缓存广播到每个块中的所有线程 - 计算能力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
}
Run Code Online (Sandbox Code Playgroud)

[标准免责声明:用浏览器编写,不是真正的代码,需要注意事项]

如果事实证明你magicint实际上只有一个你事先知道的少量值之一,那么模板是一个非常强大的工具:

template<int magiconstant1>
__global__ void kernel(....)
{
    for(int i=0; i < magconstant1; ++i) {
       // .....
    }
}

template kernel<3>(....);
template kernel<4>(....);
template kernel<5>(....);
Run Code Online (Sandbox Code Playgroud)

编译器足够智能以识别magconstant在编译时使循环行程已知,并将自动为您循环循环.模板化是构建快速,灵活的代码库的一种非常强大的技术,如果你还没有这样做,你最好习惯使用它.

  • 我不会按值传递40个标量,我会按值传递它们,但是,编译器最了解并且没有更好的方法可以做到这一点.实际上,对于可能具有有限值范围的整数常量,有一种更好的方法 - 使它们成为模板参数并实例化不同的内核版本.当编译时已知常量时,编译器将执行许多有用的优化 (2认同)