MPI集体输出5个特殊形式的非连续3D阵列



在课程工作的实现过程中,我必须编写MPI程序来解决PDE连续体力学。(FORTRAN)

在序列中,程序文件如下所示:

do i=1,XX
    do j=1,YY
        do k=1,ZZ
            write(ifile) R(i,j,k)
            write(ifile) U(i,j,k)
            write(ifile) V(i,j,k)
            write(ifile) W(i,j,k)
            write(ifile) P(i,j,k)
        end do
    end do
end do

在并行程序中,我写了如下相同的内容:/平行化仅沿X/轴进行

call MPI_TYPE_CREATE_SUBARRAY(4, [INT(5), INT(ZZ),INT(YY), INT(XX)], [5,ZZ,YY,PDB(iam).Xelements], [0, 0, 0, PDB(iam).Xoffset], MPI_ORDER_FORTRAN, MPI_FLOAT, slice, ierr)
call MPI_TYPE_COMMIT(slice, ierr)   
call MPI_FILE_OPEN(MPI_COMM_WORLD, cFileName, IOR(MPI_MODE_CREATE, MPI_MODE_WRONLY), MPI_INFO_NULL, ifile, ierr)
do i = 1,PDB(iam).Xelements
    do j = 1,YY
        do k = 1,ZZ
            dataTmp(1,k,j,i) = R(i,j,k)
            dataTmp(2,k,j,i) = U(i,j,k)
            dataTmp(3,k,j,i) = V(i,j,k)
            dataTmp(4,k,j,i) = W(i,j,k)
            dataTmp(5,k,j,i) = P(i,j,k)
        end do
    end do
end do
call MPI_FILE_SET_VIEW(ifile, offset, MPI_FLOAT, slice, 'native', MPI_INFO_NULL, ierr)
call MPI_FILE_WRITE_ALL(ifile, dataTmp, 5*PDB(iam).Xelements*YY*ZZ, MPI_FLOAT, wstatus, ierr)
call MPI_BARRIER(MPI_COMM_WORLD, ierr)

它运行良好。但我不确定是否要使用数组dataTmp。什么解决方案会更快、更正确?在整个程序中使用类似dataTmp的4D阵列怎么样?或者,也许我应该创建5个具有不同置换的特殊mpi_type。

如果有内存空间,使用dataTmp是可以的。MPI_FILE_WRITE_ALL调用将是此代码中最昂贵的部分。

您已经完成了最困难的部分,即设置MPI-IO文件视图。如果要去掉dataTmp,可以创建一个MPI数据类型来描述数组(可能使用MPI_Type_hindexed和MPI_get_address),然后使用MPI_BOTTOM作为内存缓冲区。

如果I/O速度是个问题,并且您可以选择,我建议更改文件格式,或者更改数据在内存中的排列方式,使其更紧密:在串行代码中,以这种转置和交错的方式写入数据会非常慢:

program testoutput
implicit none
integer, parameter :: XX=512, YY=512, ZZ=512
real, dimension(:,:,:), allocatable :: R, U, V, W, P
integer :: timer
integer :: ifile
real :: elapsed
integer :: i,j,k
allocate(R(XX,YY,ZZ), P(XX,YY,ZZ))
allocate(U(XX,YY,ZZ), V(XX,YY,ZZ), W(XX,YY,ZZ))
R = 1.; U = 2.; V = 3.; W = 4.; P = 5.
open(newunit=ifile, file='interleaved.dat', form='unformatted', status='new')
call tick(timer)
do i=1,XX
    do j=1,YY
        do k=1,ZZ
            write(ifile) R(i,j,k)
            write(ifile) U(i,j,k)
            write(ifile) V(i,j,k)
            write(ifile) W(i,j,k)
            write(ifile) P(i,j,k)
        end do
    end do
end do
elapsed=tock(timer)
close(ifile)
print *,'Elapsed time for interleaved: ', elapsed
open(newunit=ifile, file='noninterleaved.dat', form='unformatted',status='new')
call tick(timer)
write(ifile) R
write(ifile) U
write(ifile) V
write(ifile) W
write(ifile) P
elapsed=tock(timer)
close(ifile)
print *,'Elapsed time for noninterleaved: ', elapsed
deallocate(R,U,V,W,P)
contains
subroutine tick(t)
    integer, intent(OUT) :: t
    call system_clock(t)
end subroutine tick
! returns time in seconds from now to time described by t 
real function tock(t)
    integer, intent(in) :: t
    integer :: now, clock_rate
    call system_clock(now,clock_rate)
    tock = real(now - t)/real(clock_rate)
end function tock
end program testoutput

运行提供

$ gfortran -Wall io-serial.f90 -o io-serial
$ ./io-serial 
 Elapsed time for interleaved:    225.755005    
 Elapsed time for noninterleaved:    4.01700020 

正如Rob Latham所说,你对并行版本的转换很好——它在内存中显式地进行交织和转换,速度要快得多,然后将其发送到磁盘。这与IO的速度差不多。

在通过MPI_File_write_all例程输出到磁盘的过程中,您可以通过写入一个或五个单独的数据类型来为您进行换位/交错,从而避免使用dataTmp阵列。这将使您在内存使用率和性能之间获得更多的平衡。您不会显式地定义一个大的三维数组,但MPI-IO代码将通过进行相当多的缓冲来提高在单个元素上循环的性能,这意味着将留出一定的内存来高效地进行写入。好消息是,可以通过在Info变量中设置MPI-IO提示来调整平衡;坏消息是,代码可能不如现在的代码清晰。

最新更新