2017-09-17 4 views
2

私はmpiでフラクタル画像の並列計算を実行しようとしています。 私は4パートで私のプログラムを分割しました:2D int配列を送信しようとするとMPI_Sendがブロックされるのはなぜですか?

  1. バランス各ランク
  2. によって行御馳走の数は、行の数と行の送信ランクに
  3. を各行属性のCalculがを実行しますランクに0

ステップ1と2が動作している(テストだけでint型を印刷するために)ランク0のデータを扱うが、私は、行を送信しようとしているとき0にプログラムをランク付けします停止してブロックしています。私は、MPI_Sendがブロックすることができることを知っています。ここには理由はありません。

ステップ1:

#include <stdio.h> 
#include <stdlib.h> 
#include <string.h> 

/* Include the MPI library for function calls */ 
#include <mpi.h> 

/* Define tags for each MPI_Send()/MPI_Recv() pair so distinct messages can be 
* sent */ 
#define OTHER_N_ROWS_TAG 0 
#define OTHER_PIXELS_TAG 1 

int main(int argc, char **argv) { 
    const int nRows = 513; 
    const int nCols = 513; 
    const int middleRow = 0.5 * (nRows - 1); 
    const int middleCol = 0.5 * (nCols - 1); 
    const double step = 0.00625; 
    const int depth = 100; 
    int pixels[nRows][nCols]; 
    int row; 
    int col; 
    double xCoord; 
    double yCoord; 
    int i; 
    double x; 
    double y; 
    double tmp; 
    int myRank; 
    int nRanks; 
    int evenSplit; 
    int nRanksWith1Extra; 
    int myRow0; 
    int myNRows; 
    int rank; 
    int otherNRows; 
    int otherPixels[nRows][nCols]; 

    /* Each rank sets up MPI */ 
    MPI_Init(&argc, &argv); 

    /* Each rank determines its ID and the total number of ranks */ 
    MPI_Comm_rank(MPI_COMM_WORLD, &myRank); 
    MPI_Comm_size(MPI_COMM_WORLD, &nRanks); 
    printf("My rank is %d \n",myRank); 
    evenSplit = nRows/nRanks; 
    nRanksWith1Extra = nRows % nRanks; 

/*Each rank determine the number of rows that he will have to perform (well balanced)*/ 
    if (myRank < nRanksWith1Extra) { 

    myNRows = evenSplit + 1; 
    myRow0 = myRank * (evenSplit + 1); 
    } 
    else { 
    myNRows = evenSplit; 
    myRow0 = (nRanksWith1Extra * (evenSplit + 1)) + 
     ((myRank - nRanksWith1Extra) * evenSplit); 
    } 
/*__________________________________________________________________________________*/ 

ステップ2:

/*_____________________PERFORM CALCUL ON EACH PIXEL________________________________ */ 
    for (row = myRow0; row < myRow0 + myNRows; row++) { 

    /* Each rank loops over the columns in the given row */ 
    for (col = 0; col < nCols; col++) { 

     /* Each rank sets the (x,y) coordinate for the pixel in the given row and 
     * column */ 
     xCoord = (col - middleCol) * step; 
     yCoord = (row - middleRow) * step; 

     /* Each rank calculates the number of iterations for the pixel in the 
     * given row and column */ 
     i = 0; 
     x = 0; 
     y = 0; 
     while ((x*x + y*y < 4) && (i < depth)) { 
     tmp = x*x - y*y + xCoord; 
     y = 2*x*y + yCoord; 
     x = tmp; 
     i++; 
     } 

     /* Each rank stores the number of iterations for the pixel in the given 
     * row and column. The initial row is subtracted from the current row 
     * so the array starts at 0 */ 
     pixels[row - myRow0][col] = i; 
    } 
     //printf("one row performed by %d \n",myRank); 

    } 
     printf("work done by %d \n",myRank); 
/*_________________________________________________________________________________*/ 

ステップ3:

/*__________________________SEND DATA TO RANK 0____________________________________*/ 

    /* Each rank (including Rank 0) sends its number of rows to Rank 0 so Rank 0 
    * can tell how many pixels to receive */ 
    MPI_Send(&myNRows, 1, MPI_INT, 0, OTHER_N_ROWS_TAG, MPI_COMM_WORLD); 
    printf("test \n"); 
    /* Each rank (including Rank 0) sends its pixels array to Rank 0 so Rank 0 
    * can print it */ 
    MPI_Send(&pixels, sizeof(int)*myNRows * nCols, MPI_BYTE, 0, OTHER_PIXELS_TAG, 
     MPI_COMM_WORLD); 
    printf("enter ranking 0 \n"); 
/*_________________________________________________________________________________*/ 

ステップ4:

ここ

2の最初のステップであります
/*________________________TREAT EACH ROW IN RANK 0_________________________________*/ 
    /* Only Rank 0 prints so the output is in order */ 
    if (myRank == 0) { 

    /* Rank 0 loops over each rank so it can receive that rank's messages */ 
    for (rank = 0; rank < nRanks; rank++){ 

     /* Rank 0 receives the number of rows from the given rank so it knows how 
     * many pixels to receive in the next message */ 
     MPI_Recv(&otherNRows, 1, MPI_INT, rank, OTHER_N_ROWS_TAG, 
     MPI_COMM_WORLD, MPI_STATUS_IGNORE); 

     /* Rank 0 receives the pixels array from each of the other ranks 
     * (including itself) so it can print the number of iterations for each 
     * pixel */ 
     MPI_Recv(&otherPixels, otherNRows * nCols, MPI_INT, rank, 
      OTHER_PIXELS_TAG, MPI_COMM_WORLD, MPI_STATUS_IGNORE); 

     /* Rank 0 loops over the rows for the given rank */ 
     for (row = 0; row < otherNRows; row++) { 

     /* Rank 0 loops over the columns within the given row */ 
     for (col = 0; col < nCols; col++) { 

      /* Rank 0 prints the value of the pixel at the given row and column 
      * followed by a comma */ 
      printf("%d,", otherPixels[row][col]); 
     } 

     /* In between rows, Rank 0 prints a newline character */ 
     printf("\n"); 
     } 
    } 
    } 

    /* All processes clean up the MPI environment */ 
    MPI_Finalize(); 

    return 0; 
} 

