Ошибка Fortran: несоответствие типов между двумя несвязанными вызовами подпрограммы

#compilation #fortran #mpi #gnu

#Сборник #fortran #mpi #gnu

Вопрос:

Эта программа 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, amp;
             MPI_DOUBLE_PRECISION, all_compute_times, 1, amp;
             MPI_DOUBLE_PRECISION, 0, MPI_COMM_WORLD, ierr)
CALL MPI_GATHER(nreadslb, 1, MPI_INTEGER4, amp;
             all_nreadslb, 1, MPI_INTEGER4, 0, amp;
             MPI_COMM_WORLD, ierr)


call mpi_finalize(ierr)


end program
  

Но не удается скомпилировать на платформе Cray под GNU. Возвращаемая ошибка:

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

Реальная проблема заключается в том, что если я закомментирую первый MPI_GATHER, второй компилируется просто отлично, и если я закомментирую второй MPI_GATHER, первый компилируется просто отлично. В наличии их обоих в коде есть что-то, что не нравится компилятору GNU. Просто для усмешки я вставил между ними инструкцию debug; получил ту же ошибку. Код отлично компилируется под Cray или Intel Fortran.

Есть идеи, в чем может быть проблема?

РЕДАКТИРОВАТЬ: я использую среду Cray PrgEnv-gnu / 6.0.9, которая использует gfortran из gcc 10.1.0 и Cray MPICH 7.7.16. Я выполняю компиляцию с помощью команды Cray «ftn», без флагов, просто ftn what.f90 . Также выяснилось, что проблема связана с gcc 10.1.0; код отлично компилируется под 9.3.0. Так что это решает непосредственную проблему. Но если кто-нибудь знает, что делать под 10.1.0 (поскольку 9.3.0 не будет длиться вечно), хотелось бы это услышать! Спасибо.

Комментарии:

1. Какой компилятор вы используете? Как выглядит ваша команда компиляции? Какую версию компилятора и версию библиотеки MPI вы используете? Вы пробовали какую-либо другую версию?

2. Если mpi_gather не является универсальным или использует предполагаемый тип / подходящие полиморфные фиктивные аргументы, то да, не разрешается вызывать его дважды с двумя разными типами аргументов. Можете ли вы попробовать use mpi_f08 вместо этого получить полный модуль, совместимый с Fortran 2008?

3. @francescalus mpi_gather может использоваться практически для любого типа данных (в пределах разумного), и я много раз видел, как он работает с несколькими типами данных в одном коде; даже делал это сам. Тем не менее, спасибо.

4. Можете ли вы попробовать с use mpi_f08 вместо use mpi и обновить нас? Частью мотивации предоставления этого модуля (интерфейса F2008) являются известные проблемы, из-за которых действительно очень сложно предоставить интерфейс MPI, совместимый с F95 (например, эта ошибка, с которой вы столкнулись).

5. Ах, хорошо. Это необязательное дополнение, поэтому может быть недоступно. Если присутствует, это было бы в том же месте (я бы ожидал, но зависит от вашей реализации MPI). Я предполагаю, что вы застряли со старыми флагами компилятора / compiler, увы.

Ответ №1:

Не вдаваясь в подробности о том, следует ли принимать программу-пример или почему, поскольку это зависит от языковой версии Fortran и от деталей используемого модуля MPI, GCC 10 обеспечивает более строгую проверку типов для аргументов процедуры Fortran. Вы должны быть в состоянии преобразовать эти конкретные ошибки в предупреждения, добавив -fallow-argument-mismatch параметр в командную строку компиляции. Это было эффективно для других проектов, таких как NetCDF.

Комментарии:

1. Спасибо, я подозревал что-то подобное. Это может даже повлиять на мою кодовую базу. Это сложнее проверить, поскольку сначала нужно перекомпилировать библиотеку MPI и многие другие библиотеки с GCC 10, поэтому я чаще всего тестирую только версию, отличную от MPI, с самыми последними компиляторами. Но, возможно, я в порядке, потому что я уже использовал -Wargument-mismatch и -Werror .

2. @VladimirF Так что, черт возьми, нам делать? В краткосрочной перспективе я просто вернусь к gcc 9, но это не является хорошим долгосрочным решением. Предложенный Джоном флаг у меня не сработал.

3. @bob.sacamento, добавление этого флага является рекомендуемым подходом GCC для того, чтобы заставить компилятор принять код, который отклонен из-за изменения. Я полагаю, что, поскольку это приводит к преобразованию ошибок в предупреждения, это может оказаться неэффективным, если вы также укажете -Werror . Я не думаю, что мы можем сказать больше без деталей, которые запросил Владимир.

4. Джон, пробую как ваш флаг, так и Владимира. С и без -Werror . Результат в любом случае не изменился. Спасибо.

Ответ №2:

UPD: Похоже, что рецепт при работе в GCC10 в Ubuntu 20.04 вызывает повреждение памяти, по крайней мере, с 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 в качестве ЦЕЛЕВЫХ (также подойдут указатели)

 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, amp;
             MPI_DOUBLE_PRECISION, C_LOC(all_compute_times), 1, amp;
             MPI_DOUBLE_PRECISION, 0, MPI_COMM_WORLD, ierr)
CALL MPI_GATHER(C_LOC(nreadslb), 1, MPI_INTEGER4, amp;
             C_LOC(all_nreadslb), 1, MPI_INTEGER4, 0, amp;
             MPI_COMM_WORLD, ierr)
  

Затем компиляция проходит без ошибок.