2017-05-12 5 views
2

1,2,4または8個のプロセッサを使用して、MPIで単純な行列乗算プログラムを作成しようとしています。私のコードは1で動作します(その場合、通常の行列乗算しか行いません。とにかく1つのランクで実行するだけで分割する作業はありません)。また、2プロセッサーと4プロセッサーで動作します。しかし、私が8つのプロセッサ(プログラムを実行しているときにコマンドラインで-n 8)を使用しようとすると、マトリックスcのすべての場所に適切な値が得られません。ここMPIでの行列の乗算

の例である:

8.00 8.00 8.00 8.00 8.00 8.00 8.00 8.00 
    8.00 8.00 8.00 8.00 8.00 8.00 8.00 8.00 
    8.00 8.00 8.00 8.00 8.00 8.00 8.00 8.00 
    8.00 8.00 8.00 8.00 8.00 8.00 8.00 8.00 
    16.00 16.00 16.00 16.00 16.00 16.00 16.00 16.00 
    16.00 16.00 16.00 16.00 16.00 16.00 16.00 16.00 
    16.00 16.00 16.00 16.00 16.00 16.00 16.00 16.00 
    0.00 0.00 16.00 16.00 16.00 16.00 16.00 16.00 

およびサイズ= 16であれば:

SIZE = 8(つまり、AとBとCは、すべての8×8行列である)場合、結果の行列は、次の通りであります
16.00 16.00 16.00 16.00 16.00 16.00 16.00 16.00 16.00 16.00 16.00 16.00 16.00 16.00 16.00 16.00 
    16.00 16.00 16.00 16.00 16.00 16.00 16.00 16.00 16.00 16.00 16.00 16.00 16.00 16.00 16.00 16.00 
    16.00 16.00 16.00 16.00 16.00 16.00 16.00 16.00 16.00 16.00 16.00 16.00 16.00 16.00 16.00 16.00 
    16.00 16.00 16.00 16.00 16.00 16.00 16.00 16.00 16.00 16.00 16.00 16.00 16.00 16.00 16.00 16.00 
    16.00 16.00 16.00 16.00 16.00 16.00 16.00 16.00 16.00 16.00 16.00 16.00 16.00 16.00 16.00 16.00 
    16.00 16.00 16.00 16.00 16.00 16.00 16.00 16.00 16.00 16.00 16.00 16.00 16.00 16.00 16.00 16.00 
    16.00 16.00 16.00 16.00 16.00 16.00 16.00 16.00 16.00 16.00 16.00 16.00 16.00 16.00 16.00 16.00 
    16.00 16.00 16.00 16.00 16.00 16.00 16.00 16.00 16.00 16.00 16.00 16.00 16.00 16.00 16.00 16.00 
    32.00 32.00 32.00 32.00 32.00 32.00 32.00 32.00 32.00 32.00 32.00 32.00 32.00 32.00 32.00 32.00 
    32.00 32.00 32.00 32.00 32.00 32.00 32.00 32.00 32.00 32.00 32.00 32.00 32.00 32.00 32.00 32.00 
    32.00 32.00 32.00 32.00 32.00 32.00 32.00 32.00 32.00 32.00 32.00 32.00 32.00 32.00 32.00 32.00 
    32.00 32.00 32.00 32.00 32.00 32.00 32.00 32.00 32.00 32.00 32.00 32.00 32.00 32.00 32.00 32.00 
    32.00 32.00 32.00 32.00 32.00 32.00 32.00 32.00 32.00 32.00 32.00 32.00 32.00 32.00 32.00 32.00 
    32.00 32.00 32.00 32.00 32.00 32.00 32.00 32.00 32.00 32.00 32.00 32.00 32.00 32.00 32.00 32.00 
    0.00 0.00 0.00 0.00 32.00 32.00 32.00 32.00 32.00 32.00 32.00 32.00 32.00 32.00 32.00 32.00 
    32.00 32.00 32.00 32.00 32.00 32.00 32.00 32.00 32.00 32.00 32.00 32.00 32.00 32.00 32.00 32.00 

ご覧のとおり、左下にゼロが表示されます。ランク7が行っていることは、それらの座標が0になることです。

私は自分のコードを自分で見つめていました。私はもう一組の目が必要だと感じています。私が知る限り、すべての送受信は適切に動作し、すべての異なるタスクは、それらが想定していた価値を得ます。私が行ったテストから、実際にはC行列のどこにも0の値が与えられません。なぜそれが起こるのか、どうやってそれを修正するためにできるのか分かりません。ここで

コードです:何かアドバイスが参考になる

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

#define SIZE 16 /*assumption: SIZE a multiple of number of nodes*/ 
#define FROM_MASTER 1/*setting a message type*/ 
#define FROM_WORKER 2/*setting a message type*/ 
#define DEBUG 1/*1 = debug on, 0 = debug off*/ 

MPI_Status status; 

