Я пытаюсь понять некоторые аспекты ввода-вывода 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
Я думаю о записи в 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, который может увеличить скорость записи на порядки для очень больших файлов / большого количества процессов.
Нет, вы всегда должны вызывать MPI_FILE_SET_VIEW
Спасибо! Итак, в любых, кроме самых тривиальных, ситуациях, можно ли использовать MPI_FILE_WRITE (_ALL) без предварительной настройки представления с помощью MPI_FILE_SET_VIEW?