性能 OpenMP 崩溃与大型嵌套循环的不崩溃

Len*_*nBo 1 c openmp

我想知道是否有人更了解大型嵌套循环的崩溃原因的性能?意思是我想比较编译指示

omp parallel for private(i,j,k) collapse(3) schedule(static)

omp parallel for private(i,j,k) schedule(static)

对于嵌套循环结构,如

for(int i=0; i<i_max; i++){
  for(int j=0; j<j_max; j++){
   for(int k=0; k<k_max; k++){
     A[i][j][k]=B[i][j][k]+C[i][j][k];
                              }
                             }
                            }
Run Code Online (Sandbox Code Playgroud)

其中 i_max、j_max 和 k_max 都比可用线程数大 5 - 10 倍。

如果我正确理解了崩溃原因,openmp 只会将 3 个循环折叠为一个具有相同大小的循环,i_max*j_max*k_max如果(i_max*j_max*k_max) mod #threads = 0.

如果没有崩溃,openmp 只会让 i 循环并行,这是正确的吗?如果是这样,我的下一个假设将是获得最佳性能,i_max mod #threads = 0并且我希望两种 pragma 具有可比的性能。

正如你所看到的,我在这里几乎是在猜测。有没有人真正测试过这两种编译指示的性能?

Hri*_*iev 5

当您折叠循环时,OpenMP 会将它们变成一个大循环。然后,该循环的迭代空间被分成多个块,这些块根据有效的循环调度在线程之间拆分。根据单个循环迭代除以线程数的可分性,您可能最终会遇到块包含不完整内部循环的情况。的示例情况是当没有的i_maxj_maxk_max是整除的线程的数量,但i_max * j_max * k_max是。此外,不同的块可能包含不完整循环的不同部分。然后这一切都取决于运行时可配置的线程数。因此,可能会禁止矢量化器,因为编译器无法可靠地对循环的矢量化进行建模并评估它是否有益。它还必须创建串行循环来处理循环迭代次数不能被向量长度整除或数据未对齐的情况。

当只有外循环是并行的时,编译器可以自由地转换它认为合适的内循环,例如,它可以安全地矢量化这些循环。这是否会比前一种情况更快尚不清楚。矢量化提高了计算性能,但也给内存子系统带来了更大的压力。这些比例决定了是否会有好处。

在另一方面,假设ABC都是i_maxX j_maxX k_max(这x <= x_max是一个错字和实际上应该是x < x_max),一个真正聪明的编译器会注意到你迭代所有可能的指标和基本总结两个1 d载体和转折叠的循环变成类似的东西

#pragma omp parallel schedule(static)
for (z = 0; z < i_max * j_max * k_max; z++)
   A_lin[z] = B_lin[z] + C_lin[z];
Run Code Online (Sandbox Code Playgroud)

X_lin[]后面数据的线性化一维视图在哪里X[][][]?这里有很大的矢量化潜力,因此它实际上取决于编译器能够执行多少分析。

没有银弹解决方案,也没有一种算法可以在多种类型的硬件上表现同样出色。这就是 OpenMP 提供了许多可以通过环境变量设置的可调参数的原因。另请注意,在比较服务器 CPU 和台式机 CPU 的性能时,应记住服务器 CPU 通常具有更大的最后一级缓存和更多内存通道以及更高的主内存带宽,因此矢量化代码在大量运行时性能更好数据的。