0

プロセスから列を送信し、別のプロセスで受信する通信に問題がMPI_Sendあります。MPI_Recv

デバッグのために、 と で 10x10 行列 (x0配列)x_domain = 4を初期化する基本的な例を以下に示しますy_domain = 4。テストでは、2D 配列の値を で初期化するだけですx0[i][j] = i+j

rank=2から列を送信し、で受信するだけの次のテスト コードをコンパイルして実行してみてくださいrank=0(で実行する必要がありますnproc=4)。

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

int main(int argc, char *argv[]) 
    {
      /* size of the discretization */

      double** x;
      double** x0;
      int bonk1, bonk2;      
      int i,j,k,l;
      int nproc;
      int ndims; 
      int S=0, E=1, N=2, W=3;
      int NeighBor[4];
      int xcell, ycell, size_tot_x, size_tot_y;
      int *xs,*ys,*xe,*ye;
      int size_x = 4;
      int size_y = 4;
      int me;
      int x_domains=2;
      int y_domains=2;
      int flag = 1;      
      MPI_Comm comm, comm2d;
      int dims[2];
      int periods[2];
      int reorganisation = 0;
      int row;
      MPI_Datatype column_type;
      MPI_Status status;


      size_tot_x=size_x+2*x_domains+2;
      size_tot_y=size_y+2*y_domains+2;

      xcell=(size_x/x_domains);
      ycell=(size_y/y_domains);

      MPI_Init(&argc, &argv);
      comm = MPI_COMM_WORLD;
      MPI_Comm_size(comm,&nproc);
      MPI_Comm_rank(comm,&me);

      x = malloc(size_tot_y*sizeof(double*));
      x0 = malloc(size_tot_y*sizeof(double*));


      for(j=0;j<=size_tot_y-1;j++) {
        x[j] = malloc(size_tot_x*sizeof(double));
        x0[j] = malloc(size_tot_x*sizeof(double));
      }

      xs = malloc(nproc*sizeof(int));
      xe = malloc(nproc*sizeof(int));
      ys = malloc(nproc*sizeof(int));
      ye = malloc(nproc*sizeof(int));

      /* Create 2D cartesian grid */
      periods[0] = 0;
      periods[1] = 0;

      ndims = 2;
      dims[0]=x_domains;
      dims[1]=y_domains;

      MPI_Cart_create(comm, ndims, dims, periods, reorganisation, &comm2d);

      /* Identify neighbors */
      NeighBor[0] = MPI_PROC_NULL;
      NeighBor[1] = MPI_PROC_NULL;
      NeighBor[2] = MPI_PROC_NULL;
      NeighBor[3] = MPI_PROC_NULL;

      /* Left/West and right/Est neigbors */
      MPI_Cart_shift(comm2d,0,1,&NeighBor[W],&NeighBor[E]);
      /* Bottom/South and Upper/North neigbors */
      MPI_Cart_shift(comm2d,1,1,&NeighBor[S],&NeighBor[N]);

      /* coordinates of current cell with me rank */

      xcell=(size_x/x_domains);
      ycell=(size_y/y_domains);

      ys[me]=(y_domains-me%(y_domains)-1)*(ycell+2)+2;
      ye[me]=ys[me]+ycell-1;

      for(i=0;i<=y_domains-1;i++) 
      {xs[i]=2;}

      for(i=0;i<=y_domains-1;i++) 
      {xe[i]=xs[i]+xcell-1;}

      for(i=1;i<=(x_domains-1);i++)
         { for(j=0;j<=(y_domains-1);j++) 
              {
               xs[i*y_domains+j]=xs[(i-1)*y_domains+j]+xcell+2;
               xe[i*y_domains+j]=xs[i*y_domains+j]+xcell-1;
              }
         }

      for(i=0;i<=size_tot_y-1;i++)
          { for(j=0;j<=size_tot_x-1;j++)
            { x0[i][j]= i+j;
        }       
      }

      /*  Create column data type to communicate with South and North neighbors */



      MPI_Type_vector( ycell, 1, size_tot_x, MPI_DOUBLE, &column_type);  
      MPI_Type_commit(&column_type);

       if(me==2) {
       printf("Before Send - Process 2 subarray\n");
                    for(i=ys[me]-1;i<=ye[me]+1;i++)
                    { for(j=xs[me]-1;j<=xe[me]+1;j++)
                      { printf("%f ",x0[i][j]);
                      }
                      printf("\n");
                    }
                    printf("\n");



       MPI_Send(&(x0[ys[2]][xs[2]]), 1, column_type,  0, flag, comm2d );
       }

         if(me==0) {

     MPI_Recv(&(x0[ys[0]][xe[0]]), 1, column_type,  2, flag, comm2d , &status);
     printf("After Receive - Process 0 subarray\n");
                    for(i=ys[me]-1;i<=ye[me]+1;i++)
                    { for(j=xs[me]-1;j<=xe[me]+1;j++)
                      { printf("%f ",x0[i][j]);
                      }
                      printf("\n");
                    }
                    printf("\n");

        MPI_Get_count(&status,column_type,&bonk1);
        MPI_Get_elements(&status,MPI_DOUBLE,&bonk2);
        printf("got %d elements of type column_type\n",bonk1);
        printf("which contained %d elements of type MPI_DOUBLE\n",bonk2);
    printf("\n");

         }

              for(i=0;i<=size_tot_y-1;i++)
           {
            free(x[i]);
            free(x0[i]);
           }     

        free(x);
        free(x0);

        free(xs);
        free(xe);
        free(ys);
        free(ye);

        MPI_Finalize();

        return 0;
    }        

