2

我试图将一个 1-dim n*n 数组分散到 p 个处理器,然后使用收集来获取数据。但问题是它在我运行程序时显示垃圾输出。我正在使用一个 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

让我感到奇怪的一件事是 scatter_data 函数原型放置在另一个函数的主体中。这是很不寻常的。

其次,查看完整代码可能会有所帮助。编译完整的代码将有助于我们进行一些家庭调试,因为 MPI 代码通常很难在屏幕上调试。

编辑 ::

我确实稍微清理了您的代码并添加了一些注释和检查。scatterv 和 gatherv 似乎都工作得很好——我添加了另一个数组 (C),用于存储收集的数据,而不是原始 A 数组,它在两个 MPI 调用之前之后包含相同的数据。我还修改了用于分散数据的本地临时数组的大小。

可能让您感到困惑的一件事是用于分散数据的接收缓冲区的大小。当我增加接收到的数据时,原始代码使用了太多空间并给了我段错误。例如,对于 4x4 A 矩阵,原始接收缓冲区大小为 8x4,但假设有两个进程,则应为 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()动态分配变量的好习惯。

于 2013-02-26T05:51:36.847 回答