如何使用 MPI 和 OpenMP 运行并行循环

Posted

技术标签:

【中文标题】如何使用 MPI 和 OpenMP 运行并行循环【英文标题】:How to use MPI and OpenMP to run a parallel loop 【发布时间】:2019-11-14 16:50:20 【问题描述】:

我需要使用 MPI 和 OpenMP(2 个不同的问题)来并行化来自 Sbac-Pad 马​​拉松的代码(参考:http://lspd.mackenzie.br/marathon/18/problems.html)。我正在研究 himeno 基准。我相信这段代码中唯一值得并行化的部分是 jacobi 函数:

#define MR(mt,n,r,c,d)  mt->m[(n) * mt->mrows * mt->mcols * mt->mdeps + (r) * mt->mcols* mt->mdeps + (c) * mt->mdeps + (d)]

struct Matrix 
  float* m;
  int mnums;
  int mrows;
  int mcols;
  int mdeps;
;

float
jacobi(int nn, Matrix* a,Matrix* b,Matrix* c,
       Matrix* p,Matrix* bnd,Matrix* wrk1,Matrix* wrk2)

  int    i,j,k,n,imax,jmax,kmax;
  float  gosa,s0,ss;

  imax= p->mrows-1;
  jmax= p->mcols-1;
  kmax= p->mdeps-1;

  for(n=0 ; n<nn ; n++)
    gosa = 0.0;
    for(i=1 ; i<imax; i++)
      for(j=1 ; j<jmax ; j++)
        for(k=1 ; k<kmax ; k++)
          s0= MR(a,0,i,j,k)*MR(p,0,i+1,j,  k)
            + MR(a,1,i,j,k)*MR(p,0,i,  j+1,k)
            + MR(a,2,i,j,k)*MR(p,0,i,  j,  k+1)
            + MR(b,0,i,j,k)
             *( MR(p,0,i+1,j+1,k) - MR(p,0,i+1,j-1,k)
              - MR(p,0,i-1,j+1,k) + MR(p,0,i-1,j-1,k) )
            + MR(b,1,i,j,k)
             *( MR(p,0,i,j+1,k+1) - MR(p,0,i,j-1,k+1)
              - MR(p,0,i,j+1,k-1) + MR(p,0,i,j-1,k-1) )
            + MR(b,2,i,j,k)
             *( MR(p,0,i+1,j,k+1) - MR(p,0,i-1,j,k+1)
              - MR(p,0,i+1,j,k-1) + MR(p,0,i-1,j,k-1) )
            + MR(c,0,i,j,k) * MR(p,0,i-1,j,  k)
            + MR(c,1,i,j,k) * MR(p,0,i,  j-1,k)
            + MR(c,2,i,j,k) * MR(p,0,i,  j,  k-1)
            + MR(wrk1,0,i,j,k);

          ss= (s0*MR(a,3,i,j,k) - MR(p,0,i,j,k))*MR(bnd,0,i,j,k);

          gosa+= ss*ss;
          MR(wrk2,0,i,j,k)= MR(p,0,i,j,k) + omega*ss;
        

    for(i=1 ; i<imax ; i++)
      for(j=1 ; j<jmax ; j++)
        for(k=1 ; k<kmax ; k++)
          MR(p,0,i,j,k)= MR(wrk2,0,i,j,k);

   /* end n loop */

  return(gosa);

问题是,这个函数似乎具有顺序性,因为nn 的每次迭代都依赖于最后一个。我尝试使用 MPI 为 gosa (auxgosa) 创建一个辅助变量,并在 i j k for 循环之后使用 MPI_REDUCE,如下所示(根进程为 rank = 0):

//rank is the current process
//size is the total amount of processes

int start = ((imax+1)/size)*rank; 
int stop = ((imax+1)/size)*(rank+1)-1;

  if(rank == 0)start++;

  for(n=0 ; n<nn ; n++)
    gosa = 0.0;
    auxgosa = 0.0;

    for(i=start ; i<stop; i++)
      for(j=1 ; j<jmax ; j++)
        for(k=1 ; k<kmax ; k++)
          s0= MR(aa,0,i,j,k)*MR(pp,0,i+1,j,k)
            + MR(aa,1,i,j,k)*MR(pp,0,i,  j+1,k)
            + MR(aa,2,i,j,k)*MR(pp,0,i,  j,  k+1)
            + MR(bb,0,i,j,k)
             *( MR(pp,0,i+1,j+1,k) - MR(pp,0,i+1,j-1,k)
              - MR(pp,0,i-1,j+1,k) + MR(pp,0,i-1,j-1,k) )
            + MR(bb,1,i,j,k)
             *( MR(pp,0,i,j+1,k+1) - MR(pp,0,i,j-1,k+1)
              - MR(pp,0,i,j+1,k-1) + MR(pp,0,i,j-1,k-1) )
            + MR(bb,2,i,j,k)
             *( MR(pp,0,i+1,j,k+1) - MR(pp,0,i-1,j,k+1)
              - MR(pp,0,i+1,j,k-1) + MR(pp,0,i-1,j,k-1) )
            + MR(cc,0,i,j,k) * MR(pp,0,i-1,j,  k)
            + MR(cc,1,i,j,k) * MR(pp,0,i,  j-1,k)
            + MR(cc,2,i,j,k) * MR(pp,0,i,  j,  k-1)
            + MR(awrk1,0,i,j,k);

          ss= (s0*MR(aa,3,i,j,k) - MR(pp,0,i,j,k))*MR(abnd,0,i,j,k);

          auxgosa+= ss*ss;
          MR(awrk2,0,i,j,k)= MR(pp,0,i,j,k) + omega*ss;
        

    MPI_Reduce(&auxgosa,&gosa,1,MPI_FLOAT,MPI_SUM,0,MPI_COMM_WORLD);

    for(i=1 ; i<imax ; i++)
      for(j=1 ; j<jmax ; j++)
        for(k=1 ; k<kmax ; k++)
          MR(pp,0,i,j,k)= MR(awrk2,0,i,j,k);

   /* end n loop */

很遗憾,这不起作用。谁能给我一些关于这个的见解?我计划对 OpenMP 使用类似的策略。

【问题讨论】:

【参考方案1】:

如果awrk2不同于apbcwrk1,则不存在循环携带依赖。

简单的谷歌搜索将指向 Himeno 基准测试的并行版本(MPI、OpenMP 和混合 MPI+OpenMP 版本可用)。

【讨论】:

以上是关于如何使用 MPI 和 OpenMP 运行并行循环的主要内容,如果未能解决你的问题,请参考以下文章

OpenMp实现并行化

MPI和OpenMP混合编程并行计算--入门程序

Windows和Linux系统下并行计算环境MPI和OpenMP的搭建

谐波级数和 c++ MPI 和 OpenMP

在 OpenMP 中,我们如何并行运行多个代码块,其中每个代码块包含 omp single 和 omp for 循环?

请看看则个fortran结合openmp并行程序,为啥老出错?