【问题标题】:MPI Sending array of arrayMPI 发送数组数组
【发布时间】:2012-03-19 11:05:42
【问题描述】:

好的,所以我正在尝试通过 MPI 发送这样的结构

struct BColumns {
        double **B;
        int offset;
};

如果我只是像这样对数据进行一些 BS 分配

    bSet.offset = myRank;
    bSet.B = (double **) calloc(2, sizeof(double *));
    bSet.B[0] = (double *) calloc(1, sizeof(double));
    bSet.B[1] = (double *) calloc(1, sizeof(double));

    bSet.B[0][0] = 1;
    bSet.B[1][0] = 2;


    if(myRank == 0){
            MPI_Send(&bSet,sizeof(struct BColumns), MPI_BYTE, 1, 1, MPI_COMM_WORLD);
    }else{
            MPI_Recv(&recvBuf, sizeof(struct BColumns), MPI_BYTE, MPI_ANY_SOURCE, MPI_ANY_TAG, MPI_COMM_WORLD, &status );
    }

我假设它不能正常工作,因为如果我按原样发送这个结构,它只会发送 B 中的指针,而该指针不指向另一个处理器上的任何东西,那么我将如何处理在 MPI 中发送这样的数据。

【问题讨论】:

    标签: c mpi mpich


    【解决方案1】:

    正如 suszterpatt 指出的那样,您真的想将 B 块分配为一大块;无论如何,这可能对性能更好,但它确实是任何通信所必需的,因此您不会到处追逐指针。而且我认为您可能必须以一种或另一种方式在不同的发送中执行此操作-发送大小信息,然后是一个块中的数据-尽管您可能可以为其中的每一个创建和删除不同的 MPI_Type_struct发送。但是每个对象使用多个发送并不是很困难:

    #include <stdio.h>
    #include <stdlib.h>
    #include <mpi.h>
    
    typedef struct BColumns {
            double **B;
            int offset;
    } bc;
    
    double **alloc2d(int n, int m) {
        double *data = malloc(n*m*sizeof(double));
        double **array = malloc(n*sizeof(double *));
        for (int i=0; i<n; i++) {
            array[i] = &(data[i*m]);
        }
        return array;
    }
    
    void free2d(double **array) {
        free(array[0]);
        free(array);
    }
    
    int main(int argc, char **argv) {
    
        const int tag = 13;
        int size, rank;
    
        MPI_Init(&argc, &argv);
        MPI_Comm_size(MPI_COMM_WORLD, &size);
    
        if (size < 2) {
            fprintf(stderr,"Requires at least two processes.\n");
            exit(-1);
        }
    
        MPI_Comm_rank(MPI_COMM_WORLD, &rank);
        if (rank == 0) {
            int ncols=3, colsize=5;
            bc *send;
    
            send = malloc(sizeof(bc));
            send->offset = 1;
            send->B = alloc2d(ncols, colsize);
            for (int i=0; i<ncols; i++)
                for (int j=0; j<colsize; j++)
                    send->B[i][j] = i*j;
    
            const int dest = 1;
            MPI_Send(&ncols,   1, MPI_INT, dest, tag, MPI_COMM_WORLD);
            MPI_Send(&colsize, 1, MPI_INT, dest, tag, MPI_COMM_WORLD);
            MPI_Send(&(send->offset), 1, MPI_INT, dest, tag, MPI_COMM_WORLD);
            MPI_Send(&(send->B[0][0]), ncols*colsize, MPI_DOUBLE, dest, tag,
                     MPI_COMM_WORLD);
    
    
            printf("Rank %d: sent structure B\n", rank);
            free2d(send->B);
            free(send);
        }
    
        if (rank == 1) {
            MPI_Status status;
            const int src=0;
            int rncols, rcolsize;
            bc *recv;
    
            MPI_Recv(&rncols,   1, MPI_INT, src, tag, MPI_COMM_WORLD, &status);
            MPI_Recv(&rcolsize, 1, MPI_INT, src, tag, MPI_COMM_WORLD, &status);
            printf("Rank %d: Received: rncols = %d rcolsize=%d\n", rank, rncols, rcolsize);
    
            recv = malloc(sizeof(bc));
            recv->B = alloc2d(rncols, rcolsize);
    
            MPI_Recv(&(recv->offset), 1, MPI_INT, src, tag, MPI_COMM_WORLD, &status);
            MPI_Recv(&(recv->B[0][0]), rncols*rcolsize, MPI_DOUBLE, src, tag,
                    MPI_COMM_WORLD, &status);
    
            printf("Rank %d: Received: offset = %d\n", rank, recv->offset);
            for (int i=0; i<rncols; i++) {
                printf("%d:  Column %d/%d: ", rank, i, rncols);
                for (int j=0; j<rcolsize; j++)
                    printf(" %lf ", recv->B[i][j]);
                printf("\n");
            }
    
            free2d(recv->B);
            free(recv);
        }
    
        MPI_Finalize();
    
        return 0;
    }
    

    然后运行它:

    $ mpirun -np 3 ./bstruct
    Rank 0: sent structure B
    Rank 1: Received: rncols = 3 rcolsize=5
    Rank 1: Received: offset = 1
    1:  Column 0/3:  0.000000  0.000000  0.000000  0.000000  0.000000 
    1:  Column 1/3:  0.000000  1.000000  2.000000  3.000000  4.000000 
    1:  Column 2/3:  0.000000  2.000000  4.000000  6.000000  8.000000 
    

    如果您想通过手动或使用 MPI 函数调用或数据类型来避免多次发送的延迟(并且如果您事先知道 B 数组的最大大小),您可以将这些数据编组到一条消息中,但是您仍然必须以类似的方式进行。

    【讨论】:

      【解决方案2】:

      最简单的方法是使用单个数组以行/列优先顺序存储您的值,以便它们在内存中都是连续的。然后你只需要定义一个 MPI 数据类型来描述结构的内存布局(很多双精度和一个 int)。

      【讨论】:

      • 那么现在如果我没有设置这个数组的大小,所以我仍然需要结构中的指针并且我动态分配数组,即使我将它放在行/列中主要我仍然会传递一个对其他进程没有任何意义的指针。
      • 因此,您不会发送结构本身。相反,发送接收进程可以重建相同结构的数据:双精度数组和 int。原理是一样的,尽管你必须巧妙地使用MPI_Address 函数,并确保内存中双精度和 int 的相对位置不会改变,或者你在之后重新定义数据类型它已经改变了。或者只是传递多条消息。
      猜你喜欢
      • 2013-03-07
      • 1970-01-01
      • 2015-06-06
      • 1970-01-01
      • 2019-08-12
      • 2013-11-13
      • 2021-06-11
      • 2018-11-11
      • 2013-12-12
      相关资源
      最近更新 更多