2

1-dim n*n 配列を p 個のプロセッサに分散させようとした後、gather を使用してデータを取得しようとしましたが、問題は、プログラムを実行するとガベージ出力が表示されることです。私は n*n の配列 A とサイズ n の配列 b を使用しています。

// num_rows is the number of rows each process will be receiving,base is the base index and last is the last index .
// curr_index_proce is the index of the processor which contains the index i of Array A. 

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

#define NUM_EQN 10

#define NUM_ROWS(i,n,p)  ((((i)+1)*(n)/(p)) - ((i)*(n)/(p)))
#define BASE(i,n,p)     (((i)*(n)/(p)))
#define LAST(i,n,p) ((((i)+1)*(n)/(p)) - 1)
#define CUR_INDEX_PROC(i,n,p) ( ((p) * ( (i) + 1 ) - 1 )/(n))

#define MIN(a,n) ((a) > (b) ? (a) : (b))

void gather(float *A,float *b,int n);
void print_array(float *A,float *b,int n){
        int i,j;
        for ( i = 0 ; i < n;i++){
//              printf("i = %d ",i);
                for(j = 0 ; j < n;j++){
                        printf("%6.2f " ,A[i*n+j]);
                }
                printf("\n");
                //printf(" : %6.2f\n",b[i]);
        }
        printf("\n\n\n");
}



int SIZE_A(int n,int p ){
    if ( n%p == 0 )
            return n*n/p;
    else
            return n*(n/p+1);
}

int SIZE_B(int n,int p){
    if ( n%p == 0 )
            return n/p;
    else
            return n/p + 1;
}
int main(int argc,char **argv){
        MPI_Init(&argc,&argv);
        int size,rank;
        MPI_Comm_rank(  MPI_COMM_WORLD,&rank);
        MPI_Comm_size(MPI_COMM_WORLD,&size);
        double time_start, time_finish;
        float *A = malloc(sizeof(float)*NUM_EQN*NUM_EQN);
        float *b = malloc(sizeof(float)*NUM_EQN);
        float *X;
        int i,j;
        FILE *fp = fopen("A","r");
        if (fp == NULL ){
                printf("Error %s Not Found\n",argv[1]);
                exit(0);
                MPI_Finalize();
        }
        for ( i = 0 ; i < NUM_EQN;i++)
                for(j = 0 ; j < NUM_EQN;j++)
                        fscanf(fp,"%f",&A[i*NUM_EQN+j]);
        FILE *fp2 = fopen("b","r");
        if (fp2 == NULL ){
                printf("Error %s Not Found\n",argv[2]);
                exit(0);
        }
        for ( i = 0 ; i < NUM_EQN;i++)
                fscanf(fp2,"%f",&b[i]);
        time_start = - MPI_Wtime();
        gather(A,b,NUM_EQN);
        time_finish = MPI_Wtime();
        char name[100];
        int length;
        MPI_Finalize();
}

