OpenCL内核中的变量'for-loop'降低了性能

Cia*_*ano 3 opencl

我的内核中有一个for循环,我已经硬编码迭代我的代码的固定数量的循环:

for (int kk = 0; kk < 50000; kk++)
{
  <... my code here ...>
}
Run Code Online (Sandbox Code Playgroud)

我不认为循环中的代码与我的问题相关,它是一些非常简单的表查找和整数数学.

我想让我的内核代码更灵活,所以我修改了循环,以便我的循环(50000)的迭代次数被内核输入参数'num_loops'替换.

for (int kk = 0; kk < num_loops; kk++)
{
  <... more code here ...>
}
Run Code Online (Sandbox Code Playgroud)

我发现的是,即使我的宿主程序调用内核

num_loops = 50000 
Run Code Online (Sandbox Code Playgroud)

这是与之前硬编码值相同的值,我内核的性能几乎减少了一半.

我试图找出导致性能下降的原因.我想它与OpenCL编译器无法有效地展开循环有关?

有没有办法在不招致性能损失的情况下做我想做的事情?

更新:以下是使用"#pragma unroll"播放的一些结果

不幸的是,似乎展开循环并不能解决我的性能问题.

即使展开硬编码循环也会降低性能.

这是具有硬编码值的正常循环(最佳性能):

for (int kk = 0; kk < 50000; kk++)
// Time to execute = 0.18 (40180 Mi ops/sec)
Run Code Online (Sandbox Code Playgroud)

如果我展开循环,情况会变得更糟:

#pragma unroll
// or #pragma unroll 50000
for (int kk = 0; kk < 50000; kk++)
// Time to execute = 0.22 (33000 Mi ops/sec)
Run Code Online (Sandbox Code Playgroud)

这是使用变量num_loops = 50000的循环:

for (int kk = 0; kk < num_loops; kk++)
// Time to execute = 0.26 (27760 Mi ops/sec)

#pragma unroll 50000
for (int kk = 0; kk < num_loops; kk++)
// Time to execute = 0.26 (27760 Mi ops/sec)

#pragma unroll
for (int kk = 0; kk < num_loops; kk++)
// Time to execute = 0.24 (30280 Mi ops/sec)
Run Code Online (Sandbox Code Playgroud)

使用带有直接"#pragma unroll"的num_loops变量时情况确实会好一些,但即使这种性能仍​​然比硬编码的展开版本慢约25%.

关于如何使用num_loops作为循环变量而不会导致性能损失的任何其他想法?

jpr*_*ice 9

是的,性能下降的最可能原因是编译器无法展开循环.您可以尝试一些改善这种情况的方法.


您可以将参数定义为通过程序构建选项传递的预处理器宏.这是用于构建仅在运行时作为编译时常量在内核中已知的值的常用技巧.例如:

clBuildProgram(program, 1, &device, "-Dnum_loops=50000", NULL, NULL);
Run Code Online (Sandbox Code Playgroud)

您可以动态构建构建选项,sprintf以使其更灵活.显然,如果您不需要经常更改参数,这将是值得的,因此重新编译的开销不会成为问题.


您可以调查您的OpenCL平台是否使用任何编译指示,这些编译指示可以为编译器提供有关循环展开的提示.例如,一些OpenCL编译器识别#pragma unroll(或类似).OpenCL 2.0有一个属性:__attribute__((opencl_unroll_hint)).


您可以手动展开循环.这看起来如何取决于您可以对num_loops参数做出的假设.例如,如果您知道(或可以确保)它将始终是4的倍数,您可以执行以下操作:

for (int kk = 0; kk < num_loops;)
{
  <... more code here ...>
  kk++;
  <... more code here ...>
  kk++;
  <... more code here ...>
  kk++;
  <... more code here ...>
  kk++;
}
Run Code Online (Sandbox Code Playgroud)

即使您不能做出这样的假设,您仍然可以执行手动展开,但可能需要一些额外的工作(例如,完成任何剩余的迭代).