私はなぜそれがブロックされているのか理解したいと思います、あなたは私を説明できますか? 私はMPIの新しいユーザーです。私はそれが働いているプログラムを持っているだけでなく、それを学びたいと思います。

ありがとうございます。

答えて

1

MPI_Send動作を遮断標準の定義によってあります。手段を遮断することを

注:送信者は送信バッファを変更して自由であるように

を、それはメッセージデータとエンベロープまで戻りませんが安全に離れて格納されています。メッセージは、一致する受信バッファに直接コピーされるか、または一時的なシステムバッファにコピーされる可能性があります。

メッセージを自分宛に送信しようとすると、MPI_SendMPI_Recvがデッドロックになります。

適切な一括通信操作MPI_GatherおよびMPI_Gathervを使用することです。

1

ランク0自体に送信するときにブロッキングsend/recv構造体を使用すると、デッドロックが発生する可能性があります。 MPI 3.0 standard, Section 3.2.4から

ソース=先はつまり、プロセスが自分自身にメッセージを送ることができ、許可されています。 (。。しかし、それはこれがデッドロックにつながる可能性があるため、ブロッキング送信および受信操作は 、上記でそうすることは危険です3.5節を参照してください)

考えられる解決策:

  • 使用不ランク0との間で送受信を行う場合、send/recvの構造をブロックします。詳細については、MPI_Isend,MPI_IrecvおよびMPI_Waitルーチンを参照してください。
  • ランク0自体との通信を削除します。あなたはランク0になっているので、計算しなければならないピクセルの数を知る方法はすでにあります。
1

前の回答で説明したように、MPI_Send()ブロックです。

理論的には、デッドロックの可能性があるため、アプリケーションが正しくありません(受信がポストされていない場合はランク0MPI_Send())。 小さなメッセージが(例えばmyNRowsとして)送信された場合、ビューの非常に実用的な観点から

は、MPI_Send()は、一般的にすぐに戻り、しかしマッチングまでのブロックは、メッセージが(例えばpixelsとして送信されたときに転記され受け取ります)。

  • 小さなは、少なくともMPIライブラリーと使用されている相互接続の両方に依存しますのでご注意ください
  • MPI_Send()がためにすぐに返すことを想定して、ビューのMPI点から間違っていますsmallメッセージ

あなたが本当にあなたのアプリケーションは、あなたが単にMPI_Ssend()MPI_Send()を置き換えることができ、デッドロックフリーであることを確認したい場合は。ランク0は、(すべての情報はそうでは通信が

  • は前MPI_Irecv()を投稿する必要はありません、利用可能である自分自身と通信しないように

    戻るあなたの質問に、いくつかのオプションがここにあります

      アプリを改造
    • MPI_Send()、およびアプリそう0ではなくMPI_Send()MPI_Recv(source=0)が、MPI_SendrecvをしませんランクMPI_Wait()
    • 刷新とMPI_Recv(source=0)を交換してください。のThあなたがコミュニケーションパターン(計算パターンはそのまま)に少し変更を加えるだけで済むので、私の推奨するオプションはよりエレガントなイホです。
  • 関連する問題