减少CUDA内核中使用的寄存器数量

时间:2010-02-17 19:00:18

标签: optimization cuda gpgpu

我有一个使用17个寄存器的内核,将其减少到16会使我100%占用。我的问题是:是否有可用于减少所用数量或寄存器的方法,不包括以不同方式完全重写我的算法。我总是认为编译器比我更聪明,所以例如我为了清晰起见而经常使用额外的变量。这个想法我错了吗?

请注意:我确实知道--max_registers(或任何语法)标志,但使用本地内存会比占用率降低25%更有害(我应该测试一下)

5 个答案:

答案 0 :(得分:8)

占用率可能有点误导,100%的入住率不应该是您的主要目标。如果您可以完全合并访问全局内存,那么在高端GPU上50%的占用率足以隐藏全局内存的延迟(对于浮点数,甚至更低的双倍数)。有关此主题的更多信息,请查看去年GTC的Advanced CUDA C演示文稿。

在你的情况下,你应该在maxrregcount设置为16的情况下测量性能。本地内存的延迟应该由于拥有足够的线程而被隐藏,假设你没有随机访问本地数组(这会导致在非合并访问中)。

要回答有关减少寄存器的具体问题,请发布代码以获取更详细的答案!理解编译器的工作原理可能会有所帮助,但请记住,nvcc是一个具有大参数空间的优化编译器,因此最小化寄存器数必须与整体性能相平衡。

答案 1 :(得分:6)

很难说,在我看来,nvcc编译器并不是很聪明 您可以尝试显而易见的事情,例如使用short而不是int,通过引用传递和使用变量(例如& variable),展开循环,使用模板(如在C ++中)。如果你有分裂,超越函数,按顺序应用,尝试将它们作为循环。尝试摆脱条件,可能用冗余计算替换它们。

如果你发布一些代码,也许你会得到具体的答案。

答案 2 :(得分:4)

将共享内存用作缓存可能会减少寄存器的使用并防止寄存器溢出到本地内存......

认为内核计算了一些值,所有线程都使用这些计算值

__global__ void kernel(...) {
    int idx = threadIdx.x + blockDim.x * blockIdx.x;
    int id0 = blockDim.x * blockIdx.x;

    int reg = id0 * ...;
    int reg0 = reg * a / x + y;


    ...

    int val =  reg + reg0 + 2 * idx;

    output[idx] = val > 10;
}

因此,我们可以使用共享内存,而不是将reg和reg0保留为寄存器并使它们可能溢出到本地内存(全局内存)。

__global__ void kernel(...) {
    __shared__ int cache[10];

    int idx = threadIdx.x + blockDim.x * blockIdx.x;

    if (threadIdx.x == 0) {
      int id0 = blockDim.x * blockIdx.x;

      cache[0] = id0 * ...;
      cache[1] = cache[0] * a / x + y;
    }
    __syncthreads();


    ...

    int val =  cache[0] + cache[1] + 2 * idx;

    output[idx] = val > 10;
}

请查看此paper以获取更多信息..

答案 3 :(得分:2)

通常不是最小化套准压力的好方法。编译器在优化整体预计内核性能方面做得很好,并且它考虑了很多因素,包括寄存器。

  

减少寄存器导致速度降低时如何工作

编译器很可能不得不将不足的寄存器数据泄漏到“本地”内存中,这与全局内存基本相同,因而非常慢

出于优化目的,我建议在必要时使用const,volatile等关键字来帮助编译器进行优化。

无论如何,这些像寄存器这样的微小问题往往会导致CUDA内核运行缓慢。我建议使用全局内存,访问模式,纹理内存中的缓存(如果可能)来优化工作,通过PCIe进行事务处理。

答案 4 :(得分:1)

降低寄存器使用时的指令计数增加有一个简单的解释。编译器可能正在使用寄存器来存储在代码中多次使用的一些操作的结果,以避免重新计算这些值,当强制使用较少的寄存器时,编译器决定重新计算将存储在寄存器中的那些值否则。

相关问题