2017-02-21 13 views
0

誰かが説明を提供できるかどうか疑問に思っています。私は、コードから始めましょう異常なMPIの振舞い

:行動

コード予想

/* 
Barrier implemented using tournament-style coding 
*/ 

// Constraints: Number of processes must be a power of 2, e.g. 
// 2,4,8,16,32,64,128,etc. 

#include <mpi.h> 
#include <stdio.h> 
#include <unistd.h> 

void mybarrier(MPI_Comm); 

// global debug bool 
int verbose = 1; 

int main(int argc, char * argv[]) { 
    int rank; 
    int size; 

    int i; 
    int sum = 0; 

    MPI_Init(&argc, &argv); 
    MPI_Comm_rank(MPI_COMM_WORLD, &rank); 
    MPI_Comm_size(MPI_COMM_WORLD, &size); 

    int check = size; 

    // check to make sure the number of processes is a power of 2 
    if (rank == 0){ 
     while(check > 1){ 
      if (check % 2 == 0){ 
       check /= 2; 
      } else { 
       printf("ERROR: The number of processes must be a power of 2!\n"); 
       MPI_Abort(MPI_COMM_WORLD, 1); 
       return 1; 
      } 
     } 
    } 

    // simple task, with barrier in the middle 
    for (i = 0; i < 500; i++){ 
    sum ++; 
    } 
    mybarrier(MPI_COMM_WORLD); 
    for (i = 0; i < 500; i++){ 
    sum ++; 
    } 

    if (verbose){ 
     printf("process %d arrived at finalize\n", rank); 
    } 
    MPI_Finalize(); 
    return 0; 
} 

void mybarrier(MPI_Comm comm){ 
    // MPI variables 
    int rank; 
    int size; 

    int * data; 

    MPI_Status * status; 

    // Loop variables 
    int i; 
    int a; 

    int skip; 

    int complete = 0; 
    int currentCycle = 1; 

    // Initialize MPI vars 
    MPI_Comm_rank(comm, &rank); 
    MPI_Comm_size(comm, &size); 

    // step 1, gathering 
    while (!complete){ 
     skip = currentCycle * 2; 

     // if currentCycle divides rank evenly, then it is a target 
     if ((rank % currentCycle) == 0){ 
      // if skip divides rank evenly, then it needs to receive 
      if ((rank % skip) == 0){ 
       MPI_Recv(data, 0, MPI_INT, rank + currentCycle, 99, comm, status); 
       if (verbose){ 
        printf("1: %d from %d\n", rank, rank + currentCycle); 
       } 
      // otherwise, it needs to send. Once sent, the process is done 
      } else { 
       if (verbose){ 
        printf("1: %d to %d\n", rank, rank - currentCycle); 
       } 
       MPI_Send(data, 0, MPI_INT, rank - currentCycle, 99, comm); 
       complete = 1; 
      } 
     } 

     currentCycle *= 2; 

     // main process will never send, so this code will allow it to complete 
     if (currentCycle >= size){ 
      complete = 1; 
     } 
    } 

    complete = 0; 
    currentCycle = size/2; 

    // step 2, scattering 

    while (!complete){ 
     // if currentCycle is 1, then this is the last loop 
     if (currentCycle == 1){ 
      complete = 1; 
     } 

     skip = currentCycle * 2; 

     // if currentCycle divides rank evenly then it is a target 
     if ((rank % currentCycle) == 0){ 
      // if skip divides rank evenly, then it needs to send 
      if ((rank % skip) == 0){ 
       if (verbose){ 
        printf("2: %d to %d\n", rank, rank + currentCycle); 
       } 
       MPI_Send(data, 0, MPI_INT, rank + currentCycle, 99, comm); 
      // otherwise, it needs to receive 
      } else { 
       if (verbose){ 
        printf("2: %d waiting for %d\n", rank, rank - currentCycle); 
       } 
       MPI_Recv(data, 0, MPI_INT, rank - currentCycle, 99, comm, status); 
       if (verbose){ 
        printf("2: %d from %d\n", rank, rank - currentCycle); 
       } 
      } 
     } 

     currentCycle /= 2; 
    } 
} 

は、ブロッキングMPI_Send関数とMPI_RECV呼び出しを使用してそのポイントに到達するために他のすべてのプロセスを待ち、500に合計をインクリメントすることです、その後、

予想どおりにクラスターに

クラスタの動作1000

観察された挙動に合計をインクリメント

異常行動私のマシン

に観察主な機能のすべてのプロセスは、私は、具体的mybarrierの第二のwhileループのタグにリンクされている99、であると報告されています。

加え

で私の最初のドラフトは、forループで書かれた、とだけでなく、クラスタ上で予想されるように、その1で、プログラムが実行されますが、私のマシンの実行にすべてのプロセスがMPI_Finalize(呼び出しにもかかわらず、終了したことがありませんしかし、それを超えて動くものはありません)。

MPIのバージョン

私のマシンは、私は私のマシンが突然のすべてを実行するように見えることを観察した

クラスタがOpenRTE 1.6.3

質問を実行しているOpenRTE 2.0.2 を実行していますクラスタは正常に実行されます。これは私が書いた他のMPIコードにも当てはまります。私が気づいていない1.6.3と2.0.2の間に大きな変更がありましたか?

いずれにせよ、私は困惑しています。なぜ私のマシンがMPIを正しく実行していないように見えるのか誰かが説明できるかどうか疑問に思っていました。十分な詳細を提供していただければ幸いですが、必要でない場合は、必要な追加情報を提供いたします。

答えて

3

あなたのコードに問題があります。あなたが見ている奇妙な動作を引き起こしているかもしれません。

MPI_Recvルーチンstatus割り当てられていないオブジェクトに渡しています。実際には、そのポインタは初期化されていないので、NULLにならない場合、MPI_Recvは未定義の動作を引き起こすメモリ内のどこにでも書き込みを行います。

MPI_Status status; 
... 
MPI_Recv(..., &status); 

それとも、ヒープ使用する場合:正しい形式は以下の通りである。また

MPI_Status *status = malloc(sizeof(MPI_Status)); 
... 
MPI_Recv(..., status); 
... 
free(status); 

をあなたが受け取るによって返された値を使用していないので、あなたが代わりにMPI_STATUS_IGNOREを代わりに使用する必要があります。

MPI_Recv(..., MPI_STATUS_IGNORE); 
+0

私はそれを修正したと信じています。ご協力いただきありがとうございます。私はMPIを初めて使っているので、私はまだすべてがどのように機能するか把握しようとしています。 – electr0sheep