0

我想创建一个大量使用 SCALAPACK 的并行程序。SCALAPACK 的基础是 BLACS,它本身依赖 MPI 进行进程间通信。

我想以定义数量的进程(例如机器上的内核数)启动程序,并让算法决定如何使用这些进程进行计算。

作为测试用例,我想使用 10 个进程。其中 9 个进程应排列成网格 ( BLACS_GRIDINIT),第 10 个进程应等到其他进程完成。

不幸的是,OpenMPI 崩溃是因为最后一个进程没有从 BLACS 进入 MPI 上下文,而其他进程却进入了。

问题:使用 BLACS 处理比需要的更多的正确方法是什么?

我做了一些额外的MPI_INITMPI_FINALIZE调用的实验,但我的尝试都没有成功。


我从 Intel MKL 的示例代码开始(稍微缩短了一点):

      PROGRAM HELLO 
*     -- BLACS example code --
*     Written by Clint Whaley 7/26/94 
*     Performs a simple check-in type hello world 
*     .. 
*     .. External Functions ..
      INTEGER BLACS_PNUM
      EXTERNAL BLACS_PNUM 
*     .. 
*     .. Variable Declaration ..
      INTEGER CONTXT, IAM, NPROCS, NPROW, NPCOL, MYPROW, MYPCOL
      INTEGER ICALLER, I, J, HISROW, HISCOL 

*     Determine my process number and the number of processes in 
*     machine 
      CALL BLACS_PINFO(IAM, NPROCS) 

*     Set up process grid that is as close to square as possible 
      NPROW = INT( SQRT( REAL(NPROCS) ) )
      NPCOL = NPROCS / NPROW 

*     Get default system context, and define grid
      CALL BLACS_GET(0, 0, CONTXT)
      CALL BLACS_GRIDINIT(CONTXT, 'Row', NPROW, NPCOL)
      CALL BLACS_GRIDINFO(CONTXT, NPROW, NPCOL, MYPROW, MYPCOL) 

*     If I'm not in grid, go to end of program 
      IF ( (MYPROW.GE.NPROW) .OR. (MYPCOL.GE.NPCOL) ) GOTO 30

*     Get my process ID from my grid coordinates 
      ICALLER = BLACS_PNUM(CONTXT, MYPROW, MYPCOL) 

*     If I am process {0,0}, receive check-in messages from 
*     all nodes 
      IF ( (MYPROW.EQ.0) .AND. (MYPCOL.EQ.0) ) THEN

         WRITE(*,*) ' '

         DO 20 I = 0, NPROW-1
            DO 10 J = 0, NPCOL-1

               IF ( (I.NE.0) .OR. (J.NE.0) ) THEN
                  CALL IGERV2D(CONTXT, 1, 1, ICALLER, 1, I, J)
               END IF 
*              Make sure ICALLER is where we think in process grid
              CALL BLACS_PCOORD(CONTXT, ICALLER, HISROW, HISCOL)
              IF ( (HISROW.NE.I) .OR. (HISCOL.NE.J) ) THEN
                 WRITE(*,*) 'Grid error!  Halting . . .'
                 STOP
              END IF
              WRITE(*, 3000) I, J, ICALLER
10         CONTINUE 
20      CONTINUE
        WRITE(*,*) ' '
        WRITE(*,*) 'All processes checked in.  Run finished.' 

*     All processes but {0,0} send process ID as a check-in
      ELSE
         CALL IGESD2D(CONTXT, 1, 1, ICALLER, 1, 0, 0)
      END IF

30    CONTINUE

      CALL BLACS_EXIT(0)

1000  FORMAT('How many processes in machine?') 
2000  FORMAT(I) 
3000  FORMAT('Process {',i2,',',i2,'} (node number =',I,
     $       ') has checked in.')

      STOP
      END

更新:我调查了源代码,BLACS看看那里发生了什么。

如果以前没有发生这种情况,该调用BLACS_PINFO会使用 初始化 MPI 上下文。MPI_INIT这意味着,在这一点上,一切都按预期工作。

最后,调用BLACS_EXIT(0)应该释放所有资源BLACS,如果参数是0,它也应该调用MPI_FINALIZE。不幸的是,这没有按预期工作,我的最后一个过程没有调用MPI_FINALIZE.

