回 帖 发 新 帖 刷新版面

主题:mpi并行程序,在vs中把openmp打开后程序发散,望高手赐教

向并行高手请教一下:我的mpi并行程序,在vs中把openmp打开后程序发散,什么原因啊?
P.S:我的是一个工程计算程序,算流场的,需要迭代很多步才收敛,开了openmp后算了100多步就发散了,我本来是想mpi和openmp混编并行,后来发现只要开了openmp原来的mpi程序并行时就发散,后面的就没法做了。

望高手赐教,不胜感激!

回复列表 (共7个回复)

沙发

这发散很难说原因的, 要看具体的代码的. 你的"工程计算程序"的并行代码是别人编写并调试过的吗?

板凳

我自己编写的,没有打开openmp时可以正常运行,打开以后就发散了,这和什么有关系?很难理解,我只是让编译器支持openmp,有没有添加openmp语句,这怎么会影响源程序呢?搞不明白

3 楼

openmp语句只有在打开相应的编译选项才被视为代码的一部分,不打开的情况下就一句注释而已.
如果你已经移除了omp语句,开启跟关闭omp的编译选项都没有关系的. mpi跟omp混编我也做过,没遇到相互冲突的情况.
要不你开两个工程, 一个开启omp选项的, 一个不开. 运行两个程序看那一步开始数据出现差异.(程序规模什么的先调小方便调试)

4 楼


理论上应该如你所说,但是我试了一个更简单的例子,用的是vs2008,PGI fortran 2008,32位系统,打开openmp选项,但没有添加omp语句的情况下,迭代没有发散,但是执行时间变长了。
只有MPI时:13s;打开openmp选项后28s。这一点也让我很奇怪。添加omp语句后边的更慢,linux环境下,混编更加慢。这也让我很不解。
我的QQ:190961506,很希望与你更详细的讨论,切磋一下。

5 楼

! Poisson 方程求解: 使用阻塞通信 (可能死锁)。作者: 莫则尧
      INCLUDE  'mpif.h'
      PARAMETER(DW=2.0, DH=3.0)  ! 问题求解区域沿 X、Y 方向的大小
      PARAMETER(IM=120, JM=240)    ! 沿 X、Y 方向的全局网格规模
      PARAMETER(NPX=2,  NPY=1)   ! 沿 X、Y 方向的进程个数
      PARAMETER(IML=IM/NPX, JML=JM/NPY)
         ! 各进程沿 X、Y 方向的局部网格规模
      REAL  U(0:IML+1, 0:JML+1)  ! 定义在网格结点的近似解
      REAL  US(0:IML+1, 0:JML+1) ! 定义在网格结点的精确解
      REAL  U0(IML, JML)         ! Jacobi 迭代辅助变量
      REAL  F(IML, JML)          ! 函数 $f(x,y)$ 在网格结点上的值
      INTEGER  NPROC             ! mpirun 启动的进程个数, 必须等于 NPX*NPY
      INTEGER  MYRANK,MYLEFT,MYRIGHT,MYUPPER,MYLOWER
                                 ! 各进程自身的进程号, 4 个相邻进程的进程号
      INTEGER  MEPX,MEPY         ! 各进程自身的进程号沿 X、Y 方向的坐标
      REAL  XST,YST              ! 各进程拥有的子区域沿 X、Y 方向的起始坐标
      REAL  HX, HY               ! 沿 X、Y 方向的网格离散步长
      REAL  HX2,HY2,HXY2,RHXY
      INTEGER  IST,IEND,JST,JEND
                      ! 各进程沿 X、Y 方向的内部网格结点的起始和终止坐标
      INTEGER  HTYPE, VTYPE
                      ! MPI 用户自定义数据类型, 表示各进程沿 X、Y 方向
                      ! 与相邻进程交换的数据单元
      INTEGER  STATUS(MPI_STATUS_SIZE)    ! \label{poisson0:1}
      DOUBLE PRECISION T0, T1
! In-line functions
      solution(x,y)=x*x+y*y    ! 解析解
      rhs(x,y)=-4.0              ! Poisson 方程源项 (右端项)
