CPU/Intel OpenCL性能问题,实现问题

10
我有一些问题已经悬而未决了几天。这些问题是因为我有一个相同问题的OpenMP和OpenCL实现。OpenCL在GPU上运行得非常完美,但在CPU上运行时性能比OpenMP实现低50%。post已经讨论了OpenMP和OpenCL性能差异的问题,但它没有回答我的问题。目前我面临以下问题:
1)是否真的很重要要有“向量化内核”(就英特尔离线编译器而言)?
有一个similar的帖子,但我认为我的问题更普遍。
据我了解:向量化内核并不意味着编译后的二进制代码中没有向量/SIMD指令。我检查了我的内核的汇编代码,发现有很多SIMD指令。向量化内核意味着通过使用SIMD指令,您可以在一个CPU线程中执行4个(SSE)或8个(AVX)OpenCL“逻辑”线程。只有当您的所有数据都按顺序存储在内存中时,才能实现这一点。但是,谁有如此完美排序的数据呢?
所以我的问题是:以这种方式使您的内核“向量化”真的很重要吗?
当然,它可以提高性能,但如果内核中大部分计算密集型部分都由向量指令完成,则可能会接近“最佳”性能。我认为答案在于内存带宽。可能更适合有效内存访问的是矢量寄存器。在这种情况下,内核参数(指针)必须被向量化。

2) 如果我在CPU上的本地内存中分配数据,它将被分配到哪里?OpenCL将L1缓存显示为本地内存,但它显然不是像GPU本地内存那样的内存类型。如果存储在RAM /全局内存中,那么将数据复制到其中就没有意义了。如果它在缓存中,可能会有其他进程将其清除...因此这也没有意义。

3) “逻辑” OpenCL 线程如何映射到实际的 CPU 软件/硬件(Intel HTT)线程?因为如果我有短的运行内核,并且内核像 TBB(Thread Building Blocks)或 OpenMP 中那样被分叉,那么分叉开销将占主导地位。

4) 线程分叉的开销是什么?对于每个“逻辑” OpenCL 线程是否都会新建一个 CPU 线程,还是 CPU 线程只会被分叉一次,然后被更多的“逻辑” OpenCL 线程重用?

我希望我不是唯一对这些微小问题感兴趣的人,你们中的一些人可能知道这些问题的一些细节。提前感谢您!


更新

3) 目前,OpenCL 的开销比 OpenMP 更重要,因此需要使用大型内核以实现高效的运行时执行。在英特尔 OpenCL 中,一个工作组被映射到一个 TBB 线程,因此一个虚拟 CPU 核心执行整个工作组(或线程块)。工作组由三个嵌套的 for 循环实现,其中最内层循环在可能的情况下进行矢量化。因此,您可以将其想象为:

#pragam omp parallel for
for(wg=0; wg < get_num_groups(2)*get_num_groups(1)*get_num_groups(0); wg++) {

  for(k=0; k<get_local_size(2); k++) {
    for(j=0; j<get_local_size(1); j++) {
      #pragma simd
      for(i=0; i<get_local_size(0); i++) {
        ... work-load...
      }
    }
  }
}

如果最内层循环可以进行矢量化,则使用SIMD步骤进行迭代:
for(i=0; i<get_local_size(0); i+=SIMD) {

4) 在OpenCL执行过程中,每个TBB线程会被分叉一次并被重复使用。每个TBB线程都绑定到一个虚拟核心,即计算过程中没有线程迁移。

我也接受@natchouf-s的答案。


与大多数GPU不同,CPU缓存不能直接寻址。数据始终存储在主内存中,如果它适合缓存,则尽可能长时间地保留在缓存中。 - Hristo Iliev
2个回答

8
我对你的问题有一些提示。根据我的小经验,针对CPU优化的良好OpenCL实现不能超过良好的OpenMP实现。如果可以,您可能需要改进OpenMP代码以打败OpenCL。
1)拥有矢量化内核非常重要。这与您的第3和4个问题相关。如果您有一个处理4或8个输入值的内核,您将拥有更少的工作项(线程),因此开销更小。我建议使用OpenCL提供的矢量指令和数据(如float4、float8、float16),而不是依赖于自动矢量化。不要犹豫使用float16(或double16):这将映射到4个sse或2个avx向量,并将工作项所需的数量除以16(这对于CPU很好,但并不总是适用于GPU:我为CPU和GPU使用2个不同的内核)。
2)在CPU上,本地内存是RAM。不要在CPU内核中使用它。
3和4)我不太清楚,这取决于实现,但fork开销对我来说似乎很重要。

首先,感谢您的回答,它们在完全黑暗的情况下为我提供了指引。根据您的前两个答案,我需要完全重写内核,并查看其在 CPU 和 GPU 上是否正常工作。如果我完成了这项工作,我会通知您。 - laszlo.endre
2
关于#2,我之前读过一篇论文,他们通过使任何全局请求完全提交或读取而不使用缓存来将本地内存强制放入缓存中。这可能是一个有趣的概念,但就目前而言,英特尔和AMD确实只是将所有数据都塞进RAM中,你说得对。 - KLee1
3
你需要两个独立的内核,一个用于GPU,一个用于CPU,并在运行时决定你正在运行哪一个。GPU优化通常对CPU不利,反之亦然。 - KLee1

1

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接