OpenMP 不会利用所有内核?

Posted

技术标签:

【中文标题】OpenMP 不会利用所有内核?【英文标题】:OpenMP won't utilize all cores? 【发布时间】:2011-09-26 17:38:16 【问题描述】:

我正在尝试使用 OpenMP 使一些代码并行化。

    omp_set_num_threads( 8 );
    #pragma omp parallel 
    for (int i = 0; i < verSize; ++i)
    
        #pragma omp single nowait
         
            neighVec[i].index = i;
            mesh.getBoxIntersecTets(mesh.vertexList->at(i), &neighVec[i]);
        
    

verSize 大约是 90k,而 getBoxIntersecTets 相当昂贵。所以我希望代码能够充分利用四核 cpu。 但是 CPU 使用率只有 25% 左右。 有什么想法吗?

我也尝试使用 omp parallel 进行构造,但情况相同。

getBoxIntersecTets 使用 STL unordered_set、vector 和 deque,但我猜 OpenMP 应该不知道它们,对吧?

谢谢。

【问题讨论】:

【参考方案1】:

首先,#pragma omp single 正在禁用并行执行,你绝对不希望这样。


试试这个:

#pragma omp parallel for private(tempVec)
for (int i = 0; i < verSize; ++i)

    auto tempVec = neighVec[i];
    tempVec.index = i;
    mesh.getBoxIntersecTets(mesh.vertexList->at(i), &tempVec);
    neighVec[i] = tempVec;

原始代码的问题在于不同的线程正在使用数组的相邻元素。相邻元素在内存中彼此相邻放置,这意味着它们可能共享一个缓存行。由于一次只有一个核心可以拥有一个高速缓存行,因此只有一个核心可以一次完成工作。或者更糟的是,您的程序可能会花费更多时间来转移缓存行的所有权,而不是实际工作。

通过引入一个临时变量,每个worker可以对一个独立的cache line进行操作,然后只需要访问最后共享的cache line就可以存储结果。如果第一个参数是通过非常量引用传递的,你应该对它做同样的事情。

【讨论】:

谢谢。我试过了,但 CPU 使用率仍然相同。 getBoxIntersecTets 的第一个参数是 const ref 所以不需要改变它。 @birdsman:mesh 的对象是什么? getBoxIntersecTets 会改变网格的成员变量吗?你会有同样的问题。我也不确定你为什么使用omp single,这也可能是个问题。 mesh 基本上有一个顶点向量和一个四面体向量。 getBoxIntersecTets 进行一些交叉测试并将结果写入 neighVec[i]。它不会改变网格中的任何内容。我尝试使用 omp for 构造,同样的事情。 还是不行。在getBoxIntersecTets 内部,我大量使用了STL 数据结构,并对它们进行了相当多的操作。不过这些都无所谓吧? @birdsman:如果你只是从共享数据结构中读取(本地每个任务的结构应该可以读写),那应该不是问题。

以上是关于OpenMP 不会利用所有内核?的主要内容,如果未能解决你的问题,请参考以下文章

使用 openMP 进行多核处理与多线程

OpenMp 不使用所有 CPU(双插槽、Windows 和 Microsoft Visual Studio)

OpenMp 不使用所有 CPU(双插槽、Windows 和 Microsoft Visual Studio)

确保混合 MPI / OpenMP 在不同的内核上运行每个 OpenMP 线程

什么是 HPC 内核 (MPI-OpenMP)?

Openmp 创建了许多线程,但似乎只使用一个内核