0

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

在顺控程序文件中写如下:

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_types。

4

2 回答 2

1

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

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

于 2014-10-15T02:01:09.507 回答
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 提示来调整平衡;坏消息是代码可能不如你现在拥有的那么清晰。

于 2014-10-15T15:05:46.033 回答