2017-03-22 6 views
0
PROGRAM ShareNeighbors 
IMPLICIT REAL (a-h,o-z) 
INCLUDE "mpif.h" 
PARAMETER (m = 500, n = 500) 
DIMENSION a(m,n), b(m,n) 
DIMENSION h(m,n) 
INTEGER istatus(MPI_STATUS_SIZE) 
INTEGER iprocs, jprocs 
PARAMETER (ROOT = 0) 
integer dims(2),coords(2) 
logical periods(2) 
data periods/2*.false./ 
integer status(MPI_STATUS_SIZE) 
integer comm2d,req,source 

CALL MPI_INIT(ierr) 
CALL MPI_COMM_SIZE(MPI_COMM_WORLD, nprocs, ierr) 
CALL MPI_COMM_RANK(MPI_COMM_WORLD, myrank, ierr) 
! Get a new communicator for a decomposition of the domain. 
! Let MPI find a "good" decomposition 
dims(1) = 0 
dims(2) = 0 
CALL MPI_DIMS_CREATE(nprocs,2,dims,ierr) 
if (myrank.EQ.Root) then 
    print *,nprocs,'processors have been arranged into',dims(1),'X',dims(2),'grid' 
endif 
CALL MPI_CART_CREATE(MPI_COMM_WORLD,2,dims,periods,.true., & 
        comm2d,ierr) 
! Get my position in this communicator 
CALL MPI_COMM_RANK(comm2d,myrank,ierr) 
! Get the decomposition 
CALL fnd2ddecomp(comm2d,m,n,ista,iend,jsta,jend) 
! print *,ista,jsta,iend,jend 
ilen = iend - ista + 1 
jlen = jend - jsta + 1 

CALL MPI_Cart_get(comm2d,2,dims,periods,coords,ierr) 
iprocs = dims(1) 
jprocs = dims(2) 
myranki = coords(1) 
myrankj = coords(2) 

DO j = jsta, jend 
    DO i = ista, iend 
    a(i,j) = myrank+1 
    ENDDO 
ENDDO 
! Send data from each processor to Root 
call MPI_ISEND(ista,1,MPI_INTEGER,Root,1, & 
        MPI_COMM_WORLD,req,ierr) 
call MPI_ISEND(iend,1,MPI_INTEGER,Root,1, & 
        MPI_COMM_WORLD,req,ierr) 
call MPI_ISEND(jsta,1,MPI_INTEGER,Root,1, & 
        MPI_COMM_WORLD,req,ierr) 
call MPI_ISEND(jend,1,MPI_INTEGER,Root,1, & 
        MPI_COMM_WORLD,req,ierr) 
call MPI_ISEND(a(ista:iend,jsta:jend),(ilen)*(jlen),MPI_REAL, & 
        Root,1,MPI_COMM_WORLD,req,ierr) 
! Recieved the results from othe precessors 
if (myrank.EQ.Root) then 
    do source = 0,nprocs-1 
     call MPI_RECV(ista,1,MPI_INTEGER,source, & 
        1,MPI_COMM_WORLD,status,ierr) 
     call MPI_RECV(iend,1,MPI_INTEGER,source, & 
        1,MPI_COMM_WORLD,status,ierr) 
     call MPI_RECV(jsta,1,MPI_INTEGER,source, & 
        1,MPI_COMM_WORLD,status,ierr) 
     call MPI_RECV(jend,1,MPI_INTEGER,source, & 
        1,MPI_COMM_WORLD,status,ierr)  
     ilen = iend - ista + 1 
     jlen = jend - jsta + 1       
     call MPI_RECV(a(ista:iend,jsta:jend),(ilen)*(jlen),MPI_REAL, & 
        source,1,MPI_COMM_WORLD,status,ierr) 
! print the results 
     call ZMINMAX(m,n,ista,iend,jsta,jend,a(:,:),amin,amax) 
     print *, 'myid=',source,amin,amax 
     call MPI_Wait(req, status, ierr) 
    enddo  
endif 

CALL MPI_FINALIZE(ierr) 
END 

subroutine fnd2ddecomp(comm2d,m,n,ista,iend,jsta,jend) 
integer comm2d 
integer m,n,ista,jsta,iend,jend 
integer dims(2),coords(2),ierr 
logical periods(2) 
! Get (i,j) position of a processor from Cartesian topology. 
CALL MPI_Cart_get(comm2d,2,dims,periods,coords,ierr) 
! Decomposition in first (ie. X) direction 
CALL MPE_DECOMP1D(m,dims(1),coords(1),ista,iend) 
! Decomposition in second (ie. Y) direction 
CALL MPE_DECOMP1D(n,dims(2),coords(2),jsta,jend) 

return 
end 
SUBROUTINE MPE_DECOMP1D(n,numprocs,myid,s,e) 
integer n,numprocs,myid,s,e,nlocal,deficit 
nlocal = n/numprocs 
s  = myid * nlocal + 1 
deficit = mod(n,numprocs) 
s  = s + min(myid,deficit) 
! Give one more slice to processors 
if (myid .lt. deficit) then 
    nlocal = nlocal + 1 
