首页
学习
活动
专区
工具
TVP
发布
社区首页 >问答首页 >在fortran程序中运行MPI子程序

在fortran程序中运行MPI子程序
EN

Stack Overflow用户
提问于 2018-05-27 07:30:53
回答 1查看 292关注 0票数 0

我想运行一个Fortran程序,它调用一个我想用MPI并行化的子例程。我知道这听起来很复杂,但我希望能够为每个调用指定进程数。我想要使用的是这样的结构:

代码语言:javascript
复制
program my_program

implicit none

!Define variables

nprocs =  !formula for calculating number of processes.

call my_subroutine(output,nprocs,other input vars)

end my_program

我想运行my_subroutine,效果和下面的一样:

代码语言:javascript
复制
mpirun -n nprocs my_subroutine.o

其中my_subroutine是用“other input Varis.”编译的。

这个是可能的吗?

这里有一个简单的例子。我尝试这样编译:$ mpif90 -o my_program WAVE_2D_FP_TUNER_mpi.f90 SIMPLE_ROUTINE.f90。f SIMPLE_ROUTINE.f90我尝试这样运行它:$ mpirun -np (1 or 2) my_program

代码语言:javascript
复制
PROGRAM WAVE_2D_FP_TUNER_mpi
USE MPI
IMPLICIT NONE

REAL(KIND=8) :: T,PARAM(1:3),Z,ZBQLU01
REAL(KIND=8) :: ERRORS,COSTS,CMAX,CMAX_V(1:1000),THRESHOLD,Z_MIN,Z_MAX
REAL(KIND=8) :: U,S,R(1:6),MATRIX(1:15)
INTEGER :: EN,INC,I,J,M,P
INTEGER :: NPROCS,IERR

!0.8,-0.4,0.4,10,4,4,7 -- [0.003,0.534]
!0.8,-0.2,0.2,10,4,4,7 -- [0.190,0.588]
CALL MPI_INIT(IERR)
CALL MPI_COMM_SIZE(MPI_COMM_WORLD,NPROCS,IERR)

THRESHOLD = 0.D0
EN = 81
INC = 1
Z_MIN = -2.D-1; Z_MAX = 2.D-1

T = 1.D0
PARAM(1) = 10.D0; PARAM(2) = 4.D0; PARAM(3) = 4.D0

CMAX = 7.D0 !Max that wave speed could possibly be.

CALL ZBQLINI(0.D0)

OPEN(UNIT = 1, FILE = "TUNER_F.txt")
WRITE(1,*) 'Grid Size: '
WRITE(1,*) T/(EN-1)

DO P = 1,15
    S = 0
    Z = Z_MIN + (1.d0/(15-1))*dble((P-1))*(Z_MAX - Z_MIN)
    WRITE(1,*) 'Z: ',Z
    DO I = 1,1000
        DO J = 1,6
            R(J) = ZBQLU01(0.D0)
        END DO
        !CALL PDE_WAVE_F_mpi(T,PARAM,R,Z,CMAX,EN,INC,NPROCS,U)
        CALL SIMPLE_ROUTINE(T,PARAM,R,Z,CMAX,EN,INC,NPROCS,U)
        IF (U<=threshold) THEN
        S = S + 1.D0
        ELSE 
        S = S + 0.D0
        END IF
    END DO
    MATRIX(P) = (1.D0/1000)*S
END DO

DO I = 1,15
    WRITE(1,*) MATRIX(I)
END DO

PRINT *,MINVAL(MATRIX)
PRINT *,MAXVAL(MATRIX)

CLOSE(1)

CALL MPI_FINALIZE(IERR)

END PROGRAM WAVE_2D_FP_TUNER_mpi

下面是我希望用mpi并行化的子例程。

代码语言:javascript
复制
SUBROUTINE SIMPLE_ROUTINE(T,PARAM,R,Z,CMAX,EN,INC,NPROCS,U)
! Outputs scalar U = T*Z*CMAX*INC*SUM(PARAM)*SUM(R)*SUM(Y)
USE MPI

IMPLICIT NONE

