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

时间:2014-10-14 16:32:16

标签: arrays mpi multidimensional-array mpi-io

在课程实现过程中,我必须编写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个具有不同displacemet的特殊mpi_types。

2 个答案:

答案 0 :(得分:1)

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

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

答案 1 :(得分:0)

如果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数组。这将在内存使用和性能方面为您提供更多的平衡。你不会明确地定义一个大的3-D数组,但是MPI-IO代码通过做一些缓冲来提高在单个元素上循环的性能,这意味着一定量的内存被放在一边有效地写作。好消息是通过在Info变量中设置MPI-IO提示可以调整余额;坏消息是代码可能不如你现在的那么清晰。