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为什么.希望有人能帮助我
n 有多大?
OpenMP 指令的默认调度parallel for是特定于实现的。看起来在 GOMP(gcc 使用的 OpenMP 实现)中,默认值是(dynamic,1)根据此处的文档。这意味着每个线程正在访问(ati-1和i+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)