使用 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.010.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

TypeError: "exports" 是只读的 => 导出模块时调用另一个方法的方法

失败时调用的成功回调函数。可能的错误?