将 mpi 与 openMP 相结合

Combine mpi with openMP

我正在尝试使用 MPI、openMP 以及这两者的组合来解决问题。 MPI 和 openMP 都 运行ning 很好,但是当我尝试 MPI-openMP 版本的代码时,我无法通过 post.

末尾出现错误

MPI 版本

for(i=0;i<loop;i++)               
{
  for(j=start;j<end+1;j++)        
  {
    for(k=0;k<N;k++)              
    {
      if(j!=k)
      {
        dx=C[k*3+0]-C[j*3+0];
        dy=C[k*3+1]-C[j*3+1];
        dz=C[k*3+2]-C[j*3+2];

        d=sqrt(pow(dx,2)+pow(dy,2)+pow(dz,2));

        dCube=pow(d,3);
        mSquare=pow(m,2);

        F[(j-start)*3+0]-=G*mSquare/dCube*dx;
        F[(j-start)*3+1]-=G*mSquare/dCube*dy;
        F[(j-start)*3+2]-=G*mSquare/dCube*dz;
      }
    }
  }
  for(j=0;j<length;j++)                           
  {
    for(k=0;k<3;k++)                               
    {
      a=F[j*3+k]/m;                               
      V[j*3+k]=V[j*3+k]+a*dt;                     
      Cw[j*3+k]=C[(j+start)*3+k]+V[j*3+k]*dt;     
    }
  }
  MPI_Allgatherv(&Cw[0],length*3,MPI_DOUBLE,&C[0],counts,displs,MPI_DOUBLE,MPI_COMM_WORLD);
}

openMP 版本

#pragma omp parallel private(i,k,dx,dy,dz,d,dCube,mSquare,a)
{
  for(i=0;i<loop;i++)                          
  {
    #pragma omp for schedule(static)
      for(j=0;j<N;j++)                         
      {
        for(k=0;k<N;k++)                       
        {
          if(j!=k)
          {
            dx=C[k*3+0]-C[j*3+0];
            dy=C[k*3+1]-C[j*3+1];
            dz=C[k*3+2]-C[j*3+2];

            d=sqrt(pow(dx,2)+pow(dy,2)+pow(dz,2));

            dCube=pow(d,3);
            mSquare=pow(m,2);

            F[j*3+0]-=G*mSquare/dCube*dx;
            F[j*3+1]-=G*mSquare/dCube*dy;
            F[j*3+2]-=G*mSquare/dCube*dz;
          }
        }
      }
    #pragma omp for schedule(static)
      for(j=0;j<N;j++)                        
      {
        for(k=0;k<3;k++)                      
        {
          a=F[j*3+k]/m;                       
          V[j*3+k]=V[j*3+k]+a*dt;             
          C[j*3+k]=C[j*3+k]+V[j*3+k]*dt;      
        }
      }
  }
}

i 循环不能并行,因为每个循环都需要更新 C,所以并行部分从 j

开始

合并版

#pragma omp parallel private(i,k,dx,dy,dz,d,dCube,mSquare,a)
  {
    for(i=0;i<loop;i++)                                 
    {
      #pragma omp for schedule(static)
        for(j=start;j<end+1;j++)                        
        {
          for(k=0;k<N;k++)                              
          {
            if(j!=k)
            {
              dx=C[k*3+0]-C[j*3+0];
              dy=C[k*3+1]-C[j*3+1];
              dz=C[k*3+2]-C[j*3+2];

              d=sqrt(pow(dx,2)+pow(dy,2)+pow(dz,2));

              dCube=pow(d,3);
              mSquare=pow(m,2);

              F[(j-start)*3+0]-=G*mSquare/dCube*dx;
              F[(j-start)*3+1]-=G*mSquare/dCube*dy;
              F[(j-start)*3+2]-=G*mSquare/dCube*dz;
            }
          }
        }
      #pragma omp for schedule(static)
        for(j=0;j<length;j++)                           
        {
          for(k=0;k<3;k++)                              
          {
            a=F[j*3+k]/m;                               
            V[j*3+k]=V[j*3+k]+a*dt;                     
            Cw[j*3+k]=C[(j+start)*3+k]+V[j*3+k]*dt;     
          }
        }
      MPI_Allgatherv(&Cw[0],length*3,MPI_DOUBLE,&C[0],counts,displs,MPI_DOUBLE,MPI_COMM_WORLD);
    }
  }

我在这里用 MPI 试图实现的是在每个节点中说 C 的 部分作为上面的 MPI 方法工作,然后是 openMP计算出Cwtables对应这部分。然后 MPI 在 C table 中收集 MPI_Allgather 的结果并重新开始 loop 次。问题是当我 运行 上面的代码出现此错误时:

Assertion failed in file src/mpid/ch3/src/ch3u_request.c at line 572: *(&incomplete) >= 0

= BAD TERMINATION OF ONE OF YOUR APPLICATION PROCESSES
= PID 10389 RUNNING AT felix-desktop
= EXIT CODE: 139
= CLEANING UP REMAINING PROCESSES
= YOU CAN IGNORE THE BELOW CLEANUP MESSAGES

YOUR APPLICATION TERMINATED WITH THE EXIT STRING: Segmentation fault (signal 11)
This typically refers to a problem with your application.
Please see the FAQ page for debugging suggestions

问题出在 MPI_Allgather 行代码中,但我不知道是什么原因造成的。

您正在并行区域内调用 MPI_Allgather。因此,多个线程使用相同的通信器( MPI_COMM_WORLD)调用 MPI 例程,这是 MPI 不允许的标准。不过,您可以确保 MPI_Allgather 例程由单个线程调用:

#pragma omp parallel private(i,k,dx,dy,dz,d,dCube,mSquare,a)
{
  ... 
  #pragma omp master 
  MPI_Allgatherv(&Cw[0],length*3,MPI_DOUBLE,&C[0],counts,displs,MPI_DOUBLE,MPI_COMM_WORLD);
  #pragma omp barrier 
}

通过添加 OpenMP 子句 master 可以确保只有一个线程调用 MPI_Allgather master 线)。为确保您没有竞争条件(即, 线程更改将在 MPI_Allgatherv MPI 调用中使用的内容)OpenMP barrier 是在 MPI_Allgather 之后添加的。因此,所有进程的所有线程都将等待,直到其进程的 master 线程完成执行 MPI_Allgather 调用。

如果您使用的 MPI 版本的线程支持级别为 MPI_THREAD_SERIALIZED,那么您可以使用构造函数 single 而不是 master。确保 MPI 实现的线程支持级别至少为 MPI_THREAD_FUNNELED.

另一种方法是将MPI_Allgather例程移动到并行区域之外:

for(i=0;i<loop;i++)                                 
{
  #pragma omp parallel private(i,k,dx,dy,dz,d,dCube,mSquare,a){
  ...
  }
  MPI_Allgatherv(&Cw[0],length*3,MPI_DOUBLE,&C[0],counts,displs,MPI_DOUBLE,MPI_COMM_WORLD);
}     

由于 体面的 OpenMP 实现将使用线程池,因此只初始化线程一次,因此应该可以减少多个并行区域创建开销。