xs[me]xe[me]はそれぞれ と に対応x_start[me]x_end[me]ますrank = me。これは と についても同じys[me]ですye[me]

前の投稿で言ったように、rank のプロセスが受け取る列の最初の値しかありません0。このプログラムの出力は次のとおりです。

Before Send - Process 2 subarray
10.000000 11.000000 12.000000 13.000000
11.000000 **12.000000** 13.000000 14.000000
12.000000 **13.000000** 14.000000 15.000000
13.000000 14.000000 15.000000 16.000000

After Receive - Process 0 subarray
6.000000 7.000000 8.000000 9.000000
7.000000 8.000000 **12.000000** 10.000000
8.000000 9.000000 **10.000000** 11.000000
9.000000 10.000000 11.000000 12.000000

got 1 elements of type column_type
which contained 2 elements of type MPI_DOUBLE

最初の要素は取得12.00000しますが、2 番目の要素は10.00000代わりに13.00000.

私は次のように定義column_typeしました:

MPI_Type_vector( ycell, 1, size_tot_x, MPI_DOUBLE, &column_type); 
MPI_Type_commit(&column_type);

size_tot_xは、グローバル配列の列の総数に等しくなりますx0

どんな助けでも本当にありがたいです。

4

1 に答える 1

0

これはMPIの問題ではなく、メモリ内のアレイの割り当て方法の問題です。

2次元以上の配列の割り当てに関しては、基本的に2つの「考え方」があります。MPIも従う古い学校では、フラット配列を使用しています。行はメモリ内に次々に配置されます。これは、コンパイラが明示的に整形された配列をメモリにレイアウトする方法です。たとえばdouble x[4][4]、次のレイアウトになります。

x[0][0] x[0][1] x[0][2] x[0][3] x[1][0] x[1][1] ... x[3][2] x[3][3]

x[i][k]このようなレイアウトでは、との間の距離(要素数)x[i+1][k]は、行の要素数に正確に等しくなります。つまり4、この場合です。1ブロック長がで、ストライドが、の派生ベクトルデータ型をMPIで4作成する場合、データの送受信に使用すると、同じ列にある要素が使用されます。

このモデルの欠点は、メモリを動的に割り当てる場合x[4*i+k]、単純ではなくのようなものを使用して、配列内のオフセットを明示的に計算する必要があることですx[i][k]

2番目の考え方では、各行へのポインターの配列を使用してから、各行を個別に割り当てます。このメカニズムは、「ジャグ」配列を構築でき、x[i][k]構文を使用できるので便利ですが、連続する行がメモリ内で隣接することを保証するものではありませんx[i]。つまり、要素x[i+1]よりも4離れている場所を指す場合があります。 。

あなたがすべきことは、フラット配列を使用するようにロジックを切り替えるか、ハイブリッドモデルを使用することができます-フラット配列を割り当ててmalloc()から、行インデックスを作成します:

double** x;
double** x0;

x = malloc(size_tot_y*sizeof(double*));
x0 = malloc(size_tot_y*sizeof(double*));

for(j=0;j<=size_tot_y-1;j++) {
  x[j] = malloc(size_tot_x*sizeof(double));
  x0[j] = malloc(size_tot_x*sizeof(double));
}

...

for(i=0;i<=size_tot_y-1;i++)
{
  free(x[i]);
  free(x0[i]);
}     

free(x);
free(x0);

になる必要があります

double* x_vals;
double** x;
double* x0_vals;
double** x0;

x_vals = malloc(size_tot_x*size_tot_y*sizeof(double));
x0_vals = malloc(size_tot_x*size_tot_y*sizeof(double));

x = malloc(size_tot_y*sizeof(double*));
x0 = malloc(size_tot_y*sizeof(double*));

for(j=0;j<=size_tot_y-1;j++) {
  x[j] = &x_vals[j*size_tot_x];
  x0[j] = &x0_vals[j*size_tot_x];
}

...

free(x);
free(x_vals);
free(x0);
free(x0_vals);

あなたのコードと私が提案するものの違いがはっきりと見えることを願っています。

于 2012-08-20T08:32:43.420 に答える