MPI_FILE_WRITE() 的用法
Usage of MPI_FILE_WRITE()
我正在尝试了解 MPI 的某些方面 I/O。下面的测试代码旨在填充四个进程的本地数组,每个本地数组都是一个更大的 10x10 数组的一部分,然后输出到一个文件,以便整个数组按正确的顺序写入。您可能会注意到这四个进程拥有数组的矩形部分,并且它们一起精确地覆盖了大数组的域,但它们的边界彼此并不 "squared" 。这是故意的。
您会注意到,在写作实际发生的地方,我有两个选择。第一个生成一个文件,其中包含一些命中或未命中的正确值,但主要是乱码。第二种选择非常有效。我期待第一个选项也能工作。我对 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%正确。每个进程将其所有本地数据作为连续块发送。现在您的子数组应用于接收端,即将来自每个进程的数据解压缩到接收缓冲区(文件)的正确部分。这里唯一有点担心的是您为 "set_view" 中的 disp 指定了硬“0”。这可能会被接口转换为正确的类型 (MPI_OFFSET_KIND),但我使用过必须传递变量 "disp" 的系统:INTEGER(KIND=MPI_OFFSET_KIND) disp=0确保获得 64 位零(不是默认的 32 位值)。
为了提高性能,您应该使用 MPI_File_Write_all,它可以将非常大的文件/大进程数的写入速度提高几个数量级。
我正在尝试了解 MPI 的某些方面 I/O。下面的测试代码旨在填充四个进程的本地数组,每个本地数组都是一个更大的 10x10 数组的一部分,然后输出到一个文件,以便整个数组按正确的顺序写入。您可能会注意到这四个进程拥有数组的矩形部分,并且它们一起精确地覆盖了大数组的域,但它们的边界彼此并不 "squared" 。这是故意的。
您会注意到,在写作实际发生的地方,我有两个选择。第一个生成一个文件,其中包含一些命中或未命中的正确值,但主要是乱码。第二种选择非常有效。我期待第一个选项也能工作。我对 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%正确。每个进程将其所有本地数据作为连续块发送。现在您的子数组应用于接收端,即将来自每个进程的数据解压缩到接收缓冲区(文件)的正确部分。这里唯一有点担心的是您为 "set_view" 中的 disp 指定了硬“0”。这可能会被接口转换为正确的类型 (MPI_OFFSET_KIND),但我使用过必须传递变量 "disp" 的系统:INTEGER(KIND=MPI_OFFSET_KIND) disp=0确保获得 64 位零(不是默认的 32 位值)。
为了提高性能,您应该使用 MPI_File_Write_all,它可以将非常大的文件/大进程数的写入速度提高几个数量级。