我有几天悬而未决的问题没有答案。出现这些问题是因为我有相同问题的 OpenMP 和 OpenCL 实现。OpenCL 在 GPU 上完美运行,但在 CPU 上运行时性能降低 50%(与 OpenMP 实现相比)。一篇文章已经在处理 OpenMP 和 OpenCL 性能之间的差异,但它没有回答我的问题。目前我面临这些问题:
1)拥有“矢量化内核”(就英特尔离线编译器而言)真的那么重要吗?
有一个类似的帖子,但我认为我的问题更笼统。
据我了解:矢量化内核不一定意味着编译后的二进制文件中没有矢量/SIMD 指令。我检查了我的内核的汇编代码,并且有一堆 SIMD 指令。矢量化内核意味着通过使用 SIMD 指令,您可以在一个 CPU 线程中执行 4 个 (SSE) 或 8 个 (AVX) OpenCL“逻辑”线程。这只有在您的所有数据都连续存储在内存中时才能实现。但是谁拥有如此完美排序的数据呢?
所以我的问题是:从这个意义上说,让你的内核“矢量化”真的那么重要吗?
当然它可以提高性能,但是如果内核中的大多数计算密集型部分都是通过向量指令完成的,那么您可能会接近“最佳”性能。我认为我的问题的答案在于内存带宽。向量寄存器可能更适合高效的内存访问。在这种情况下,必须对内核参数(指针)进行矢量化。
2)如果我在CPU的本地内存中分配数据,它将分配到哪里?OpenCL 将 L1 缓存显示为本地内存,但它显然与 GPU 本地内存上的内存类型不同。如果它存储在 RAM/全局内存中,那么将数据复制到其中是没有意义的。如果它在缓存中,其他一些进程可能会将它刷新出来......所以这也没有意义。
3) “逻辑”OpenCL 线程如何映射到真正的 CPU 软件/硬件(Intel HTT)线程?因为如果我的内核运行时间很短,并且内核像在 TBB(线程构建块)或 OpenMP 中那样分叉,那么分叉开销将占主导地位。
4)线程分叉开销是多少?是否为每个“逻辑”OpenCL 线程派生了新的 CPU 线程,或者 CPU 线程是否被派生一次,然后再用于更多“逻辑”OpenCL 线程?
我希望我不是唯一对这些小东西感兴趣的人,你们中的一些人现在可能对这些问题有所了解。先感谢您!
更新
3) 目前,OpenCL 的开销比 OpenMP 更大,因此需要大量内核来实现高效的运行时执行。在 Intel OpenCL 中,工作组映射到 TBB 线程,因此 1 个虚拟 CPU 内核执行整个工作组(或线程块)。一个工作组是用 3 个嵌套的 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) 每个 TBB 线程在 OpenCL 执行期间被分叉一次并被重用。每个 TBB 线程都绑定到一个虚拟内核,即。计算过程中没有线程迁移。
我也接受@natchouf-s 的回答。