作为一种解决方法,如有必要,可以询问MPI_FINALIZED并致电。MPI_FINALIZE

更新 2:我之前的尝试是使用Intel Studio 2013.0.079OpenMPI 1.6.2on完成的SUSE Linux Enterprise Server 11

在阅读了cteo的回答后,我尝试使用Ubuntu 12.04gfortran 4.6.3, OpenMPI 1.4.3, BLACS 1.1)给出的工具编译这个例子并且成功了。

我的结论是,英特尔的实施似乎有问题。我将在不久的将来使用 的最新服务版本重试此示例Intel Studio,但不要期望任何更改。

但是,我将不胜感激任何其他(也许更好)的解决方案。

4

2 回答 2

1

我不知道答案,我会冒险猜测参与 SO 的人和知道你的问题答案的人是 < 1。但是,我建议你问的运气可能会好一些在scicomp上或通过他们的支持页面直接联系田纳西大学的 ScaLAPACK 团队。祝你好运!

于 2013-08-29T19:21:23.640 回答
0

我认为您不需要做太多事情就可以在 SCALAPACK 中使用更少的进程。该BLACS_PINFO子例程返回进程总数。如果你想少用一个,就做NPROCS = NPROCS - 1. 我使用了您的示例代码(修复了 FORMAT 中的一些拼写错误),添加了减法并得到以下输出:

$ mpirun -n 4 ./a.out 

Process { 0, 0} (node number = 0) has checked in.
Process { 0, 1} (node number = 1) has checked in.
Process { 0, 2} (node number = 2) has checked in.

 All processes checked in.  Run finished.

BLACS_GRIDINIT创建一个带有缩减的网格NPROCS。通过调用BLACS_GRIDINFO一个进程得到MYPROW=MYPCOL=-1

另一方面,如果您想创建多个使用不同进程的网格,那么您可能应该使用BLACS_GRIDMAP子例程。下面的示例代码创建了两个相等的网格,它们的大小是总进程的一半。

      PROGRAM HELLO 
*     .. 
      INTEGER CONTXT(2), IAM, NPROCS, NPROW, NPCOL, MYPROW, MYPCOL
      INTEGER ICALLER, I, J, HISROW, HISCOL
      integer UMAP(2,10,10)
*     
      CALL BLACS_PINFO(IAM, NPROCS) 
      NPROCS = NPROCS/2
*     
      NPROW = INT( SQRT( REAL(NPROCS) ) )
      NPCOL = NPROCS / NPROW 
*     
      DO IP = 1, 2
        DO I = 1, NPROW
          DO J = 1, NPCOL
            UMAP(IP,I,J) = (IP-1)*NPROCS+(I-1)*NPCOL+(J-1)
          ENDDO
        ENDDO
        CALL BLACS_GET(0, 0, CONTXT(IP))
        CALL BLACS_GRIDMAP(CONTXT(IP), UMAP(IP,:,:), 10, NPROW, NPCOL )
      ENDDO
*
      DO IP = 1, 2
        CALL BLACS_GRIDINFO(CONTXT(IP), NPROW, NPCOL, MYPROW, MYPCOL) 
        IF(MYPROW.GE.0 .AND. MYPCOL.GE.0 ) THEN
          WRITE(*,1000) IAM, MYPROW, MYPCOL, IP
        END IF
      ENDDO

      CALL BLACS_EXIT(0)
 1000 FORMAT('Process ',i2,' is (',i2,','i2 ') of grid ',i2)
*
      STOP
      END

我得到以下输出:

$ mpirun -n 8 ./a.out 
Process  0 is ( 0, 0) of grid  1
Process  1 is ( 0, 1) of grid  1
Process  2 is ( 1, 0) of grid  1
Process  3 is ( 1, 1) of grid  1
Process  4 is ( 0, 0) of grid  2
Process  5 is ( 0, 1) of grid  2
Process  6 is ( 1, 0) of grid  2
Process  7 is ( 1, 1) of grid  2

我没有在零过程中收集数据。因此,如果所有进程都是本地的,则您可以获得此输出。

于 2013-08-30T13:12:29.950 回答