增加 CUDA 中每个线程寄存器的使用

nur*_*bha 5 memory cuda latency cpu-registers

通常建议降低每个线程的寄存器压力以增加 warp 占用,从而提供更大的机会通过 warp 级多线程 (TLP) 隐藏延迟。为了减少寄存器压力,可以使用更多的每个线程本地内存或每个线程块共享内存。CUDA nvcc 编译器也可以强制每个线程使用更少的寄存器。这种方法对于具有良好算术延迟的工作负载很有用,即 ALU 操作与内存 r/w 访问请求的比率很高。然而,对于计算量非常少且内存访问更频繁的延迟关键应用程序,这种方法实际上往往会降低性能。

在此类延迟关键应用程序的情况下,将尽可能多的数据放入片上寄存器或共享内存中更有意义,然后在用全局内存中的下一个数据块替换它之前尽可能多地使用它。当然,通过增加寄存器压力,warp 占用率降低,但现在我们使用快速片上寄存器隐藏片外存储器延迟。增加每个线程寄存器使用的方法是通过展开循环或计算每个线程更多的输出数据来增加 ILP(这也基本上通过对更多输入执行相同的工作来增加 ILP)。这种方法基本上是由 Volkov(Better Performance at Lower Occupancy)提出的。

现在 nvcc 编译器驱动程序有一个名为 maxrregcount 的命令行选项,它允许更改每个线程寄存器的使用。使用此选项一次可以强制编译器减少每个线程寄存器的使用,但不能强制它增加它。我有一个案例,我想增加每个线程寄存器的使用,但我无法在内核中展开循环,因为循环边界是数据相关且动态的。到目前为止,我已经尝试了一些技巧,但我已经没有关于如何增加每个线程寄存器使用的想法。任何人都可以建议增加单个 CUDA 线程的寄存器使用率的方法吗?

har*_*ism 2

在某种程度上,这个问题重复了Forcing CUDA to use register for a variable。您已经很好地总结了这些选项。如果您无法通过展开和显式标量变量使用来强制寄存器使用,那么我认为您可能会陷入困境。

请注意,即使具有动态边界的循环也可以部分手动展开。您只需检查循环展开部分内的边界。这可能有助于增加寄存器的使用。

我还认为,增加寄存器使用量和减少延迟之间并不存在保证的直接关系,因此您实际上应该专注于减少延迟,而不是特别关注寄存器使用量。

如果您想减少总体内核延迟,那么您应该尝试一些方法。

  • 启动的线程块数量不得超过 GPU 上可以同时运行的数量(由占用计算器确定)。
  • 最大限度地减少内核函数参数的数量,因为这些参数需要在内核启动期间初始化(因此参数过多会增加启动开销)。