Странный результат MPI_AllReduce для 16-байтового реального

Компилятор: gfortran-4.8.5

Библиотека MPI: OpenMPI-1.7.2 (предустановленный OpenSuSE 13.2)

Эта программа:

  use mpi
  implicit none

  real*16 :: x
  integer :: ierr, irank, type16

  call MPI_Init(ierr)

  call MPI_Comm_Rank(MPI_Comm_World, irank, ierr)

  if (irank+1==1) x = 2.1
  if (irank+1==8) x = 2.8
  if (irank+1==7) x = 5.2
  if (irank+1==4) x = 6.7
  if (irank+1==6) x = 6.5
  if (irank+1==3) x = 5.7
  if (irank+1==2) x = 4.0
  if (irank+1==5) x = 6.8

  print '(a,i0,a,f3.1)', "rank+1: ",irank+1," x: ",x

  call MPI_AllReduce(MPI_IN_PLACE, x, 1, MPI_REAL16, MPI_MAX, MPI_Comm_World, ierr)

  if (irank==0) print '(i0,a,f3.1)', irank+1," max x: ", x

  call MPI_Finalize(ierr)
end

Я тоже пробовал real(16), real(kind(1.q0)), real(real128) на самом деле эквивалентно real*10 для этого компилятора.

Результат:

> mpif90 reduce16.f90 
> mpirun -n 8 ./a.out 
rank+1: 1 x: 2.1
rank+1: 2 x: 4.0
rank+1: 3 x: 5.7
rank+1: 4 x: 6.7
rank+1: 5 x: 6.8
rank+1: 6 x: 6.5
rank+1: 7 x: 5.2
rank+1: 8 x: 2.8
1 max x: 2.8

Программа находит истинный максимум для real*10 хранение MPI_REAL16, Спецификация MPI (3.1, стр. 628 и 674) не очень понятна, если MPI_REAL16 соответствует real*16 или же real(real128) если они отличаются.

Кроме того, предполагая, MPI_REAL16 на самом деле real(real128) и попытка использовать это в программе приводит к другой проблеме:

Error: There is no specific subroutine for the generic 'mpi_recv' at (1)
Error: There is no specific subroutine for the generic 'mpi_send' at (1)

чего не бывает за real*16, (без учета того, что нужно передавать любой битовый шаблон, поэтому эта проверка излишня)

Как правильно использовать 16-байтовые вещественные числа? Библиотека OpenMPI по ошибке?

1 ответ

Хотя это должно работать правильно в каждой реализации MPI, простой обходной путь - реализовать пользовательское сокращение для этого типа, написанное на Фортране, поэтому нет проблем с его реализацией на C (именно так MPICH и OpenMPI пытаются сделать все, следовательно, есть проблемы, когда C не может воспроизвести поведение Fortran).

Ниже приведена попытка реализовать это. Это пользовательское сокращение в Фортране. Я уверен, что опытные современные программисты на Фортране могут сделать это лучше.

  subroutine sum_real16(iv,iov,n)
    implicit none
    integer, intent(in) ::  n
    real*16, intent(in) :: iv(:)
    real*16, intent(inout) :: iov(:)
    integer :: i
    do i = 1,n
      iov(i) = iov(i) + iv(i)
    enddo
  end subroutine sum_real16
  subroutine reduce_sum_real16(iv, iov, n, dt)
    use, intrinsic ::  iso_c_binding, only : c_ptr
    use mpi_f08
    implicit none
    type(c_ptr), value ::  iv, iov
    integer ::  n
    type(MPI_Datatype) ::  dt
    if ( dt .eq. MPI_REAL16 ) then
        call sum_real16(iv,iov,n)
    endif
  end subroutine reduce_sum_real16
  program test_reduce_sum_real16
    use, intrinsic ::  iso_c_binding
    use mpi_f08
    implicit none
    integer, parameter ::  n = 10
    real*16 :: output(n)
    real*16 :: input(n)
    real*16 :: error
    integer :: me, np
    procedure(MPI_User_function) :: reduce_sum_real16
    type(MPI_Op) :: mysum
    integer :: i
    call MPI_Init()
    call MPI_Comm_rank(MPI_COMM_WORLD,me)
    call MPI_Comm_size(MPI_COMM_WORLD,np)
    output = 0.0
    input  = 1.0*me
    call MPI_Op_create(reduce_sum_real16,.true.,mysum)
    call MPI_Allreduce(input,output,n,MPI_REAL16,mysum,MPI_COMM_WORLD)
    error = 0.0
    do i = 1,n
      error = error + (output(i)-1.0*np)
    enddo
    if (error.gt.0.0) then
        print*,'SAD PANDA = ',error
        call MPI_Abort(MPI_COMM_SELF,1)
    endif
    call MPI_Op_free(mysum)
    call MPI_Finalize()
  end program test_reduce_sum_real16

Эта программа без ошибок возвращается с компилятором Intel 16 Fortran и MPICH 3.2+. По-видимому, я не правильно использую ввод-вывод, поэтому моя уверенность в правильности этой программы не так высока, как если бы я мог записать все результаты в стандартный вывод.

Другие вопросы по тегам