endif 
e = s + nlocal - 1 
if (e .gt. n .or. myid .eq. numprocs-1) e = n 

return 
end 
SUBROUTINE ZMINMAX(IX,JX,SX,EX,SY,EY,ZX,ZXMIN,ZXMAX) 

INTEGER :: IX,JX,SX,EX,SY,EY 
REAL :: ZX(IX,JX) 
REAL :: ZXMIN,ZXMAX 

ZXMIN=1000. 
ZXMAX=-1000. 
DO II=SX,EX 
    DO JJ=SY,EY 
     IF(ZX(II,JJ).LT.ZXMIN)ZXMIN=ZX(II,JJ) 
     IF(ZX(II,JJ).GT.ZXMAX)ZXMAX=ZX(II,JJ) 
    ENDDO 
ENDDO 

RETURN 
END 

上記のコードを4つのプロセッサで実行しているとき、ルートはガベージ値を受け取ります。 15プロセッサの場合、データ転送は適切です。どのように私はこれに取り組むことができますか? 私はそれが関連するバッファーだと思いますが、それは私には分かりません。私はバッファを賢明にどのように取り組まなければならないのですか?FortranのMPIはゴミ値を返します

+0

値を表示し、それらが間違っている理由と表示したい値を説明します。 –

+0

サブルーチンを内部にしたり(includeの後ろに置く)、モジュールに入れ、 'INCLUDE" mpif.h "の代わりに' use mpi'を使うことをお勧めします。コンパイラがあなたのためにできる多くのチェックを可能にします。 –

答えて

2

1.複数を行っている問題

は同じリクエスト変数req

call MPI_ISEND(ista,1,MPI_INTEGER,Root,1, & 
        MPI_COMM_WORLD,req,ierr) 
call MPI_ISEND(iend,1,MPI_INTEGER,Root,1, & 
        MPI_COMM_WORLD,req,ierr) 
call MPI_ISEND(jsta,1,MPI_INTEGER,Root,1, & 
        MPI_COMM_WORLD,req,ierr) 
call MPI_ISEND(jend,1,MPI_INTEGER,Root,1, & 
        MPI_COMM_WORLD,req,ierr) 
call MPI_ISEND(a(ista:iend,jsta:jend),(ilen)*(jlen),MPI_REAL, & 
        Root,1,MPI_COMM_WORLD,req,ierr) 

、それらのすべてを送信します。それはうまくいかない。

2.あなたは、ノンブロッキングMPIでサブアレーa(ista:iend,jsta:jend)を使用している問題

。それは許可されていません。配列をいくつかの一時配列バッファにコピーするか、MPI由来のサブ配列データ型を使用する必要があります(この段階ではあなたにとっては難しい)。

理由は、コンパイラがISendの呼び出しのためだけに一時コピーを作成するためです。 ISendはアドレスを記憶しますが、何も送信しません。一時的に削除され、アドレスは無効になります。そして、MPI_Waitはそのアドレスの使用を試み、失敗します。

あなたMPI_Wait

3.問題が間違った場所にあります。常に送信されるようにif条件から送信した後でなければなりません(常に送信している場合)。

すべてのリクエストを個別に収集し、すべてのリクエストを待機する必要があります。配列に入れて、すぐにMPI_Waitallを使ってそれらのすべてを待つことがベストです。

通常、バッファが大きい場合、ISendは実際には何も送信しません。この交換は、Waitの操作中に頻繁に行われます。少なくとも大きな配列の場合は。


勧告:

簡単な問題の例を取り、2つのプロセス間MPI_IRecvとMPI_ISendとちょうど2つの小さな配列を交換してみてください。できるだけ簡単なテスト問題として。それから学び、簡単な手順を実行します。犯行にはならないが、現在のノンブロッキングMPIの理解は、本格的なプログラムを書くには弱すぎる。 MPIは難しく、非ブロッキングMPIはさらに困難です。


* MPI-2で使用可能なインターフェイスを使用する場合は許可されません。可能であれば、use mpi_f08を使用して新しいインターフェイスを使用できます。しかし、最初に基礎を学ぶ。

+0

私はあなたが言ったのと同じことに従っています。送信後にmpi_Waitを追加すると、デッドロックが発生します。mpi_recvの実行後、mpi_waitとしてデッドロックが発生します。しかし、問題は同じで16以下のプロセッサのごみ値です。 –

+1

受信側と送信側を正しく注文する必要があるからです。私はあなたにすべてを教えることはできません。最も良いことは、すべての受信を 'IRecv 'として行い、送信者と受信者の両方からのすべての要求を収集し、次に単一の' MPI_Waitall'を作成することです。 –

+0

しかし、デッドロックは**あなたが何をどのように注文すべきかで何をしているのかを考えるのに時間を費やさなければ**非常にそうです**。ペンと紙を持って、少数のプロシーシーのためのコミュニケーションを描きなさい。あなたは本当にそれについて考える必要があります。 MPIは難しい。あなたの前の質問の1つの下で、私は小さな単純な例で 'MPI_ISend'と' MPI_Irecv'を学ぶべきであることをすでに教えていました。それでもなお真です。 –

関連する問題