MPI_FILE_WRITE()

时间:2018-10-23 17:04:21

标签: io fortran mpi

我试图了解MPI I / O的某些方面。以下测试代码旨在填充四个进程的本地数组,每个本地数组都是较大的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 :(得分:2)

我认为写MPI-IO就像写调用是发送操作一样,您可以使用文件类型作为接收方的数据类型来对文件执行接收。

在第一个命令中,您没有告诉MPI将数据放入文件的位置-它需要知道这一点,因为来自每个进程的数据在接收方(文件)是不连续的,而在发送方是连续的。您将在发送端应用子数组类型,因此您将发送随机数据,因为它将访问lcl_data的范围之外。由于尚未指定文件类型,因此它必须在接收端(文件)使用一些默认值。无论使用哪种默认设置,它都无法正常工作,因为您没有发送正确的数据。

第二个咒语是100%正确的。每个进程将其所有本地数据作为连续块发送。现在,您的子数组将在接收端应用,即来自每个进程的数据将被解包到接收缓冲区(文件)的正确部分中。这里唯一需要担心的是您在“ set_view”中为显示指定了硬“ 0”。接口可能会将其转换为正确的类型(MPI_OFFSET_KIND),但是我使用的系统必须传递变量“ disp”:INTEGER(KIND = MPI_OFFSET_KIND)disp = 0以确保获得64位零(不是默认的32位值)。

为了提高性能,您应该使用MPI_File_Write_all,它可以将非常大的文件/大量的进程数上的写入速度提高几个数量级。