我有几个问题悬而未决几天没有回答。问题出现了,因为我有一个OpenMP和一个同样问题的OpenCL实现。 OpenCL在GPU上运行完美,但在CPU上运行时性能降低了50%(与OpenMP实现相比)。 post已经在处理OpenMP和OpenCL性能之间的差异,但它没有回答我的问题。目前我面临这些问题:
1)拥有“矢量化内核”(就英特尔脱机编译器而言)真的那么重要吗?
有similar个帖子,但我认为我的问题更为笼统。
据我所知:矢量化内核不一定意味着编译后的二进制文件中没有向量/ SIMD指令。我检查了我的内核的汇编代码,并且有一堆SIMD指令。向量化内核意味着通过使用SIMD指令,您可以在一个CPU线程中执行4(SSE)或8(AVX)OpenCL“逻辑”线程。只有当所有数据连续存储在内存中时,才能实现此目的。但谁拥有如此完美排序的数据?
所以我的问题是:在这个意义上让你的内核“矢量化”真的那么重要吗?
当然它可以提高性能,但如果内核中的大多数计算密集型部分都是通过向量指令完成的,那么您可能会接近“最佳”性能。我认为我的问题的答案在于内存带宽。可能矢量寄存器更适合高效的存储器访问。在这种情况下,内核参数(指针)必须进行矢量化。
2)如果我分配 本地内存中的数据>> ,它将在哪里分配? OpenCL将L1缓存显示为本地内存,但它显然与GPU本地内存上的内存类型不同。如果它存储在RAM /全局存储器中,那么将数据复制到其中是没有意义的。如果它在缓存中,其他一些进程可能会将其刷新......所以这也没有意义。
3)“逻辑”OpenCL线程如何映射到真正的CPU软件/硬件(Intel HTT)线程?因为如果我有短的运行内核并且内核像TBB(线程构建块)或OpenMP那样分叉,那么fork开销将占主导地位。
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)在OpenCL执行期间,每个TBB线程都被分叉一次,并且它们被重用。每个TBB线程都绑定到一个虚拟核心,即。在计算过程中没有线程迁移。
我也接受@ natchouf的答案。
答案 0 :(得分:8)
我可能会对您的问题提出一些提示。 根据我的经验,针对CPU调整的优秀OpenCL实现无法击败良好的OpenMP实现。如果是这样,你可能会改进OpenMP代码以击败OpenCL代码。
1)拥有矢量化内核非常重要。它链接到您的问题3和4.如果您有一个处理4或8个输入值的内核,您将拥有更少的工作项(线程),因此开销更少。我建议使用OpenCL提供的向量指令和数据(如 float4 , float8 , float16 ),而不是依赖于自动向量化。 不要犹豫使用 float16 (或 double16 ):这将被映射到4个sse或2个avx向量,并将16除以所需的工作项数(这是适用于CPU,但并不总是适用于GPU:我使用2个不同的内核用于CPU和GPU)。
2)CPU上的本地内存是RAM。不要在CPU内核上使用它。
3和4)我真的不知道,这将取决于实现,但叉开销对我来说似乎很重要。