! 程序可执行语句开始
      CALL MPI_Init(IERR)
      CALL MPI_Comm_size(MPI_COMM_WORLD,NPROC,IERR)
      IF (NPROC.NE.NPX*NPY.OR.MOD(IM,NPX).NE.0.OR.MOD(JM,NPY).NE.0) THEN
         PRINT *, '+++ mpirun -np xxx error OR grid scale error, ',
     &            'exit out +++'
     CALL MPI_Finalize(IERR)
         STOP
      ENDIF
! 按自然序 (先沿 X 方向, 后沿 Y 方向) 确定各进程自身及其 4 个相邻进程的进程号
      CALL MPI_Comm_rank(MPI_COMM_WORLD,MYRANK,IERR)
      MYLEFT  = MYRANK - 1
      IF (MOD(MYRANK,NPX).EQ.0)   MYLEFT=MPI_PROC_NULL
      MYRIGHT = MYRANK + 1
      IF (MOD(MYRIGHT,NPX).EQ.0)  MYRIGHT=MPI_PROC_NULL
      MYUPPER = MYRANK + NPX
      IF (MYUPPER.GE.NPROC)       MYUPPER=MPI_PROC_NULL
      MYLOWER = MYRANK - NPX
      IF (MYLOWER.LT.0)           MYLOWER=MPI_PROC_NULL
      MEPY=MYRANK/NPX
      MEPX=MYRANK-MEPY*NPX
!                      对应二维 NPYxNPX Cartesian 行主序坐标为 (MEPY,MEPX).
! 基本变量赋值, 确定各进程负责的子区域
      HX =DW/IM
      HX2=HX*HX
      HY =DH/JM
      HY2=HY*HY
      HXY2=HX2*HY2
      RHXY=0.5/(HX2+HY2)
      DX=HX2*RHXY
      DY=HY2*RHXY
      DD=RHXY*HXY2
      XST=MEPX*DW/NPX
      YST=MEPY*DH/NPY
      IST=1
      IEND=IML
      IF (MEPX.EQ.NPX-1) IEND=IEND-1   ! 最右边的区域 X 方向少一个点
      JST=1
      JEND=JML
      IF (MEPY.EQ.NPY-1) JEND=JEND-1   ! 最上边的区域 Y 方向少一个点
! 数据类型定义
      CALL MPI_Type_contiguous(IEND-IST+1, MPI_REAL, HTYPE, IERR)
      CALL MPI_Type_commit(HTYPE, IERR)
                 ! 沿 X 方向的连续 IEND-IST+1 个 MPI_REAL 数据单元,
                 ! 可用于表示该进程与其上、下进程交换的数据单元
      CALL MPI_Type_vector(JEND-JST+1, 1, IML+2, MPI_REAL, VTYPE, IERR)
      CALL MPI_Type_commit(VTYPE, IERR)
                 ! 沿 Y 方向的连续 JEND-JST+1 个 MPI_REAL 数据单元,
                 ! 可用于表示该进程与其左、右进程交换的数据单元
! 初始化
      DO J=JST-1, JEND+1
      DO I=IST-1, IEND+1
         xx=(I+MEPX*IML)*HX           ! xx=XST+I*HX
         yy=(J+MEPY*JML)*HY           ! yy=YST+J*HY
         IF (I.GE.IST.AND.I.LE.IEND .AND. J.GE.JST.AND.J.LE.JEND) THEN
            U(I,J)  = 0.0             ! 近似解赋初值
            US(I,J) = solution(xx,yy) ! 解析解
            F(I,J)  = DD*rhs(xx,yy)   ! 右端项
         ELSE IF ((I.EQ.IST-1  .AND. MEPX.EQ.0) .OR. 
     &            (J.EQ.JST-1  .AND. MEPY.EQ.0) .OR.
     &            (I.EQ.IEND+1 .AND. MEPX.EQ.NPX-1) .OR.
     &            (J.EQ.JEND+1 .AND. MEPY.EQ.NPY-1)) THEN
            U(I,J) = solution(xx,yy)  ! 边界值
         ENDIF
      ENDDO
      ENDDO

6 楼

! Jacobi 迭代求解
      NITER=0
      T0 = MPI_Wtime()
