OpenMP - Easy Loop,但仍然无限?

Chr*_*ris 5 c++ parallel-processing openmp

我在我的C++代码中使用OpenMP有一个非常奇怪的问题:

void update(double *source, double *target, int n)
{
    target[0] = source[0];
    target[n-1] = source[n-1];
    #pragma omp parallel for 
    for(int i = 1; i < n-1; ++i) 
        target[i] = (1.0/3.0) * (source[i-1] + source[i] + source[i+1]);
}
Run Code Online (Sandbox Code Playgroud)

源和目标都是具有n个元素的双数组.在没有OpenMP的情况下使用它时,代码工作正常.但是一旦我使用pragma,代码就会陷入这个循环中.问题是:我绝对没有IDEA为什么.希望有人能帮助我

mho*_*son 2

n 有多大?

OpenMP 指令的默认调度parallel for是特定于实现的。看起来在 GOMP(gcc 使用的 OpenMP 实现)中,默认值是(dynamic,1)根据此处的文档。这意味着每个线程正在访问(ati-1i+1)由相邻线程加载的内存位置,这可能会导致缓存利用率不佳。在现代 CPU 架构上,像这样的模板操作经常受内存限制并且对缓存敏感。您可以尝试指定具有更大块的计划,例如:

#pragma omp parallel for schedule(dynamic,1024)
Run Code Online (Sandbox Code Playgroud)

我在这里仅使用 1024 作为示例。在实践中,您应该尝试找到最佳分块因子(或使用参数扫描进行系统搜索,该过程通常称为“自动调整”)。或者,您可以选择更多基于理论上的值,例如从 CPU 的 L1 或 L2 缓存大小中得出该值。

或者您可以尝试静态调度,因为 for 循环内的计算量在线程之间是统一的,并且动态调度程序的开销可能会导致瓶颈。如果您指定

#pragma omp parallel for schedule(static)
Run Code Online (Sandbox Code Playgroud)

如果没有块大小,则每个线程将被分配一个大小大致相同的块。

最后,您可能还想将 OpenMP 线程固定到它们自己的 CPU 内核。您可以使用GOMP_CPU_AFFINITY环境变量来执行此操作。

编辑:

我只是在玩下面用 gcc 4.2.1 编译的测试程序,我认为上面链接的文档是不正确的。看起来 GOMP 默认为schedule(static).

#include <stdio.h>
#include <omp.h>

int main(int argc, char** argv)
{
    int i;
    #pragma omp parallel for
    for (i=0; i<15; i++) {
        int id = omp_get_thread_num();
        printf("%d assigned to thread %d\n", i, id);
    }
}
Run Code Online (Sandbox Code Playgroud)

两个线程的输出是:

$ ./test_sched | sort -n
0 assigned to thread 0
1 assigned to thread 0
2 assigned to thread 0
3 assigned to thread 0
4 assigned to thread 0
5 assigned to thread 0
6 assigned to thread 0
7 assigned to thread 0
8 assigned to thread 1
9 assigned to thread 1
10 assigned to thread 1
11 assigned to thread 1
12 assigned to thread 1
13 assigned to thread 1
14 assigned to thread 1
Run Code Online (Sandbox Code Playgroud)