void gather(float *A,float *b,int n){
        int pivot,i,col;
        int row, j;
        int size,rank;
        MPI_Comm_rank(  MPI_COMM_WORLD,&rank);
        MPI_Comm_size(MPI_COMM_WORLD,&size);
        float global_max;
        float *A_recv,*b_recv;
        A_recv = malloc(sizeof(float)*(SIZE_A(n,size)));
        b_recv = malloc(sizeof(float)*(SIZE_B(n,size)));
    printf("%d %d \n",SIZE_A(n,size),SIZE_B(n,size));
    if ( rank == 0 ){
            print_array(A,b,n);
    }
                int send_count[size];
                int disp[size];
                int send_count_b[size];
                int disp_b[size];
                for ( i = 0 ; i < size ; i++ ){
                                send_count[i] = 0 ;
                                send_count_b[i] = 0;
                }
                for ( i = 0 ; i < size ; i++ ){
                                send_count[i] = n*NUM_ROWS(i,n,size);
                                if ( i == 0 )
                                        disp[i] = 0;
                                else
                                        disp[i] = disp[i-1] + send_count[i-1];
                                send_count_b[i] = NUM_ROWS(i,n,size);
                                if ( i == 0 )
                                        disp_b[i] = 0 ;
                                else
                                        disp_b[i] = disp_b[i-1] + send_count_b[i-1];
                }
                MPI_Scatterv(A, send_count, disp,MPI_FLOAT, A_recv,SIZE_A(n,size),MPI_FLOAT,0, MPI_COMM_WORLD);
                MPI_Scatterv(b, send_count_b, disp_b,MPI_FLOAT, b_recv,send_count_b[rank], MPI_FLOAT, 0, MPI_COMM_WORLD);
                for ( i = 0 ; i < send_count[rank]; i++ ){
                        for ( j = 0 ; j < n ; j++)
                                printf("%3.2f : ",A_recv[i*n+j]);
                        printf("\n\n");
                }
                MPI_Gatherv(A_recv,SIZE_A(n,size),MPI_FLOAT,A,send_count,disp,MPI_FLOAT,0,MPI_COMM_WORLD);
                MPI_Gatherv(b_recv,send_count_b[rank],MPI_FLOAT,b,send_count_b,disp_b,MPI_FLOAT,0,MPI_COMM_WORLD);
}

私を助けてください。

4

1 に答える 1

2

私が奇妙に感じる点の 1 つは、別の関数の本体に配置された scatter_data 関数プロトタイプです。それは非常に珍しいことです。

第二に、完全なコードを表示すると役立つ場合があります。MPI コードは通常、画面上でデバッグするのがかなり難しいため、完全なコードをコンパイルすることで、ホーム デバッグを行うのに役立ちます。

編集 ::

コードを少しきれいにして、いくつかのコメントとチェックを追加しました。scatterv と gatherv の両方が問題なく動作しているようです - 2 つの MPI 呼び出しの前後に同じデータを含む元の A 配列とは対照的に、収集したデータを格納するために使用される別の配列 (C) を追加しました。また、分散データに使用されるローカル一時配列のサイズも変更しました。

混乱を招く可能性があることの 1 つは、分散データに使用される受信バッファーのサイズです。元のコードではスペースが多すぎて、受信データをインクリメントするとセグ フォールトが発生しました。たとえば、4x4 A マトリックスの場合、元の受信バッファー サイズは 8x4 でしたが、2 つのプロセスを想定すると 2x4 である必要があります。関数SIZE_B(n,size)は実際に正しい数値を返します。

#define NUM_EQN 4

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

    float *A = malloc(sizeof(float)*NUM_EQN*NUM_EQN);
    float *b = malloc(sizeof(float)*NUM_EQN);

    int i;
    for (i = 0; i < NUM_EQN * NUM_EQN; i++) A[i] = (float)i;
    for (i = 0; i < NUM_EQN; i++) b[i] = (float)i;

    gather(A,b,NUM_EQN);

    MPI_Finalize();
    printf("End of process %d\n",rank);
}

