2016-08-30 1 views
1

私は、各プロセッサがいくつかの他のプロセッサに複数のメッセージを送り、MPI_Isendを使用していくつかの未知数のメッセージを受信するアプリケーションに取り組んでいます。受信者側から、MPI_Isendを使用して送信されたすべてのメッセージが受信されたことを確認するにはどうすればよいですか?

私の小さなサンプルプログラム(コード)私は4つのプロセッサーが残りの3つのプロセッサーのそれぞれに4つのメッセージを送信しているので、各プロセッサーは12のメッセージを受信することになっています。

私が見ている問題は、私のマシンが幸せであるとき、私のプログラムは、以下の

Rank 2 receives 12 msgs; Global count = 48 
Rank 1 receives 12 msgs; Global count = 48 
Rank 3 receives 12 msgs; Global count = 48 
Rank 0 receives 12 msgs; Global count = 48 

を出力しかし、それはになっていてたまに、一部のプロセッサだけで十分なメッセージを受信して​​いないということです。

Rank 1 receives 9 msgs; Global count = 37 
Rank 3 receives 12 msgs; Global count = 37 
Rank 2 receives 4 msgs; Global count = 37 
Rank 0 receives 12 msgs; Global count = 37 

私はこの問題は、私は、着信メッセージをチェックして、すぐにチェックがfalseを返すように、ループを終了するにはMPI_Iprobeを使用するwhile-loopとなる可能性が知っています。 しかし、私はこれをどうやって違う方法で行うことができるのか分かりません。言い換えれば、すべてのプロセッサがMPI_Allreduceステートメントに到達するまでに受け取るべきすべてのメッセージを受信するようにするにはどうすればよいですか?

私のプログラムは次のようになります。

#include "mpi.h" 

#include <stdbool.h> 
#include "stdio.h" 
#include "stdlib.h" 

int main(int argc, char* argv[]) 
{ 
    MPI_Init(&argc, &argv); 
    int rank, p; 
    MPI_Comm_rank(MPI_COMM_WORLD, &rank); 
    MPI_Comm_size(MPI_COMM_WORLD, &p); 

    //ASSUMPTION: using 4 procs 
    //Don't worry about this part. 
    //just some stupid way to determine the receivers. 
    // Irrelevant to the question. 
    int recvs[3]; 
    int i = 0, nei = 0; 
    for (; nei < 4; ++nei) 
    { 
     if (nei != rank)   
     { 
      recvs[i] = nei;  
      ++i;   
     } 
    } 

    //Proc sending msgs to its neighbors. 
    //In this case, it's all other procs. (but in my real app, it's almost never the case) 
    int TAG = 0; 
    int buff[4] = {555, 666, 777, 888}; 
    int local_counts[4] = {0, 0, 0, 0}; //EDIT 1 
    for (nei = 0; nei < 3; ++nei) 
    { 
     for (i = 0; i < 4; ++i) 
     { 
      MPI_Request req; 
      MPI_Isend(&buff[i], 1, MPI_INT, recvs[nei], TAG, MPI_COMM_WORLD, &req);    
      local_counts[recvs[nei]] += 1; //EDIT 1 
     } 
    } 

    //EDIT 1: tell processors how many msgs they're supposed to get 
    int global_counts[4]; 
    int expectedRecvCount; 
    MPI_Reduce(local_counts, global_counts, 4, MPI_INT, MPI_SUM, 0, MPI_COMM_WORLD); 
    MPI_Scatter(global_counts, 1, MPI_INT, &expectedRecvCount, 1, MPI_INT, 0, MPI_COMM_WORLD); 

    //Receiving 
    int recvCount = 0;  
    MPI_Status status; 
    int hasMsg = 0;  
    int num; 
    do 
    { 
     MPI_Iprobe(MPI_ANY_SOURCE, TAG, MPI_COMM_WORLD, &hasMsg, &status);    
     if (hasMsg) 
     { 
      MPI_Recv(&num, 1, MPI_INT, status.MPI_SOURCE, TAG, MPI_COMM_WORLD, MPI_STATUS_IGNORE); 
      ++recvCount; 
      printf("\nRank %d got %d from %d", rank, num, status.MPI_SOURCE);  
     }  
    } 
    while (recvCount < expectedRecvCount); //EDIT 1 
    //while (hasMsg); 

    //Total number msgs received by all procs. 
    //Now here's where I see the problem!!! 
    MPI_Allreduce(&recvCount, &global_count, 1, MPI_INT, MPI_SUM, MPI_COMM_WORLD); 
    printf("\nRank %d receives %d msgs; Global count = %d", rank, recvCount, global_count); 

    MPI_Finalize();  
    return 0; 

}

============================ ===============私は考えることができる

EDIT 1

一つのアプローチは、各プロセッサは、それが他のすべてのプロセッサを送信されたメッセージの数を追跡することです。その後、送信操作が完了した後、私はMPI_Reduceを実行し、次にこれらのメッセージ数ではMPI_Scatterを実行します。そうすれば、各プロセッサは受信するメッセージの数を知ることができます。 (コードを参照してください) 誰もこのアプローチのパフォーマンスについてコメントできますか?パフォーマンスを潜在的かつ真剣に妨げてしまうでしょうか?