REAL(KIND=8), INTENT(IN) :: T,PARAM(1:3),R(1:6),Z,CMAX
INTEGER, INTENT(IN) :: EN,INC
INTEGER, INTENT(IN) :: NPROCS
REAL(KIND=8), INTENT(OUT) :: U
REAL(KIND=8) :: H,LOCAL_SUM,SUM_OF_X
REAL(KIND=8), DIMENSION(:), ALLOCATABLE :: X
INTEGER :: PX,PX_MAX,NXL,REMX,IX_OFF,P_LEFT,P_RIGHT
INTEGER :: J
INTEGER :: IERR,MYID

! Broadcast nprocs handle to all processes in MPRI_COMM_WORLD
CALL MPI_BCAST(&NPROCS, NPROCS, MPI_INT, 0, MPI_COMM_WORLD,IERR)
! Create subcommunicator SUBCOMM  (Do not know how to define WORLD_GROUP?)
CALL MPI_COMM_SPLIT(MPI_COMM_WORLD,WORLD_GROUP,SUBCOMM,IERR)
! Assign IDs to processes in SUBCOMM
CALL MPI_COMM_RANK(SUBCOMM,MYID,IERR)
! Give NPROCS - 1 to SUBCOMM
CALL MPI_COMM_SIZE(SUBCOMM,NPROCS-1,IERR)

H = 2.D0/(EN-1)

! LABEL THE PROCESSES FROM 1 TO PX_MAX.
PX = MYID + 1
PX_MAX = NPROCS
! SPLIT UP THE GRID IN THE X-DIRECTION.
NXL = EN/PX_MAX !nxl = 10/3 = 3
REMX = EN-NXL*PX_MAX !remx = 10-3*3 = 1
IF (PX .LE. REMX) THEN !for px = 1,nxl = 3
    NXL = NXL+1 !nxl = 4
    IX_OFF = (PX-1)*NXL !ix_off = 0
ELSE
    IX_OFF = REMX*(NXL+1)+(PX-(REMX+1))*NXL !for px = 2 and px = 3, ix_off = 1*(3+1)+(2-(1+1))*3 = 4, ix_off = 1*(3+1)+(3-(1+1))*3 = 7
END IF

! ALLOCATE MEMORY FOR VARIOUS ARRAYS.
ALLOCATE(X(0:NXL+1))
X(:) = (/(-1.D0+DBLE(J-1+IX_OFF)*H, J=1,EN)/)
LOCAL_SUM = SUM(X(1:NXL))
CALL MPI_REDUCE(LOCAL_SUM,SUM_OF_X,1,&
          MPI_DOUBLE_PRECISION,MPI_SUM,&
          0,MPI_COMM_WORLD,IERR)

U = T*Z*CMAX*INC*SUM(PARAM)*SUM(R)*SUM_OF_X

DEALLOCATE(X)

CALL MPI_COMM_FREE(SUBCOMM,IERR)

CALL MPI_BARRIER(MPI_COMM_WORLD,IERR)

END SUBROUTINE SIMPLE_ROUTINE

最终,我希望能够更改子例程中使用的处理器数量,在该子例程中,我希望根据EN的值计算nprocs。

EN

回答 1

Stack Overflow用户

发布于 2018-05-27 09:38:13

一种简单的方法是使用最大进程数启动MPI应用程序。

然后,my_subroutine将首先使用MPI_Bcast(&nprocs, ...)MPI_COMM_SPLIT(MPI_COMM_WORLD, ..., &subcomm)创建一个带有nprocs的子通信器subcomm (您可以使用MPI_UNDEFINED,因此“另一个”通信器将是MPI_COMM_NULL

然后,作为subcomm一部分的MPI任务将执行计算。

最后,MPI_Comm_free(&subcomm)MPI_Barrier(MPI_COMM_WORLD)

从性能的角度来看,创建Note子通信器的代价可能很高,但与计算时间相比,希望不是很重要。如果没有,你宁愿修改你的算法,这样它就可以让nprocs任务来做这项工作,而其他任务则在等待。

另一种方法是使用一个MPI任务启动您的应用程序,MPI_Comm_spawn() nprocs-1任务,合并内部通信器,执行计算,并终止衍生的任务。任务创建的开销更为重要,您的资源管理器可能并不完全支持这一点,因此我不建议使用此选项。

票数 2
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/50547818

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档