MPI_TYPE_CONTIGUOUS не работает правильно с пользовательским типом, который содержит вещественное (8) - PullRequest
0 голосов
/ 27 февраля 2012

У меня странная проблема с определением mpi_type_contiguous и последующим использованием mpi_gatherv.Тип определяется как:

type glist
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
!uncomment line below for int version:
!  integer :: iref , biref
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
    real(8) :: rvar
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
!uncomment line below for buggy version:
    integer :: ciref
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
end type glist

Код, как он сейчас, не работает.Если бы я прокомментировал integer :: ciref, это бы сработало.То же самое верно, если я прокомментирую real(8) :: rvar вместо этого и раскомментирую два других целых числа integer :: iref, biref.

Это означает, что ошибка зависит как от размера типа данных, так и только в том случае, если real(8) втам.Если у меня есть один real(8) и два int, он снова работает.

Код рассчитан на работу с 3 потоками (!).Я работал с openmpi и gfortran (mpif90).Нет специальных флагов компиляции и выполнения с mpirun -np 3 filename.Если бы кто-то мог запустить его с помощью mpich или скомпилировать его с помощью ifort или чего-то еще, что было бы интересно, чтобы выяснить, откуда возникла проблема.

--- EDIT ---

Platinummonkeyниже предлагается использовать mpi_type_struct, но он все равно не работает.Если я сделаю sizeof(glist) с glist, как указано выше, я получу 16 в качестве ответа вместо 12.

--- / EDIT ---

Заранее спасибо за вашу помощь.

Полный код (не волнуйтесь, некоторые из них могут быть проигнорированы)

module mod_glist
type glist
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
!uncomment line below for int version:
!  integer :: iref , biref
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
    real(8) :: rvar
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
!uncomment line below for buggy version:
    integer :: ciref
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
end type glist

contains

subroutine sof_glist(sof)
    implicit none
    integer, intent(out) :: sof

    type(glist) :: dum
    integer     :: val

    val = 0
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
!uncomment line below for int version:
!  val = kind(dum%iref) + kind(dum%biref)
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
    val = val + kind(dum%rvar)
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
!uncomment line below for buggy version:
    val = val + kind(dum%ciref)
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
    sof = val/kind(0)
    write(*,*) 'Size in bytes, integers: ', sof, val
end subroutine

end module mod_glist

program test_mpi_gatherv

