0

コースワークの実現中に、私は PDE 連続体の力学を解くために MPI プログラムを書かなければなりません。(フォートラン)

シーケンスプログラムファイルでは、次のように記述します。

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

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 ルーチンを介してディスクに出力する途中で転置/インターリーブを行うために 1 つまたは 5 つの個別のデータ型を書き込むことで、dataTmp 配列を確実に回避できます。これにより、メモリ使用量とパフォーマンスのバランスがもう少し取れます。大きな 3 次元配列を明示的に定義するわけではありませんが、MPI-IO コードはかなりの量のバッファリングを行うことで、個々の要素をループするよりもパフォーマンスを向上させます。効率よく書く。良いニュースは、Info 変数に MPI-IO ヒントを設定することでバランスを調整できることです。悪いニュースは、コードが現在のものよりも明確でなくなる可能性があることです。

于 2014-10-15T15:05:46.033 に答える