GPU上的OpenCL性能问题

时间:2019-03-13 15:54:16

标签: raspberry-pi opencl raspberry-pi3 videocore

我正在使用OpenCL来优化Raspberry Pi GPU(视频核IV)中的某些代码。 我正在使用VC4CL实现,该实现的最大工作组大小为12。

但是,使用简单的内核(例如将两个数组相加),GPU的性能要比CPU的性能差很多。

例如,对于以下内核:

#define GLOBAL_SIZE 12
#define LOCAL_SIZE  1
#define WIDTH       12*12*12
#define NTIMES      1000

__attribute__ ((reqd_work_group_size(LOCAL_SIZE, LOCAL_SIZE, LOCAL_SIZE)))
__kernel void int_sum(global const uint* A, global const uint* B, global uint* C)
{
  int g_id0 = get_global_id(0);
  int g_id1 = get_global_id(1);
  int g_id2 = get_global_id(2);

  int index = g_id0 + g_id1 * GLOBAL_SIZE + g_id2 * GLOBAL_SIZE * GLOBAL_SIZE;

  for(int k = 0; k < NTIMES; k++)
    C[index + k * WIDTH] = A[index + k * WIDTH] + B[index + k * WIDTH];
}

将两个数组的1e6位置相加,CPU的性能要好得多... 我尝试将工作组更改为一维,并尝试使用其他组合,例如(6x6x6->全局大小,2x2x2->局部大小)。 有什么暗示我可能做错了吗?

谢谢。

2 个答案:

答案 0 :(得分:1)

我对这个特定的GPU不熟悉,但是有一些事情在您的代码中可能会引起危险:

  • 这是整数ALU重代码,而不是使用浮点运算。许多GPU根本没有为此优化。
  • 我不会依赖编译器来优化数组偏移量计算;一个特别愚蠢的编译器可能在每次循环迭代中为C[index + k * WIDTH] = A[index + k * WIDTH] + B[index + k * WIDTH];发出3个整数乘法。我会将偏移量保留在变量中,并在每次迭代时将其添加到变量中,而无需乘法。
  • 1000迭代的for循环通常是更好的并行性的潜在来源。许多GPU在长时间运行的内核中表现不佳。
  • 内存访问模式似乎不是最佳的。尝试安排事物,以使组中的相邻工作项访问相邻的内存位置。 2x2x2本地大小似乎是一个特别糟糕的选择。您尝试过12x1x1吗?
  • 您为什么还要用这种方式安排工作项?看来您实际上是在为C[i] = A[i] + B[i]计算i = 0..1000*12*12*12。如此精确地编写内核并在一维提交1728000个工作项怎么样?这样可以节省所有复杂的索引计算。

如果您可以从驱动程序中获得任何反馈,则GPU受其约束(ALU,内存负载,线程调度等),这将在选择寻找加速方法的位置方面大有帮助。

答案 1 :(得分:1)

除了其他人在评论中所说的以外,according to the RPi's OpenCL implementation author, GPU的“内存访问速度”(CPU-GPU内存副本?)比CPU慢得多。因此,像数组和之类的“算术轻”内核将受到内存带宽的限制,并且可能比CPU上慢得多。此外,理论上的GPU GFlops并不比GPU的高(24 vs 6)。

除非您有一些非常计算量很大的内核也可以完全向量化,否则您可能会发现使用GPU根本不值得。