2012-08-31 41 views
4

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

在这种等待时间的关键应用中,在片上寄存器或共享内存中引入尽可能多的数据,然后尽可能多地使用它,然后再用下一块数据全球记忆。当然,通过增加寄存器压力,跳变占用率下降,但现在我们使用快速片上寄存器隐藏片外存储器延迟。提高每线程寄存器使用率的方法是通过展开循环或计算每个线程的更多输出数据来增加ILP(这也通过在更多输入上完成相同的工作来增加ILP)。沃尔科夫基本上提出了这种方法(在较低占用率下更好的性能)。

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

+0

对不起,但这个问题对我来说似乎完全荒谬。 –

+0

@罗格达尔:如果你刚才看过我提到过的论文,那么你就会明白我在这里想要说明的观点 – nurabha

回答

2

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

请注意,即使具有动态范围的循环可以部分手动展开。你只需要检查循环展开部分的边界。这可能有助于提高注册使用率。

我也认为在增加寄存器使用率和减少延迟之间没有保证的直接关系,所以你真的应该把重点放在减少延迟上,而不是注册使用上。

如果你想减少整体内核延迟,那么你应该尝试一些东西。

  • 发射没有多个线程块比可以在GPU上同时运行(如通过占用量计算来确定)。
  • 最大限度地减少内核函数参数的数量,因为这些参数需要在内核启动时初始化(因此有许多参数可能会增加启动开销)。
+0

我已经阅读了你之前的文章。其实我现在正在尝试手动展开。最初似乎不可能,但昨晚发现了一些技巧。我实际上试图强制编译器分配更少的寄存器以获得更高的占用率,但增加占用率似乎会降低内核中的性能。为什么我认为增加每线程寄存器应该会提高性能。当然,会有一个门槛,超过这个门槛,入住率的下降会影响绩效。但我认为我需要探索这种交换。 – nurabha

+0

我正在使用特斯拉C1060,我的每线程寄存器使用率为32,这限制了每个SM的占用率为50%或两个线程块。正如我所看到的,当我用更多的线程块(每个SM 4个线程块而不是2个)启动我的内核时,我获得了更好的结果。我内核中的参数数目大约是15,现在我认为它太高了。也许我需要连接几个数组和一半参数。 – nurabha

-2

这个问题是诬陷的方式是像问,“我怎么能付更多的钱牛奶在商店?”问题是颠倒。你应该问的是,“我有一定数量的钱,我怎么用它来获得尽可能多的牛奶?”

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

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

如果您确定占用率受其他因素限制,那么您可以询问是否可以通过使用更多寄存器来提高性能(在寄存器成为占用率限制因子之前,寄存器是“空闲”的)。

为此,您开始寻找Space–time tradeoffs的选项。

+2

我认为你对于入住的评论是错误的。 nurav不需要减少他的占用限制资源,因为增加占用率可能会有他想要的完全相反的效果。它可能会增加延迟。他希望减少延迟,而不是增加吞吐量。增加占用率不能减少延迟。直到某一点(虽然有空闲的时隙填充),增加占用率不会增加延迟,但是一旦SM在每个周期完成一条指令,增加它只会增加延迟。 – harrism

+0

@harrism:确切地说。增加我的内核占用率实际上降低了性能。增加占用率可以减少延迟,直到一个点 – nurabha

+0

nurava和@harrism:感谢您的信息和反馈。我读过这篇论文,现在明白你在说什么。它违背了我认为我知道的事情,但是非常有道理。我可能会考虑将这些技术应用于未来的内存绑定内核中。 –

1

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

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

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

它在循环的每次迭代中是独立的吗?我相信关键是寻找独立的计算。 如何分批表演。假设循环次数为N,将其分解为N/M并独立地对它们进行初始化?

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

+1

我也在使用较旧的Tesla Architecture 1.3计算能力。我的顺序算法有四个级别的循环嵌套。在实现CUDA内核后,我通过并行化外部两个循环将它们减少为两个。我无法展开内部循环,现在我正在专注于手动展开外部循环。我基本上采取每个外循环迭代产生更多输出的方法,因为每个循环迭代是独立的。我想到了平铺的方法,但在我的情况下不起作用。 – nurabha

+0

任何有关改进的更新? =) 在我身边,我试图移植到开普勒架构GPU上,加速并没有那么重要。开普勒现在有更多的寄存器分配给每个线程。 –

+0

我继续使用特斯拉C1060。我也无法获得任何加速。我试了2倍和3倍的展开,注册使用率从最初的31增加到41,然后增加到52,但不幸的是性能没有太大的提高。但无论如何,我的内核已经平均32倍速和最高56倍的加速比。 – nurabha