Fortran error: type mismatch between two unrelated subroutine calls

Fortran error: type mismatch between two unrelated subroutine calls

在我看来,这个 Fortran MPI 程序非常简单:

program what

use mpi

integer(4), parameter :: ksp = 4
integer(4), parameter :: kdp = 8

integer(ksp) :: nreadslb
integer(ksp), ALLOCATABLE :: all_nreadslb(:)

real(kdp) :: compute_time
real(kdp), ALLOCATABLE :: all_compute_times(:)

integer(ksp) :: myrank

integer :: ierr

call mpi_init(ierr)


allocate(all_nreadslb(10), all_compute_times(10))

CALL MPI_GATHER(compute_time, 1, &
             MPI_DOUBLE_PRECISION, all_compute_times, 1, &
             MPI_DOUBLE_PRECISION, 0, MPI_COMM_WORLD, ierr)
CALL MPI_GATHER(nreadslb, 1, MPI_INTEGER4, &
             all_nreadslb, 1, MPI_INTEGER4, 0, &
             MPI_COMM_WORLD, ierr)


call mpi_finalize(ierr)


end program

但是在GNU下的Cray平台上编译失败。返回的错误是:

   23 |       CALL MPI_GATHER(compute_time, 1, &
      |                      2
......
   26 |       CALL MPI_GATHER(nreadslb, 1, MPI_INTEGER4, &
      |                      1
Error: Type mismatch between actual argument at (1) and actual argument at (2) (INTEGER(4)/REAL(8)).

真正的问题是,如果我注释掉第一个 MPI_GATHER,第二个编译得很好,如果我注释掉第二个 MPI_GATHER,第一个编译得很好。 GNU 编译器不喜欢将它们都放在代码中。为了好玩,我在它们之间放了一条调试语句;得到了同样的错误。代码在 Cray 或 Intel Fortran 下编译得很好。

知道问题出在哪里吗?

编辑:我正在使用 Cray 环境 PrgEnv-gnu/6.0.9,它使用来自 gcc 10.1.0 的 gfortran 和 Cray MPICH 7.7.16。我正在使用 Cray“ftn”命令进行编译,没有标志,只有 ftn what.f90。还发现问题出在gcc 10.1.0;代码在 9.3.0 下编译得很好。这样就解决了眼前的问题。但是,如果有人知道在 10.1.0 下该做什么(因为 9.3.0 不会永远持续下去),我很想听听!谢谢

没有详细说明示例程序是否或为什么应该被接受,因为这取决于 Fortran 语言版本和正在使用的 MPI 模块的详细信息,GCC 10 brings stricter type checking for Fortran procedure arguments. You should be able to convert these particular errors into warnings by adding the -fallow-argument-mismatch option to your compilation command line. This has been effective for other projects, such as NetCDF

UPD: 看起来像食谱,在 Ubuntu 20.04 中的 GCC10 中工作时,会导致内存损坏,至少对于 GNU Fortran (GCC) 8.3.0 20190222(Cray Inc.)和 cray-mpich/7.7.9。 谨慎使用!

针对 openMPI 编译您的代码没有任何问题。问题出在 MPICH 绑定中,并且仍然存在争论是 gcc 还是 MPICH 要修复:)。

我不喜欢抑制任何警告的想法,因为它们有时可能会有帮助。另一种方法是将 C_LOC() 包裹在有问题的参数周围(这是在后面的实际 C 调用中与 void* 的最佳匹配)。无论 MPI 库或编译器版本如何,此包装器都不会造成伤害。

您需要添加

use, intrinsic :: ISO_C_BINDING, only: c_loc

在程序的序言中,将 MPI_GATHER 调用的第一个参数声明为 TARGET(指针也可以)

integer(ksp), TARGET :: nreadslb
integer(ksp), ALLOCATABLE, TARGET :: all_nreadslb(:)

real(kdp), TARGET :: compute_time
real(kdp), ALLOCATABLE, TARGET :: all_compute_times(:)

并用 C_LOC

包装参数
CALL MPI_GATHER(C_LOC(compute_time), 1, &
             MPI_DOUBLE_PRECISION, C_LOC(all_compute_times), 1, &
             MPI_DOUBLE_PRECISION, 0, MPI_COMM_WORLD, ierr)
CALL MPI_GATHER(C_LOC(nreadslb), 1, MPI_INTEGER4, &
             C_LOC(all_nreadslb), 1, MPI_INTEGER4, 0, &
             MPI_COMM_WORLD, ierr)

然后编译没有错误。