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
可以完美地工作.
我正在尝试将就地 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
块变量。
然而,损坏的东西是可以修复的,最后所需要的只是将
!GCC$ ATTRIBUTES DLLIMPORT :: MPI_BOTTOM, MPI_IN_PLACE
就在上面代码中的 implicit none
之后。 (指令中似乎需要这两个变量,因为 MPI_IN_PLACE
在内部 COMMON
块中排在 MPI_BOTTOM
之后的第二个。)然后就地 MPI_Allreduce
可以完美地工作.