使用 mpi_f08 模块时调用 mpi_gatherv 后数组的 Lbound 发生变化
Posted
技术标签:
【中文标题】使用 mpi_f08 模块时调用 mpi_gatherv 后数组的 Lbound 发生变化【英文标题】:Lbound of an array changes after call to mpi_gatherv when using mpi_f08 module 【发布时间】:2020-12-28 14:52:19 【问题描述】:考虑以下 Fortran 程序
program test_prg
use iso_fortran_env, only : real64
use mpi_f08
implicit none
real(real64), allocatable :: arr_send(:), arr_recv(:)
integer :: ierr
call MPI_Init(ierr)
allocate(arr_send(3), arr_recv(3))
arr_send = 1
print *, lbound(arr_recv)
call MPI_Gatherv(arr_send, size(arr_send), MPI_DOUBLE_PRECISION, arr_recv, [size(arr_send)], [0], MPI_DOUBLE_PRECISION, 0, MPI_COMM_WORLD, ierr)
print *, lbound(arr_recv)
call MPI_Finalize(ierr)
end program
在 1 个处理器上执行此程序(使用 gfortran 9.3.0 和 mpich 3.3.2 编译),打印:
1
0
所以arr_recv
在调用MPI_Gatherv
后更改了它的下限。如果我在对MPI_Gatherv
的调用中使用arr_recv(1)
而不是arr_recv
,那么它不会改变。如果我用mpi
替换mpi_f08
模块,那么使用arr_recv(1)
或arr_recv
不会改变下限。
为什么这个程序的下界会发生变化?
【问题讨论】:
请尝试最新版本的 gfortran。这看起来像一个数组描述符或绑定头问题。 我什至不确定这是一个有效的 MPI 程序,因为接收缓冲区正在被所有级别的缓冲区覆盖。 @GillesGouaillardet 他在一个过程中得到了这个,这不会是一个问题 Fortran 2008 绑定(在 MPICH 中)又名use mpi_f08
for MPI_Gatherv()
使用假定排名(例如 dimension(..)
)
虽然use mpi_f08
vs use mpi
在问题中有所说明,但我更新了我的答案以使编译器错误的范围一目了然。
【参考方案1】:
在这个阶段,我认为这是gfortran
中的一个错误,影响了 MPI Fortran 2018 绑定(例如use mpi_f08
),我在https://gcc.gnu.org/pipermail/fortran/2020-September/055068.html 报告了它。
所有gfortran
版本都受到影响(我试过9.2.0
、10.2.0
和最新的master
分支,8
及更早的版本不支持dimension(..)
。
下面的复制器可以用来证明问题
MODULE FOO
INTERFACE
SUBROUTINE dummyc(x0) BIND(C, name="sync")
type(*), dimension(..) :: x0
END SUBROUTINE
END INTERFACE
contains
SUBROUTINE dummy(x0)
type(*), dimension(..) :: x0
call dummyc(x0)
END SUBROUTINE
END MODULE
PROGRAM main
USE FOO
IMPLICIT NONE
integer :: before(2), after(2)
INTEGER, parameter :: n = 1
DOUBLE PRECISION, ALLOCATABLE :: buf(:)
DOUBLE PRECISION :: buf2(n)
ALLOCATE(buf(n))
before(1) = LBOUND(buf,1)
before(2) = UBOUND(buf,1)
CALL dummy (buf)
after(1) = LBOUND(buf,1)
after(2) = UBOUND(buf,1)
if (before(1) .NE. after(1)) stop 1
if (before(2) .NE. after(2)) stop 2
before(1) = LBOUND(buf2,1)
before(2) = UBOUND(buf2,1)
CALL dummy (buf2)
after(1) = LBOUND(buf2,1)
after(2) = LBOUND(buf2,1)
if (before(1) .NE. after(1)) stop 3
if (before(2) .NE. after(2)) stop 4
END PROGRAM
FWIW,Intel ifort
编译器(我试过 18.0.5
)在复制器上工作得很好。
【讨论】:
不错的答案。当我看的时候,我以为dimension(..)
是什么,所以我阅读了最新的 2019 Fortran 标准(2017 年 12 月 28 日 11:02 草案),我看到这是 Fortran 2019 的一个新功能,称为“假设-rank 实体”(第 8.5.8.7 段)。
Gilles 您能否在回答中提及您使用的英特尔编译器版本和 gfortran 版本(因为它是 Fortran 中的一项新功能,我认为了解编译器的版本也很好)。
dimension(..)
和(改进的)C
互操作是在Fortran 2018
标准中引入的。我用我测试的编译器版本编辑了我的答案。 TL;DR 所有gfortran
版本都受到影响,我想所有ifort
版本都很好。
好的,继续!
已更新。始终感谢最小复制者的作者以上是关于使用 mpi_f08 模块时调用 mpi_gatherv 后数组的 Lbound 发生变化的主要内容,如果未能解决你的问题,请参考以下文章
如何从 C 中使用 MPI_Scatter 和 MPI_Gather?
使用 MPI_Gather 在 Fortran 中发送二维数组
如何使用 MPI_Scatter 和 MPI_Gather 计算多个进程的平均值?
在 C 中使用 MPI_Type_Vector 和 MPI_Gather