use mpi
use mod_glist

    implicit none

    integer                                :: err, np, tp, nglout, i, j, nglin, sofgl, mpi_type_glist
    type(glist), dimension(:), allocatable :: gl, glcom, glsave
    integer    , dimension(:), allocatable :: glsize, nglinv, nglinp
    integer(kind=mpi_address_kind) :: ii, ij

    call mpi_init(err)
    call mpi_comm_size(mpi_comm_world, np, err)
    call mpi_comm_rank(mpi_comm_world, tp, err)
    tp = tp + 1

    call sof_glist(sofgl)
    call mpi_type_contiguous(sofgl, mpi_integer, mpi_type_glist, err)
    call mpi_type_commit(mpi_type_glist, err)
    call mpi_type_get_extent(mpi_type_glist, ii, ij, err)
    write(*,*) 'extend: ', ii, ij

    allocate(glsize(np), nglinv(np), nglinp(np))

    glsize(1) = 5
    glsize(2) = 4
    glsize(3) = 3
    glsize(4:np) = 0

    allocate(gl(glsize(tp)))
    j = 1
    do i = 1,tp-1
      j = j+glsize(i)
    enddo

    do i = 1,glsize(tp)
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
!uncomment line below for int version:
!    gl(i)%iref = j
!    gl(i)%biref = -j
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
      gl(i)%rvar = real(j,8)
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
!uncomment line below for buggy version:
      gl(i)%ciref = -j*10
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
      j = j+1
    enddo

    do i=1,np ! setting up stuff can be ignored
      if(i.eq.1)then
        if(tp.eq.i)then
          nglinv(1) = 0
          nglinv(2) = 2
          nglinv(3) = 3
          nglinp(1) = 0
          nglinp(2) = nglinv(1) + nglinp(1)
          nglinp(3) = nglinv(2) + nglinp(2)
          nglin = nglinv(1) + nglinv(2) + nglinv(3)
          allocate(glcom(nglin))
          nglout = 0
        else
          if(tp.eq.2)then
            nglout = 2
            allocate(glcom(nglout))
            glcom(1) = gl(1)
            glcom(2) = gl(3)
          elseif(tp.eq.3)then
            nglout = 3
            allocate(glcom(nglout))
            glcom(1) = gl(1)
            glcom(2) = gl(2)
            glcom(3) = gl(3)
          endif
        endif
      elseif(i.eq.2)then
        if(tp.eq.i)then
          nglinv(1) = 3
          nglinv(2) = 0
          nglinv(3) = 2
          nglinp(1) = 0
          nglinp(2) = nglinv(1) + nglinp(1)
          nglinp(3) = nglinv(2) + nglinp(2)
          nglin = nglinv(1) + nglinv(2) + nglinv(3)
          allocate(glcom(nglin))
          nglout = 0
        else
          if(tp.eq.1)then
            nglout = 3
            allocate(glcom(nglout))
            glcom(1) = gl(2)
            glcom(2) = gl(4)
            glcom(3) = gl(5)
          elseif(tp.eq.3)then
            nglout = 2
            allocate(glcom(nglout))
            glcom(1) = gl(2)
            glcom(2) = gl(3)
          endif
        endif
      elseif(i.eq.3)then
        if(tp.eq.i)then
          nglinv(1) = 0
          nglinv(2) = 2
          nglinv(3) = 0
          nglinp(1) = 0
          nglinp(2) = nglinv(1) + nglinp(1)
          nglinp(3) = nglinv(2) + nglinp(2)
          nglin = nglinv(1) + nglinv(2) + nglinv(3)
          allocate(glcom(nglin))
          nglout = 0
        else
          if(tp.eq.1)then
            nglout = 0
            allocate(glcom(nglout))
          elseif(tp.eq.2)then
            nglout = 2
            allocate(glcom(nglout))
            glcom(1) = gl(1)
            glcom(2) = gl(4)
          endif
        endif
      endif ! end of setting up stuff

      if(i.eq.tp) allocate(glsave(nglin))

      ! debug output
      call mpi_barrier(mpi_comm_world, err)
      write(*,*) i, tp, nglout, nglin
      call mpi_barrier(mpi_comm_world, err)
      if(i.eq.tp) write(*,*) i, nglinv, nglinp
      call mpi_barrier(mpi_comm_world, err)
      ! end debug output

      call mpi_gatherv(glcom, nglout, mpi_type_glist, glsave, nglinv, nglinp, mpi_type_glist, i-1, mpi_comm_world, err)

      if(allocated(glcom)) deallocate(glcom)
    enddo

    ! debug output
    call mpi_barrier(mpi_comm_world, err)
    do i = 1,nglin
      write(*,*) tp, i, glsave(i)
    enddo
    ! end debug output

    call mpi_finalize(err)

end program

Ответы [ 2 ]

3 голосов
/ 27 февраля 2012

Ваша основная ошибка заключается в том, что вы не можете вычислить размер производного типа путем суммирования размера его компонентов, потому что это игнорирует заполнение, необходимое для удовлетворения требований выравнивания. В вашем примере real (8) необходимо выровнять по 8-байтовой границе, поэтому, если производный тип содержит целое число по умолчанию (размер 4 байта), то компилятор добавит 4 байта заполнения, чтобы гарантировать, что следующий элемент в массиве производных типов начнется 8-байтовая граница. Как указано в ответе Platinummonkey, правильное решение этой проблемы - определить mpi_type_struct: тип данных структуры MPI с массивом

Кроме того, если предположить, что числовые значения эквивалентны размеру типа, не является переносимым, это просто работает в gfortran.

2 голосов
/ 27 февраля 2012

Смотрите мой старый пост о создании собственной структуры. Гораздо надежнее и подойдет любая комбинация типов.

Тип данных структуры MPI с массивом

...