Fortran error: type mismatch between two unrelated subroutine calls
Asked Answered
A

2

12

This Fortran MPI program is, to my mind, completely straightforward:

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

But it fails to compile on a Cray platform under GNU. The error returned is:

   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)).

The real kicker is that if I comment out the first MPI_GATHER, the second one compiles just fine, and if I comment out the second MPI_GATHER, the first one compiles just fine. There is something about having the both of them in the code that the GNU compiler does not like. Just for grins, I put a debug statement in between them; got the same error. The code compiles just fine under Cray or Intel Fortran.

Any ideas what the problem could be?

EDIT: I am using the Cray environment PrgEnv-gnu/6.0.9 which uses gfortran from gcc 10.1.0 and Cray MPICH 7.7.16. I am compililng with the Cray "ftn" command, no flags, just ftn what.f90. Also found out that the problem is with gcc 10.1.0; code compiles just fine under 9.3.0. So that solves the immediate problem. But if anyone knows what to do under 10.1.0 (since 9.3.0 won't last forever) would love to hear it! Thanks.

Asbestos answered 14/9, 2020 at 21:28 Comment(6)
Which compiler opins do you use? How does your compile command look like? Which compiler version and MPI library version do you use? Did you try any other version?Stockjobber
If mpi_gather isn't a generic or using assumed type/suitable polymorphic dummy arguments, then yes it isn't allowed to call it twice with two different argument types. Can you try use mpi_f08 instead to get the full Fortran 2008 compliant module?Decigram
@Decigram mpi_gather can be used for just about any data type (within reason) and I have seen it operate with several data types in a single code many times; have even done it myself. Thanks, though.Asbestos
Can you try with use mpi_f08 instead of use mpi and update us? Part of the motivation of providing this module (the F2008 interface) is the known problems that it's really very hard to provide a F95 compliant MPI interface (such as this error you've come up against).Decigram
@Decigram The compiler couldn't find mpi_f08. Is there some standard location where it is generally placed?Asbestos
Ah, ok. It's an optional extra, so may not be available. If present, it'd be in the same place (I'd expect, but depends on your MPI implementation). I guess you're stuck with older compiler/compiler flags, alas.Decigram
S
14

Without going into detail on whether or why the example program should be accepted, as this depends on Fortran language version and on details of the MPI module in use, 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.

Subtropics answered 15/9, 2020 at 13:48 Comment(4)
Thank you, I suspected something like this. It may even affect my codebase. It is harder to test this as one needs to recompile the MPI library and many other libraries with GCC 10 first so I most often only test a non-MPI version with the most recent compilers. But perhaps I am fine because I was already using -Wargument-mismatch and -Werror.Stockjobber
@VladimirF So what the heck do we do? In the short term, I'll just go back to gcc 9, but that is not a good long term solution. John's suggested flag did not work for me.Asbestos
@bob.sacamento, adding that flag is GCC's recommended approach to getting the compiler to accept code that is rejected because of the change. I suppose that because it has the effect of converting errors into warnings, it might be ineffective if you also specify -Werror. I don't think we can say any more without the details that Vladimir requested.Subtropics
John, trying both your flag and Vladimir's. With and without -Werror. No change in outcome either way. Thanks.Asbestos
P
2

UPD: Looks like the recipe, while working in GCC10 in Ubuntu 20.04, causes a memory corruption, at least with GNU Fortran (GCC) 8.3.0 20190222 (Cray Inc.) and cray-mpich/7.7.9. Use with extreme care!

Compiling of your code against openMPI goes with no issues. The issue is in MPICH bindings, and there are still debates whether the it is gcc or MPICH to be fixed:).

I do not like the idea of suppressing any warnings, as they might be of help sometimes. Another way would be to wrap C_LOC() around the arguments in question (that is the best match to void* in the actual C calls behind). This wrapper should do no harm regardless the MPI library or a compiler version.

You would need to add

use, intrinsic :: ISO_C_BINDING, only: c_loc

in the preamble of the program, declare the first arguments of the calls for MPI_GATHER as TARGET (pointers would do as well)

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

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

and wrap the arguments with 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)

Then compilation goes without errors.

Phyfe answered 15/9, 2021 at 11:17 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.