static double a[SIZE][SIZE]; 
static double b[SIZE][SIZE]; 
static double c[SIZE][SIZE]; 
static double b_to_trans[SIZE][SIZE]; 
static void init_matrix(void) 
{ 
    int i, j; 
    for (i = 0; i < SIZE; i++) 
    { 
     for (j = 0; j < SIZE; j++) { 
      a[i][j] = 1.0; 
      if(i >= SIZE/2) a[i][j] = 2.0; 
      b_to_trans[i][j] = 1.0; 
      if(j >= SIZE/2) b[i][j] = 2.0; 
//   c[i][j] = 1.0; 
     } 
    } 
} 

static void print_matrix(void) 
{ 
    int i, j; 
    for(i = 0; i < SIZE; i++) { 
     for(j = 0; j < SIZE; j++) { 
      printf("%7.2f", c[i][j]); 
     } 
    printf("\n"); 
    } 
} 

static void transpose_matrix() 
{ 
    int i, j; 
    for(i = 0; i<SIZE; i++) 
     for(j = 0; j<SIZE;j++) 
      b[i][j] = b_to_trans[j][i]; 
} 

int main(int argc, char **argv) 
{ 
    int myrank, nproc; 
    int rows; /*amount of work per node (rows per worker)*/ 
    int mtype; /*message type: send/recv between master and workers*/ 
    int dest, src, offseta, offsetb; 
    int runthrough, runmod; 
    double start_time, end_time; 
    int i, j, k, l; 

    MPI_Init(&argc, &argv); 
    MPI_Comm_size(MPI_COMM_WORLD, &nproc); 
    MPI_Comm_rank(MPI_COMM_WORLD, &myrank); 
    rows = SIZE/nproc; 
    mtype = FROM_MASTER; 

    if (myrank == 0) { 
     /*Initialization*/ 
     printf("SIZE = %d, number of nodes = %d\n", SIZE, nproc); 
     init_matrix(); 
     transpose_matrix(); 
     start_time = MPI_Wtime(); 

     if(nproc == 1) { /*In case we only run on one processor, the master will simply do a regular matrix-matrix multiplacation.*/ 
      for(i = 0; i < SIZE; i++) { 
       for(j = 0; j < SIZE; j++) { 
        for(k = 0; k < SIZE; k++) 
         c[i][j] = c[i][j] + a[i][k]*b[j][k]; 
       } 
      } 
      end_time = MPI_Wtime(); 
      if(DEBUG) /*Prints the resulting matrix c*/ 
       print_matrix(); 
      printf("Execution time on %2d nodes: %f\n", nproc, end_time-start_time); 
     } 
     else { 

      for(l = 0; l < nproc; l++){ 
       offsetb = rows*l; 
       offseta = rows; 
       mtype = FROM_MASTER; 

       for(dest = 1; dest < nproc; dest++){ 
        MPI_Send(&offseta, 1, MPI_INT, dest, mtype, MPI_COMM_WORLD); 
        MPI_Send(&offsetb, 1, MPI_INT, dest, mtype, MPI_COMM_WORLD); 
        MPI_Send(&rows, 1, MPI_INT, dest, mtype, MPI_COMM_WORLD); 
        MPI_Send(&a[offseta][0], rows*SIZE, MPI_DOUBLE, dest, mtype, MPI_COMM_WORLD); 
        MPI_Send(&b[offsetb][0], rows*SIZE, MPI_DOUBLE, dest, mtype, MPI_COMM_WORLD); 
        offseta += rows; 
        offsetb = (offsetb+rows)%SIZE; 
       } 

       offseta = rows; 
       offsetb = rows*l; 
       //printf("Rank: %d, offseta: %d, offsetb: %d\n", myrank, offseta, offsetb); 
       //printf("Offseta: %d\n", offseta); 
       //printf("Offsetb: %d\n", offsetb); 
       for(i = 0; i < offseta; i++) { 
        for(j = offsetb; j < offsetb+rows; j++) { 
          for(k = 0; k < SIZE; k++){ 
           c[i][j] = c[i][j] + a[i][k]*b[j][k]; 
         } 
        } 
       } 
       mtype = FROM_WORKER; 
       for(src = 1; src < nproc; src++){ 
        MPI_Recv(&offseta, 1, MPI_INT, src, mtype, MPI_COMM_WORLD, &status); 
        MPI_Recv(&offsetb, 1, MPI_INT, src, mtype, MPI_COMM_WORLD, &status); 
        MPI_Recv(&rows, 1, MPI_INT, src, mtype, MPI_COMM_WORLD, &status); 
        for(i = 0; i < rows; i++) { 
         MPI_Recv(&c[offseta+i][offsetb], offseta, MPI_DOUBLE, src, mtype, MPI_COMM_WORLD, &status); /*returns answer c(1,1)*/ 
        } 
       } 
      } 


      end_time = MPI_Wtime(); 
      if(DEBUG) /*Prints the resulting matrix c*/ 
       print_matrix(); 
      printf("Execution time on %2d nodes: %f\n", nproc, end_time-start_time); 
     } 
    } 
    else{ 
     if(nproc > 1) { 
      for(l = 0; l < nproc; l++){ 
       mtype = FROM_MASTER; 
       MPI_Recv(&offseta, 1, MPI_INT, 0, mtype, MPI_COMM_WORLD, &status); 
       MPI_Recv(&offsetb, 1, MPI_INT, 0, mtype, MPI_COMM_WORLD, &status); 
       MPI_Recv(&rows, 1, MPI_INT, 0, mtype, MPI_COMM_WORLD, &status); 
       MPI_Recv(&a[offseta][0], rows*SIZE, MPI_DOUBLE, 0, mtype, MPI_COMM_WORLD, &status); 
       MPI_Recv(&b[offsetb][0], rows*SIZE, MPI_DOUBLE, 0, mtype, MPI_COMM_WORLD, &status); 

       for(i = offseta; i < offseta+rows; i++) { 
        for(j = offsetb; j < offsetb+rows; j++) { 
         for(k = 0; k < SIZE; k++){ 
          c[i][j] = c[i][j] + a[i][k]*b[j][k]; 
         } 
        } 
       } 

       mtype = FROM_WORKER; 
       MPI_Send(&offseta, 1, MPI_INT, 0, mtype, MPI_COMM_WORLD); 
       MPI_Send(&offsetb, 1, MPI_INT, 0, mtype, MPI_COMM_WORLD); 
       MPI_Send(&rows, 1, MPI_INT, 0, mtype, MPI_COMM_WORLD); 
       for(i = 0; i < rows; i++){ 
        MPI_Send(&c[offseta+i][offsetb], offseta, MPI_DOUBLE, 0, mtype, MPI_COMM_WORLD); 
       } 
      } 
     } 
    } 
    MPI_Finalize(); 
    return 0; 
} 

