如何在由 MPI 并行化的 fortran 中调用子例程?
Posted
技术标签:
【中文标题】如何在由 MPI 并行化的 fortran 中调用子例程?【英文标题】:How to call subroutines in fortran parallelized by MPI? 【发布时间】:2012-06-20 17:20:05 【问题描述】:我的问题是我在 Fortran 中使用 mpi 方案时不知道如何调用子程序。 我编写了这个名为 TRY.f90 的小代码,其中有一个名为 CONCENTRATION.f90 的子例程。我应该如何更改 CONTENTRATION.f90 以使代码正常工作?
PROGRAM TRY
USE MPI
integer status(mpi_status_size)
INTEGER I, J, K, II, IERR, MY_ID, NUM_PROCS, PSP
INTEGER , PARAMETER :: GRIDX =64, GRIDY=64
REAL , DIMENSION(gridx,gridy) :: PSI
PSI=0
PRINT*, 'VARIABLE'
CALL MPI_INIT(IERR)
CALL MPI_COMM_RANK(MPI_COMM_WORLD,MY_ID,IERR)
CALL MPI_COMM_SIZE(MPI_COMM_WORLD,NUM_PROCS,IERR)
CALL CONCENTRATION(GRIDX, GRIDY, NUM_PROCS, MY_ID , PSI)
IF (MY_ID .NE. 0) THEN
CALL mpi_send( PSI(1+MY_ID*GRIDX/NUM_PROCS:(MY_ID+1)*GRIDX/NUM_PROCS:1,1:GRIDY:1),&
(GRIDX/NUM_PROCS)*GRIDY,mpi_real, 0,10,mpi_comm_world,ierr)
END IF
IF (MY_ID .EQ. 0) THEN
DO II=1,NUM_PROCS-1
CALL mpi_recv(PSI(1+II*GRIDX/NUM_PROCS:(II+1)*GRIDX/NUM_PROCS:1,1:GRIDY:1),&
(GRIDX/NUM_PROCS)*GRIDY,mpi_real, &
II,10,mpi_comm_world,status,ierr)
END DO
END IF
CALL MPI_FINALIZE(IERR)
END PROGRAM TRY
我正在使用一个名为 CONCENTRATION.f90 的子程序,它是:
SUBROUTINE CONCENTRATION(GRIDX, GRIDY, NUM_PROCS, MY_ID , PSI)
implicit none
INTEGER*8, INTENT(IN) :: GRIDX, GRIDY
INTEGER , INTENT(IN) :: NUM_PROCS, MY_ID
REAL*8 , DIMENSION(GRIDX,GRIDY), INTENT(OUT) :: PSI
INTEGER*8 I, J
DO I=1+MY_ID*GRIDX/NUM_PROCS, (MY_ID+1)*GRIDX/NUM_PROCS
DO J=1,GRIDY
PSI(I,J)=2.0
END DO
END DO
END SUBROUTINE CONCENTRATION
代码当前给了我错误,因为我认为我应该对子例程 CONCENTRATION.f90 进行一些更改。或者我也应该改变调用子程序的方式。
你能告诉我这些变化是什么吗?提前感谢您的帮助
【问题讨论】:
mpirun 注意到节点 Goodin 上 PID 9249 的进程等级 0 在信号 11 上退出(分段错误)。但是,如果我删除 mpi 方案,然后应用 gfortran 编译器,那么一切正常。 我不明白,“MPI方案”是什么意思? 我的意思是如果我使代码顺序(而不是并行)并删除所有 mpi 函数,如 'use mpi'、'mpi_send and recv' ,...(意味着我只使用一个处理器) ,代码运行良好。 【参考方案1】:由于类型不匹配,您的程序出现段错误。在主程序中,您已将 PSI
声明为 REAL
的数组:
REAL , DIMENSION(gridx,gridy) :: PSI
在CONCENTRATION
子例程中使用另一种类型的REAL*8
:
REAL*8 , DIMENSION(GRIDX,GRIDY), INTENT(OUT) :: PSI
默认情况下,REAL
的长度为 4 个字节,而REAL*8
(或 DOUBLE PRECISION
或 REAL(KIND=8)
)的长度为 8 个字节。所以你给CONCENTRATION
一个比它认为的小2倍的数组,从NUM_PROCS/2
开始的所有等级都写到PSI
数组的末尾,从而导致段错误。如果你只运行一个进程,那么即使 rank 0 也会出现段错误。
您还应该阅读 MPI 集合操作。 MPI_GATHER
和 MPI_GATHERV
正是您想要实现的目标,在这里进行多次发送和接收。
【讨论】:
非常感谢。你说的对。现在,代码工作正常。然而,令我惊讶的是,代码打印“变量”的次数与处理器数量一样多!我正在使用四个处理器,所以它打印了 4 次。这让我很惊讶,因为我在 mpi_init() 之前输入了“print*, 'variable'”。mpirun
甚至在您调用 MPI_INIT
之前执行 I/O 重定向。尝试运行 mpirun -np 4 hostname
以查看它是否适用于非 MPI 程序。【参考方案2】:
唯一的变化是将concentration
声明为reentrant
。这可能是 Fortran 90 的默认设置。(我的大部分经验是 F77,reentrant
不是默认设置。)
【讨论】:
您能解释一下吗? 重入与既不递归也不在多线程环境中使用的子例程有什么关系?!以上是关于如何在由 MPI 并行化的 fortran 中调用子例程?的主要内容,如果未能解决你的问题,请参考以下文章
通过 mpi_f08 模块和 gfortran 支持 MPI Fortran