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

时间:2012-08-31 00:44:26

标签: memory cuda latency cpu-registers

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

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

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

3 个答案:

答案 0 :(得分:2)

在某种程度上,这个问题重复了Forcing CUDA to use register for a variable。您已经很好地总结了这些选项。如果你不能通过展开和显式标量变量使用强制注册使用,那么我认为你可能会被卡住。

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

我还认为增加寄存器使用和减少延迟之间没有保证的直接关系,所以你应该专注于减少延迟,尤其是寄存器使用。

如果您想减少整体内核延迟,那么您应该尝试一些事情。

  • 不再启动可以在GPU上同时运行的线程块(由占用计算器确定)。
  • 最小化内核的函数参数数量,因为这些参数需要在内核启动期间进行初始化(因此有许多参数会增加启动开销)。

答案 1 :(得分:1)

有趣的问题!我正在尝试这种使用ILP的方法来提供更好的性能!事实上,因为我受到旧架构GPU的限制,每个线程分配的寄存器较少,所以使用ILP实际上可以提高性能,因为它通过循环展开(独立指令)释放寄存器以进行更多计算工作!

我想知道你有多少嵌套循环?如果内循环无法展开,可能会上升一个级别并寻找机会?

要增加每个线程的寄存器使用量,是否减少了启动的块数(线程较小)? 要增加寄存器/线程的使用,请加载多组数据以并行执行。

它在循环的每次迭代中是独立的吗?我认为关键是要寻找独立的计算方法。 怎么样分批表演。假设循环计数为N,将其拆分为N / M并独立地进行omcpute?

当你提出一些线索时,很难给出建议:P

答案 2 :(得分:-2)

这个问题的构思方式就像问“我怎样才能在商店里为牛奶支付更多钱?”问题是颠倒的。你应该问的是,“我有一定数量的钱。我如何使用它来获得尽可能多的牛奶?”

好吧,不是最好的类比,但基本上,问题就是说增加注册计数本身就是目标,当然,目标是提高性能。

所以,首先要确定的是,你有多少个寄存器吗?如果寄存器是内核中的占用限制因素。当内核受内存限制时,更改代码以便使用更多寄存器可能不是一个好主意。

如果您已确定占用率受到其他因素的限制,那么您可以询问是否可以通过使用更多寄存器来提高性能(寄存器随后会“自由”,直到寄存器成为占用限制因素)。

为此,您开始查看Space–time tradeoffs的选项。