OpenMP GCC GOMP浪费的障碍

Any*_*orn 7 gcc openmp

我有以下程序.nv大约是100,dgemm是20x100左右,所以有很多工作要做:

#pragma omp parallel for schedule(dynamic,1)
        for (int c = 0; c < int(nv); ++c) {
            omp::thread thread;                                               
            matrix &t3_c = vv_.at(omp::num_threads()+thread);
            if (terms.first) {
                blas::gemm(1, t2_, vvvo_, 1, t3_c);
                blas::gemm(1, vvvo_, t2_, 1, t3_c);
            }

            matrix &t3_b = vv_[thread];
            if (terms.second) {
                matrix &t2_ci = vo_[thread];
                blas::gemm(-1, t2_ci, Vjk_, 1, t3_c);
                blas::gemm(-1, t2_ci, Vkj_, 0, t3_b);
            }
        }
Run Code Online (Sandbox Code Playgroud)

但是对于GCC 4.4,GOMP v1,gomp_barrier_wait_end占运行时间的近50%.更改可以GOMP_SPINCOUNT减少开销,但只使用60%的核心.同样的OMP_WAIT_POLICY=passive.该系统是Linux,8核.

如何在不旋转/等待过度的情况下获得充分利用

Jon*_*rsi 3

障碍是一种症状,而不是问题。在循环结束时出现大量等待的原因是,某些线程先于其他线程完成,并且它们都在 for 循环结束时等待相当长的时间,直到每个线程都完成为止。

这是一个经典的负载不平衡问题,这很奇怪,因为它只是一堆矩阵乘法。它们的大小不同吗?就 NUMA 而言,它们在内存中是如何布局的——它们当前都位于一个核心的缓存中,还是存在其他共享问题?或者,更简单地说——是否只有 9 个矩阵,那么剩下的 8 个矩阵注定要等待谁获得最后一个矩阵?

当这种事情发生在较大的并行代码块中时,有时可以在某些循环迭代尚未完成时继续执行下一个代码块;在那里,您可以将nowait指令添加到 for 中,这将覆盖默认行为并消除隐含的障碍。但在这里,由于并行块的大小恰好是 for 循环的大小,因此这并没有什么帮助。