2017-05-26 123 views
0

我想知道是否有人知道更多关于大型嵌套循环崩溃原因的出价吗? 含义我想比较杂注性能OpenMP崩溃vs大型嵌套循环不崩溃

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]; 
           } 
          } 
          } 

其中最大电流,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的最佳性能,我期望这两个编译指示都具有可比较的性能。

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

+0

你的猜测很好。你*测试了两种情况下的表现吗? – Zulan

+1

对于具有这种小体的循环,由于更好地实现了内部循环,当线程数量将“i_max”分开时,非折叠版本可能会更快(多少?_it depends_)。折叠环路可能会抑制其矢量化。 –

+0

@Zulan我做了一些测试,但不知道如何解释我的结果。在一台服务器上,崩溃版本更快,而在另一台服务器上则是非崩溃版本。来这里做一些澄清,因为我没有服务器容量来扩展性地测试它,而不禁止一些模拟。 – LeBo

回答

2

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

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

在另一方面,假设ABC都是i_max X j_max X 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]; 

其中X_lin[]是后面X[][][]数据的线性化1-d图。这里的矢量化有很大的潜力,所以它确实取决于编译器能够执行多少分析。

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

+0

是的<='是错别字! 谢谢您的详尽答案! – LeBo