100   CONTINUE
      NITER=NITER+1
! 交换定义在辅助网格结点上的近似解
      CALL MPI_Send(U(1,1),      1, VTYPE, MYLEFT,  NITER+100, ! \label{poisson0:2}
     &              MPI_COMM_WORLD,IERR)                    ! 发送左边界
      CALL MPI_Send(U(IEND,1),   1, VTYPE, MYRIGHT, NITER+100,
     &              MPI_COMM_WORLD,IERR)                    ! 发送右边界
      CALL MPI_Send(U(1,1),      1, HTYPE, MYLOWER, NITER+100,
     &              MPI_COMM_WORLD,IERR)                    ! 发送下边界
      CALL MPI_Send(U(1,JEND),   1, HTYPE, MYUPPER, NITER+100,
     &              MPI_COMM_WORLD,IERR)                    ! 发送上边界
      CALL MPI_Recv(U(IEND+1,1), 1, VTYPE, MYRIGHT, NITER+100,
     &              MPI_COMM_WORLD,STATUS,IERR)             ! 接收右边界
      CALL MPI_Recv(U(0,1),      1, VTYPE, MYLEFT,  NITER+100,
     &              MPI_COMM_WORLD, STATUS,IERR)            ! 接收左边界
      CALL MPI_Recv(U(1,JEND+1), 1, HTYPE, MYUPPER, NITER+100,
     &              MPI_COMM_WORLD, STATUS,IERR)            ! 接收上边界
      CALL MPI_Recv(U(1,0),      1, HTYPE, MYLOWER, NITER+100,
     &              MPI_COMM_WORLD, STATUS, IERR)           ! 接收下边界 \label{poisson0:3}
      DO J=JST,JEND    ! \label{poisson0:4}
      DO I=IST,IEND
         U0(I,J)=F(I,J)+DX*(U(I,J-1)+U(I,J+1))+DY*(U(I-1,J)+U(I+1,J))
      ENDDO
      ENDDO        ! \label{poisson0:5}
! 计算与精确解间的误差
      ERR=0.0
      DO J=JST,JEND
      DO I=IST,IEND
         U(I,J)=U0(I,J)
         ERR=MAX(ERR, ABS(U(I,J)-US(I,J))) ! 用 $L^\infty$ 模以使误差与NP无关
      ENDDO
      ENDDO
      ERR0=ERR
      CALL MPI_Allreduce(ERR0,ERR,1,MPI_REAL,MPI_MAX,
     &                   MPI_COMM_WORLD,IERR)
      IF (MYRANK.EQ.0 .AND. MOD(NITER,100).EQ.0) THEN
         PRINT *, 'NITER = ', NITER, ',    ERR = ', ERR
         call flush(6)
      ENDIF
      IF (ERR.GT.2.E-3)  THEN     ! 收敛性判断
         GOTO 100                 ! 没有收敛, 进入下次迭代
      ENDIF
      T1 = MPI_Wtime()
      IF (MYRANK.EQ.0) THEN
         PRINT *, ' !!! Successfully converged after ', 
     &            NITER, ' iterations'
         call flush(6)
         PRINT *, ' !!! error = ', ERR, '   wtime = ', T1 - T0
         call flush(6)
      ENDIF
! 输出近似解 (略)
      CALL MPI_Finalize(IERR)
      END
这是一个简单的jacobi迭代mpi程序,你可以试一试,是否会有这种情况。如果开openmp选项后对执行时间没有影响,希望各位朋友将实现的办法贴出来。(注意:请先保证openmp程序能正常运行),如果添加omp语句还能加速,也请将实现的办法贴出来。

7 楼

我是快毕业的人了,现在主要在写论文和毕业论文. 代码已经差不多一年没有大改.
因为mpi只有我一个人用,后来买的服务器都没有配置mpi(ivf+intel mpi), 所以无法去运行你的程序了.
我当时弄的混编没有你这个难度大, 我是先写好串行代码, 再omp并行, 最后外层mpi并行, 一步一步调.
你这个是先mpi再omp我就没经验了.(正如你说,理论上mpi跟omp应该互相没有影响才对)

我来回复

您尚未登录,请登录后再回复。点此登录或注册