答えて

2

受信者側から、MPI_Isendを使用して送信されたすべてのメッセージが受信されたことを確認するにはどうすればよいですか? - MPIがその機能を提供していない場合、すべてのMPI_Isend操作が完了したことだけを知ることができます。

問題を言い換えると、基本的に受信者は送信者が送信するメッセージの数を認識しません。しかし、送信者は送信するメッセージがなくなったときを知っています。だから、ランクnからそれ以上のメッセージを受信しないことを受信者に知らせるメッセージを使用できますか?

あなたのコードは、MPI_Isend操作のすべてが完了していることを確認するには、別の問題を段階的に解消していますか?

ここにあなたの例に基づくコードがあります。 MPI_Iprobeとif文の間には計算がないので、私はMPI_Iprobeを使用しませんでした。代わりに、私はMPI_Probeを使用しました。

次のコードは、すべてのメッセージが送信され、メッセージがstopTAGメッセージを受信したときに他のすべてのプロセスからメッセージの受信を停止することを保証します。

#include "mpi.h" 

#include <stdbool.h> 
#include "stdio.h" 
#include "stdlib.h" 

int main(int argc, char* argv[]) 
{ 
    MPI_Init(&argc, &argv); 
    int rank, size; 
    MPI_Comm_rank(MPI_COMM_WORLD, &rank); 
    MPI_Comm_size(MPI_COMM_WORLD, &size); 

    //ASSUMPTION: using 4 procs 
    //Don't worry about this part. 
    //just some stupid way to determine the receivers. 
    // Irrelevant to the question. 
    int recvs[3]; 
    int i = 0, nei = 0; 
    for (; nei < 4; ++nei) 
    { 
     if (nei != rank)   
     { 
      recvs[i] = nei;  
      ++i;   
     } 
    } 

    //Proc sending msgs to its neighbors. 
    //In this case, it's all other procs. (but in my real app, it's almost never the case) 
    int TAG = 0; 
    int stopTAG = 1; 
    int buff[4] = {555, 666, 777, 888}; 
    MPI_Request req[3*5]; 
    for (nei = 0; nei < 3; ++nei) 
    { 
     for (i = 0; i < 4; ++i) 
     { 
      MPI_Isend(&buff[i], 1, MPI_INT, recvs[nei], TAG, 
         MPI_COMM_WORLD, &req[nei * 5 + i]); 
     } 
    } 
    for (nei = 0; nei < 3; ++nei) { 
     MPI_Isend(NULL, 0, MPI_CHAR, recvs[nei], stopTAG, MPI_COMM_WORLD, 
        &req[nei * 5 + 4]); 
    } 

    //Receiving 
    int recvCount = 0;  
    MPI_Status status; 
    int hasMsg = 0;  
    int num; 
    char stopArray[size]; 
    for (i = 0; i < size; i++) { 
     stopArray[i] = 0; 
    } 
    stopArray[rank] = 1; 
    char stop; 

    int completedSends = 0; 

    do 
    { 
     MPI_Probe(MPI_ANY_SOURCE, MPI_ANY_TAG, MPI_COMM_WORLD, &status); 
     if (status.MPI_TAG == TAG) 
     { 
      MPI_Recv(&num, 1, MPI_INT, status.MPI_SOURCE, TAG, 
         MPI_COMM_WORLD, MPI_STATUS_IGNORE); 
      ++recvCount; 
      printf("Rank %d got %d from %d\n", rank, num, 
         status.MPI_SOURCE); 
     } 
     else if (status.MPI_TAG == stopTAG) { 
      MPI_Recv(NULL, 0, MPI_CHAR, status.MPI_SOURCE, stopTAG, 
         MPI_COMM_WORLD, MPI_STATUS_IGNORE); 

      stopArray[status.MPI_SOURCE] = 1; 
     } 
     stop = 1; 
     for (i = 0; i < size; i++) { 
      stop &= stopArray[i]; 
     } 
     if (completedSends < (3*5)) { 
      int indx; 
      MPI_Status status; 
      MPI_Waitany(3*5, req, &indx, &status); 
      completedSends++; 
     } 
    } 
    while (!stop && (completedSends <= 15)); 

    //Total number msgs received by all procs. 
    //Now here's where I see the problem!!! 
    int global_count; 
    MPI_Allreduce(&recvCount, &global_count, 1, MPI_INT, MPI_SUM, 
        MPI_COMM_WORLD); 
    printf("\nRank %d receives %d msgs;\nGlobal count = %d\n", rank, 
       recvCount, global_count); 

    MPI_Finalize(); 

    return 0; 

} 
+0

ありがとう@Angelos!私は実際にメッセージカウンターを使うことを考えています。投稿の編集を参照してください。 – 0x56794E

+1

@Angelosのソリューションは、IMHOであり、集合的なコミュニケーションを含むあらゆるものよりはるかにエレガントです。その正確さは、MPIがメッセージの順序付けを維持していること、すなわち、MPI_ANY_TAGがreceiveTAGメッセージに一致する前にTAG *としてタグ付けされたすべてのメッセージと一致することが保証されているという事実に依存することが重要です。 –

関連する問題