、事前にあなたに感謝。

+0

Jensあなたはあなたのコードをペーストビンの上に置くのではなく、ここに追加するべきです(私は今あなたのために行います)ので、クローズド投票をしないでください –

+0

人々がコード全体を望むかどうかはわかりませんでしたここにいるか、ページを洪水させるだろうと不平を言うならば。しかし、いずれにしても、ありがとうございました。 –

+0

こんにちはジェンスは、あなたのコードを見て、mpirunは間違いなく問題を作り出しています。私は行列の乗算ソリューションをやり直すつもりです。あなたのデバッグではなく、コメントを付けてください(左下にあります) –

答えて

1

これは明確な答えではありませんが、確かにデバッグに役立つはずです。

私は、masterが労働者から最終的なデータを受け取った直後に次のコードを追加してテストを行いました。出力の束の中で、私は重要なものだけを示します。プロセッサ数が8の場合を除き、j+countSIZEを決して超えないことに注意してください。これは、割り当てられていないメモリに書き込むため重要です。

for(i = 0; i < rows; i++) { 
    MPI_Recv(&c[offseta+i][offsetb], offseta, MPI_DOUBLE, src, mtype, MPI_COMM_WORLD, &status); 
    // I added the following for debugging.    
    if (src == nproc-1) 
    { 
     printf("src = %i\n", src); 
     printf("i = %i\n", offseta+i); 
     printf("j = %i\n", offsetb); 
     printf("count = %i\n", offseta); 
    } 
} 

NP = 2

src = 1 
i = 15 
j = 8 
count = 8 

NP = 4

src = 3 
i = 15 
j = 4 
count = 12 

NP = 8

src = 7 
i = 15 
j = 10 
count = 14 
+0

私はこの状況が私にとって状況を明らかにしてくれると言いたいのですが、これがどう重要なのか理解する。 Offsetaとoffset b(あなたのprintfsのjとcount)は単なる整数です。それらの合計はサイズより大きいかもしれませんが、私はたった今c [offseta + i] [offsetb]に書きます。 offseta + iまたはoffsetbが大きさより大きければ、割り振られていないメモリにどのように到達するのか分かりません。これはCとMPIの両方で初めてのことですので、私はおそらく無知から何かを見逃しています... –

+0

例として、受信バッファのアドレスは 'c [15] [10]'ですので、 'MPI_DOUBLE' 。 'c [15] [16]'。 'c [15] [17]'などは割り当てられていないメモリ空間です。右? MPI_DOUBLEが5ではなく、14を受け取ることに注意してください。 – Shibli

+0

これは私が必要としたヒントの最後の部分であり、私はそれを解決することができました。これを見ると、offsetaの値が変更されたときに、送信したいバイト数を宣言することは "offseta"でした。私はsendとrecieveを変更してメモリを変更する代わりに、メモリの '行'量を送信して受信するように修正しました。 ありがとうございました^^私はあなたの答えを正しく宣言しupvoteします。 –