MSMPI 就地 MPI_Allreduce 不适用于 MinGW-w64 gfortran

MSMPI in-place MPI_Allreduce not working with MinGW-w64 gfortran

我正在尝试将就地 MPI_Allreduce 与 MinGW-w64 gfortran(MSYS64 提供的版本 9.2)和 Microsoft MPI(版本 10)结合使用,

call MPI_Allreduce(MPI_IN_PLACE, srcdst, n, MPI_REAL8, MPI_SUM, MPI_COMM_WORLD, ierr)

标准 MPI_Allreduce(具有不同的源和目标)运行良好,当我使用 C 而不是 Fortran 时,就地变体也是如此。

完整的测试程序test_allreduce.f90

program test_allreduce

    use iso_fortran_env, only: real64
    use mpi

    implicit none

    integer, parameter :: mpiint = kind(MPI_COMM_WORLD)

    integer(mpiint) :: n = 10
    integer(mpiint) :: ierr1 = -1, ierr2 = -1, ierr3 = -1, ierr4 = -1

    real(real64) :: src(10) = (/ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 /)
    real(real64) :: dst(10) = 0

    call MPI_Init(ierr1)
    call MPI_Allreduce(src, dst, n, MPI_REAL8, MPI_SUM, MPI_COMM_WORLD, ierr2)
    call MPI_Allreduce(MPI_IN_PLACE, src, n, MPI_REAL8, MPI_SUM, MPI_COMM_WORLD, ierr3)
    call MPI_Finalize(ierr4)

    write (*, '(I4)') MPI_IN_PLACE
    write (*, '(4I4)') ierr1, ierr2, ierr3, ierr4
    write (*, '(10F4.0)') src
    write (*, '(10F4.0)') dst

end program

我是这样编译的:

set "PATH=C:\msys64\mingw64\bin;%PATH%"

x86_64-w64-mingw32-gfortran ^
    -fno-range-check ^
    "C:\Program Files (x86)\Microsoft SDKs\MPI\Include\mpi.f90" ^
    test_allreduce.f90 ^
    -I . ^
    -I "C:\Program Files (x86)\Microsoft SDKs\MPI\Include\x64" ^
    -o test_allreduce.exe ^
    C:\Windows\System32\msmpi.dll

这就是我执行它的方式(目前仅在单个进程中):

test_allreduce.exe

目前,它打印

   0
0   0   0   0
0.  0.  0.  0.  0.  0.  0.  0.  0.  0.
1.  2.  3.  4.  5.  6.  7.  8.  9. 10.

显然,src 缓冲区在第二次(就地)调用 MPI_Allreduce 时被垃圾覆盖。

我在代码中看到 mpi.f90 Intel 特定的 DLLIMPORT 指令,甚至尝试添加类比

!GCC$ ATTRIBUTES DLLIMPORT :: MPI_IN_PLACE

没有任何影响。

事实证明,问题在于在 MSMPI 中,变量 MPI_IN_PLACE 包含在内部 COMMON/MPIPRIV1/ 中,而在 gfortran 中它是一个 known bug编译器无法从 DLL 中正确导入 COMMON 块变量。

然而,损坏的东西是可以修复的,最后所需要的只是将 应用于 gfortran 代码并在 MSYS2 中从头开始编译它(ph... )、 添加指令

!GCC$ ATTRIBUTES DLLIMPORT ::  MPI_BOTTOM, MPI_IN_PLACE

就在上面代码中的 implicit none 之后。 (指令中似乎需要这两个变量,因为 MPI_IN_PLACE 在内部 COMMON 块中排在 MPI_BOTTOM 之后的第二个。)然后就地 MPI_Allreduce 可以完美地工作.