【问题标题】:Fortran error: type mismatch between two unrelated subroutine callsFortran 错误:两个不相关的子例程调用之间的类型不匹配
【发布时间】:2021-01-01 15:11:28
【问题描述】:

在我看来,这个 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 和 Cray MPICH 7.7.16 中的 gfortran。我正在使用 Cray "ftn" 命令编译,没有标志,只有ftn what.f90。还发现问题出在 gcc 10.1.0;代码在 9.3.0 下编译得很好。这样就解决了眼前的问题。但是,如果有人知道在 10.1.0 下做什么(因为 9.3.0 不会永远持续下去),他会很乐意听到的!谢谢。

【问题讨论】:

  • 您使用哪些编译器意见?你的编译命令是什么样子的?您使用哪个编译器版本和 MPI 库版本?你试过其他版本吗?
  • 如果mpi_gather 不是泛型或使用假定类型/合适的多态虚拟参数,那么是的,它不允许使用两种不同的参数类型调用它两次。你可以尝试use mpi_f08 来获得完整的 Fortran 2008 兼容模块吗?
  • @francescalus mpi_gather 可用于几乎任何数据类型(在合理范围内),我已经多次看到它在单个代码中处理多种数据类型;甚至我自己也做过。不过,谢谢。
  • @VladimirF 谢谢。请查看修改。
  • 啊,好的。这是一个可选的附加功能,因此可能不可用。如果存在,它将在同一个地方(我希望,但取决于您的 MPI 实现)。我猜你被旧的编译器/编译器标志困住了,唉。

标签: compilation fortran mpi gnu


【解决方案1】:

没有详细说明是否应该接受示例程序或为什么接受示例程序,因为这取决于 Fortran 语言版本和使用的 MPI 模块的详细信息,GCC 10 brings stricter type checking for Fortran procedure arguments。通过将-fallow-argument-mismatch 选项添加到编译命令行,您应该能够将这些特定错误转换为警告。这对其他项目有效,例如NetCDF

【讨论】:

  • 谢谢,我怀疑是这样的。它甚至可能影响我的代码库。由于需要首先使用 GCC 10 重新编译 MPI 库和许多其他库,因此很难对此进行测试,因此我通常只使用最新的编译器测试非 MPI 版本。但也许我很好,因为我已经在使用 -Wargument-mismatch-Werror
  • 约翰,谢谢你的建议,但是有了那个标志,我得到了同样的错误。但一般信息是非常相关的。谢谢。
  • @VladimirF 那么我们到底要做什么呢?在短期内,我将回到 gcc 9,但这不是一个好的长期解决方案。约翰建议的标志对我不起作用。
  • @bob.sacamento,添加该标志是 GCC 推荐的让编译器接受因更改而被拒绝的代码的方法。我想因为它具有将错误转换为警告的效果,如果您还指定-Werror,它可能无效。如果没有弗拉基米尔要求的细节,我认为我们不能再说什么了。
  • 约翰,试试你的旗帜和弗拉基米尔的旗帜。有和没有-Werror。无论哪种方式,结果都没有变化。谢谢。
【解决方案2】:

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() 包装在有问题的参数周围(这是 void* 在后面的实际 C 调用中的最佳匹配)。无论 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)

然后编译没有错误。

【讨论】:

  • 有趣的想法。我会记住的。谢谢。 FWIW,我绝对属于“修复 gcc”阵营!
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2013-08-02
  • 2013-03-13
  • 1970-01-01
  • 2014-10-05
  • 2014-09-12
  • 1970-01-01
  • 2021-09-26
相关资源
最近更新 更多