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



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

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

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

在某种程度上,这个问题与强制CUDA为变量使用寄存器重复。你已经很好地总结了各种选择。如果您不能通过展开和显式标量变量使用来强制使用寄存器,那么我认为您可能会陷入困境。

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

我还认为,增加寄存器使用量和减少延迟之间并没有直接的关系,所以实际上你应该专注于减少延迟,而不是特别关注寄存器使用量。

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

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

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

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

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

它在循环的每次迭代中是独立的吗?我认为关键是要寻找独立的计算。批量执行如何。假设循环计数为N,将其拆分为N/M,然后独立计算它们?

当你给出一点线索时,很难给出建议:p

这个问题的表述方式就像在问"我怎么能在商店里花更多的钱买牛奶?"这个问题是颠倒的。你应该问的是,"我有一笔给定的钱。我如何用它来获得尽可能多的牛奶?"

好吧,不是最好的类比,但基本上,这个问题被认为增加寄存器数量本身就是目标,而当然,目标是提高性能。

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

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

为此,您可以开始考虑在空间和时间之间进行权衡。

最新更新