void gather(float *A,float *b,int n){

    int i, j;
    int size,rank;
    MPI_Comm_rank(  MPI_COMM_WORLD,&rank);
    MPI_Comm_size(MPI_COMM_WORLD,&size);
    float *A_recv,*b_recv;
    A_recv = malloc(sizeof(float)*(SIZE_A(n,size)));
    b_recv = malloc(sizeof(float)*(SIZE_B(n,size)));    // size A and B are probably the array parts located in current thread
    float *C = malloc(sizeof(float)*NUM_EQN*NUM_EQN);

    printf("n: %d %d %d \n",n,SIZE_A(n,size),SIZE_B(n,size));

    if ( rank == 0 )
    {
        print_array(A,b,n);
    }
    int send_count[size];
    int disp[size];
    int send_count_b[size];
    int disp_b[size];
    for ( i = 0 ; i < size ; i++ )
    {
        send_count[i] = 0 ;
        send_count_b[i] = 0;
    }
    for ( i = 0 ; i < size ; i++ )
    {
        send_count[i] = n*NUM_ROWS(i,n,size);
        if ( i == 0 )
                disp[i] = 0;
        else
                disp[i] = disp[i-1] + send_count[i-1];
        send_count_b[i] = NUM_ROWS(i,n,size);
        if ( i == 0 )
                disp_b[i] = 0 ;
        else
                disp_b[i] = disp_b[i-1] + send_count_b[i-1];

        printf("%d Displacement[%d] : %d Sendcount : %d \n", rank, i, disp[i], send_count[i]);
    }


    MPI_Scatterv(A, send_count, disp ,MPI_FLOAT, A_recv,SIZE_A(n,size),MPI_FLOAT,0, MPI_COMM_WORLD);
    /*
    int MPI_Scatterv( void *sendbuf, int *sendcnts, int *displs,
                 MPI_Datatype sendtype, void *recvbuf, int recvcnt,
                 MPI_Datatype recvtype,
                 int root, MPI_Comm comm)*/

    //MPI_Scatterv(b, send_count_b, disp_b,MPI_FLOAT, b_recv,send_count_b[rank], MPI_FLOAT, 0, MPI_COMM_WORLD);

    printf("%d Receive data : \n",rank);
    for ( i = 0 ; i < SIZE_B(n,size); i++ )
    {
        for ( j = 0 ; j < n ; j++)
        {
            A_recv[i*n+j] = A_recv[i*n+j] + 10.0;
            printf("%d %3.2f : ",rank, A_recv[i*n+j]);

        }

        printf("\n");
    }

    if (rank == 0)
    {
        printf("%d Gather data : \n",rank);
        for ( i = 0 ; i < n; i++ )
        {
            for ( j = 0 ; j < n ; j++)
                printf("%d %3.2f : ",rank, C[i*n+j]);
            printf("\n");
        }
    }

    MPI_Gatherv(A_recv,SIZE_A(n,size),MPI_FLOAT,C,send_count,disp,MPI_FLOAT,0,MPI_COMM_WORLD);

    if (rank == 0)
    {
        printf("%d Gather data : \n",rank);
        for ( i = 0 ; i < n; i++ )
        {
            printf("%d", rank);
            for ( j = 0 ; j < n ; j++)
                printf(" %3.2f : ",C[i*n+j]);
            printf("\n");
        }
    }
    //MPI_Gatherv(b_recv,send_count_b[rank],MPI_FLOAT,b,send_count_b,disp_b,MPI_FLOAT,0,MPI_COMM_WORLD);
}

ご覧のとおり、配列 b はほとんど同じコードを使用しているため、削除しました。

マトリックス C は MPI_gather 呼び出し ( -np 2 の場合) の前後に表示され、元の分散データが正常に収集されたように見えます。新しく変更されたデータが適切に収集されていることを確認するために、分散された各数値に 10 を追加するだけです。

-np = 2 および -np = 4 の場合も同様です。

0 Gather data BEFORE MPI CALL: 
0 -0.00 : 0 -0.00 : 0 0.00 : 0 0.00 : 
0 0.00 : 0 0.00 : 0 0.00 : 0 0.00 : 
0 0.00 : 0 0.00 : 0 0.00 : 0 0.00 : 
0 0.00 : 0 0.00 : 0 0.00 : 0 0.00 : 
0 Gather data AFTER MPI CALL: 
0 10.00 :  11.00 :  12.00 :  13.00 : 
0 14.00 :  15.00 :  16.00 :  17.00 : 
0 18.00 :  19.00 :  20.00 :  21.00 : 
0 22.00 :  23.00 :  24.00 :  25.00 : 

また、ここにある MPI_Scatterv の良い例を見つけました: https://gist.github.com/ehamberg/1263868

別の良い例がここにあります: https://rqchp.ca/modules/cms/checkFileAccess.php?file=local.rqchpweb_udes/mpi/exemples_c/ex07_Scatter_EN.c

free()そして、もう 1 つの提案::動的に割り当てられた変数に対する良い習慣です。

于 2013-02-26T05:51:36.847 に答える