Использование MPI_FILE_WRITE () - PullRequest
0 голосов
/ 23 октября 2018

Я пытаюсь понять некоторые аспекты ввода / вывода MPI.Следующий тестовый код предназначен для заполнения локальных массивов четырех процессов, каждый из которых является частью большого массива 10x10, а затем выводится в файл, так что весь массив записывается в правильном порядке.Вы можете заметить, что четыре процесса обладают прямоугольными частями массива, и вместе они точно покрывают область большого массива, но их границы не «возводятся в квадрат» друг с другом.Это сделано намеренно.

Вы заметите, что там, где на самом деле происходит запись, у меня есть два варианта.Первый создает файл, заполненный некоторыми правильными значениями попадания или пропуска, но в основном это тарабарщина.Второй вариант работает отлично.Я ожидал, что первый вариант сработает.Что я не понимаю о mpi_file_write()?

module mpi_stuff

use mpi

integer :: err_mpi
integer :: stat_mpi(MPI_STATUS_SIZE)
integer :: numprocs, myrank
integer :: output_type
integer :: outfile
integer :: starts(2)

end module mpi_stuff


module mydata

! ll: lower left x and y of local array
! uu: upper right x and y of local array
! arrsize : dimensions of local array
integer :: ll(2), uu(2), arrsize(2)
integer, allocatable :: lcl_data(:,:)

end module mydata

program output_test

    use mpi_stuff
use mydata

! init MPI.  get rank and size of comm
call mpi_init(err_mpi)
call mpi_comm_size(MPI_COMM_WORLD, numprocs, err_mpi)
call mpi_comm_rank(MPI_COMM_WORLD, myrank, err_mpi)

! initialize data
call data_init()

! define output types
print *,'proc ',myrank,' about to create'
call flush(6)
call mpi_type_create_subarray(2, (/10,10/), arrsize, starts, MPI_ORDER_FORTRAN,   &
                              MPI_INTEGER, output_type, err_mpi)
call mpi_type_commit(output_type, err_mpi)

! open file
call mpi_file_open(MPI_COMM_WORLD, 'output.mpi',  &
                   MPI_MODE_CREATE+MPI_MODE_RDWR, &
                   MPI_INFO_NULL, outfile, err_mpi)

! write to file
! option 1 -- FAILS MISERABLY!
!call mpi_file_write(outfile, lcl_data, 1, output_type, stat_mpi, err_mpi)
! option 2 -- WORKS PERFECTLY!
call mpi_file_set_view(outfile, 0, MPI_INTEGER, output_type, "native", MPI_INFO_NULL, err_mpi)
call mpi_file_write(outfile, lcl_data, arrsize(1)*arrsize(2), MPI_INTEGER, stat_mpi, err_mpi)

! clean up
call mpi_file_close(outfile, err_mpi)
call mpi_type_free(output_type, err_mpi)
call mpi_finalize(err_mpi)

end program output_test




subroutine data_init()

use mpi_stuff
use mydata

integer :: glbj, glbi, gval

select case(myrank)
  case(0)
    ll = (/1,1/)
    uu = (/4,3/)
  case(1)
    ll = (/1,4/)
    uu = (/4,10/)
  case(2)
    ll = (/5,1/)
    uu = (/10,7/)
  case(3)
    ll = (/5,8/)
    uu = (/10,10/)
end select

arrsize(1) = uu(1)-ll(1)+1
arrsize(2) = uu(2)-ll(2)+1
starts = ll - 1

print *,myrank,": ", ll, uu, starts, arrsize

allocate(lcl_data(arrsize(1), arrsize(2)))

do j = 1, arrsize(2)
  glbj = j + ll(2) - 1
  do i = 1, arrsize(1)
    glbi = i + ll(1) - 1 
    gval = (glbi-1) + 10*(glbj-1)
    lcl_data(i,j) = gval
  enddo
enddo

print *,myrank,': ',lcl_data

end subroutine data_init

1 Ответ

0 голосов
/ 24 октября 2018

Я думаю о записи в MPI-IO, как будто вызов записи является операцией отправки, и затем вы выполняете прием в файл, используя тип файла в качестве типа данных на стороне приема.

В первомЗаклинание: вы не указываете MPI, куда помещать данные в файл - это нужно знать, поскольку данные каждого процесса несмежны на принимающей стороне (в файле), но смежны на отправляющей стороне.Вы применяете тип подмассива на стороне отправки, поэтому отправляете случайные данные, так как они будут доступны за пределами lcl_data.Поскольку вы не указали тип файла, он должен использовать некоторые значения по умолчанию на стороне приема (файл).Независимо от того, что это значение по умолчанию, оно не может работать, поскольку вы не отправляете правильные данные.

Второе заклинание на 100% верно.Каждый процесс отправляет все свои локальные данные в виде непрерывного блока.Теперь ваш подмассив применяется на приемной стороне, т.е. данные из каждого процесса распаковываются в правильный раздел приемного буфера (файла).Единственное небольшое беспокойство здесь - вы указываете жесткий «0» для disp в «set_view».Это может быть преобразовано в правильный тип (MPI_OFFSET_KIND) интерфейсом, но я использовал системы, в которых вам нужно передать переменную "disp": INTEGER (KIND = MPI_OFFSET_KIND) disp = 0, чтобы убедиться, что вы получите 64-битный ноль(не 32-разрядное значение по умолчанию).

Для повышения производительности следует использовать MPI_File_Write_all, который может увеличить скорость записи на порядки величины для очень больших файлов / большого числа процессов.

...