使用OpenMP并行化嵌套循环

时间:2013-04-09 07:39:08

标签: c++ parallel-processing nested openmp

我试图用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时更有效地使这个parllelization更有效吗?

非常感谢。

1 个答案:

答案 0 :(得分: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;
}

如果i_max依赖于j,那么这将不起作用。在这种情况下,请遵循Grizzly的建议。但还有一件事可以尝试。 OpenMP有一个开销。如果i_max太小,那么使用OpenMP实际上可能会更慢。如果在pragma末尾添加if子句,则只有在语句为true时才会运行OpenMP。像这样:

const int threshold = ... // smallest value for which OpenMP gives a speedup.
#pragma omp parallel for reduction(+:dev) schedule(dynamic) if(i_max > threshold)