1

我试图在我的代码中使用 OpenMP 并行化以下循环

 double pottemp,pot2body;
 pot2body=0.0;
 pottemp=0.0;

 #pragma omp parallel for reduction(+:pot2body) private(pottemp) schedule(dynamic)
 for(int i=0;i<nc2;i++)
    {
     pottemp=ener2body[i]->calculatePot(ener2body[i]->m_mols);
     pot2body+=pottemp;
    }

对于函数“calculatePot”,该函数内部的一个非常重要的循环也已被 OpenMP 并行化

   CEnergymulti::calculatePot(vector<CMolecule*> m_mols)
   {
        ...

        #pragma omp parallel for reduction(+:dev) schedule(dynamic)
        for (int i = 0; i < i_max; i++)
        {
         ...
         }
     }

所以看来我的并行化涉及嵌套循环。当我删除最外层循环的并行化时,似乎程序运行得比最外层循环并行化的程序快得多。测试在 8 个内核上进行。

我认为这种并行化的低效率可能与嵌套循环有关。有人建议我在并行化最外层循环时使用“折叠”。但是,由于最外层循环和内层循环之间还有一些东西,所以据说在这种情况下不能使用'collapse'。在仍然使用 OpenMP 的同时,还有其他方法可以尝试使这种并行化更有效吗?

非常感谢。

4

1 回答 1

1

如果 i_max 与外循环中的 i 无关,您可以尝试融合循环(基本上是崩溃)。这是我经常做的事情,通常会给我带来小小的推动。我也更喜欢“手动”融合循环而不是使用 OpenMP,因为 Visual Studio 仅支持没有崩溃的 OpenMP 2.0,我希望我的代码可以在 Windows 和 Linux 上运行。

#pragma omp parallel for reduction(+:pot2body) schedule(dynamic)
for(int n=0; n<(nc2*i_max); n++) {
    int i = n/i_max; //i from outer loop
    int j = n%i_max; //i from inner loop 
    double pottmp_j = ... 
    pot2body += pottmp_j;
}

If i_max depends on j then this won't work. In that case follow Grizzly's advice. But one more thing to you can try. OpenMP has an overhead. If i_max is too small then using OpenMP could actually be slower. If you add an if clause at the end of the pragma then OpenMP will only run if the statement is true. Like this:

const int threshold = ... // smallest value for which OpenMP gives a speedup.
#pragma omp parallel for reduction(+:dev) schedule(dynamic) if(i_max > threshold)
于 2013-04-10T11:16:06.977 回答