【问题标题】:How to use MPI_Type_create_subarray?如何使用 MPI_Type_create_subarray?
【发布时间】:2012-10-31 23:04:18
【问题描述】:

很明显,它的论点是:

int MPI_Type_create_subarray(
  int ndims,
  int array_of_sizes[],
  int array_of_subsizes[],
  int array_of_starts[],
  int order,
  MPI_Datatype oldtype,
  MPI_Datatype *newtype
);

但是,我无法理解此方法如何接收我们要拆分的原始数组以及它返回新子数组的位置(因为此方法应返回一个整数)。换句话说,我只是想看看这个方法在 C++ 中的简单实现,我在网上找不到。

【问题讨论】:

    标签: c++ mpi sub-array


    【解决方案1】:

    MPI_Type_create_subarray() 既不接受原始数组也不返回子数组;它创建一个 MPI 类型,描述给定子数组的内存布局: 某个给定类型的更大数组;一组子尺寸;和一个开始的“角落”。

    然后,您可以使用这个新创建的 MPI 类型从任何适当大小的数组中提取您想要的数据,并将其以消息的形式发送给另一个任务(使用点对点消息传递例程),所有其他任务(通过集体),或将其写入磁盘(使用 MPI-IO)。在以下示例中,rank 0 使用 MPI 子数组类型从更大的整数数组中提取子数组并将其发送到 rank 1。Rank 1 只是将其接收到连续缓冲区中,不需要将其作为任何特殊接收类型;它只是接收这么多整数的数据。

    #include <stdio.h>
    #include <stdlib.h>
    #include <mpi.h>
    
    void printarr(int **data, int n, char *str);
    int **allocarray(int n);
    
    int main(int argc, char **argv) {
    
        /* array sizes */
        const int bigsize =10;
        const int subsize =5;
    
        /* communications parameters */
        const int sender  =0;
        const int receiver=1;
        const int ourtag  =2;
    
        int rank, size;
    
        MPI_Init(&argc, &argv);
        MPI_Comm_rank(MPI_COMM_WORLD, &rank);
        MPI_Comm_size(MPI_COMM_WORLD, &size);
    
        if (size < receiver+1) {
            if (rank == 0)
                fprintf(stderr,"%s: Needs at least %d  processors.\n", argv[0], receiver+1);
            MPI_Finalize();
            return 1;
        }
    
        if (rank == sender) {
            int **bigarray = allocarray(bigsize);
            for (int i=0; i<bigsize; i++)
                for (int j=0; j<bigsize; j++)
                    bigarray[i][j] = i*bigsize+j;
    
    
            printarr(bigarray, bigsize, " Sender: Big array ");
    
            MPI_Datatype mysubarray;
    
            int starts[2] = {5,3};
            int subsizes[2]  = {subsize,subsize};
            int bigsizes[2]  = {bigsize, bigsize};
            MPI_Type_create_subarray(2, bigsizes, subsizes, starts,
                                     MPI_ORDER_C, MPI_INT, &mysubarray);
            MPI_Type_commit(&mysubarray);
    
            MPI_Send(&(bigarray[0][0]), 1, mysubarray, receiver, ourtag, MPI_COMM_WORLD);
            MPI_Type_free(&mysubarray);
    
            free(bigarray[0]);
            free(bigarray);
    
        } else if (rank == receiver) {
    
            int **subarray = allocarray(subsize);
    
            for (int i=0; i<subsize; i++)
                for (int j=0; j<subsize; j++)
                    subarray[i][j] = 0;
    
            MPI_Recv(&(subarray[0][0]), subsize*subsize, MPI_INT, sender, ourtag, MPI_COMM_WORLD, MPI_STATUS_IGNORE);
    
            printarr(subarray, subsize, " Receiver: Subarray -- after receive");
    
            free(subarray[0]);
            free(subarray);
        }
    
        MPI_Finalize();
        return 0;
    }
    
    void printarr(int **data, int n, char *str) {    
        printf("-- %s --\n", str);
        for (int i=0; i<n; i++) {
            for (int j=0; j<n; j++) {
                printf("%3d ", data[i][j]);
            }
            printf("\n");
        }
    }
    
    int **allocarray(int n) {
        int *data = malloc(n*n*sizeof(int));
        int **arr = malloc(n*sizeof(int *));
        for (int i=0; i<n; i++)
            arr[i] = &(data[i*n]);
    
        return arr;
    }
    

    运行它会给出

    $ mpicc -o subarray subarray.c  -std=c99 -Wall -g
    $ mpirun -np 2 ./subarray
        --  Sender: Big array  --
      0   1   2   3   4   5   6   7   8   9 
     10  11  12  13  14  15  16  17  18  19 
     20  21  22  23  24  25  26  27  28  29 
     30  31  32  33  34  35  36  37  38  39 
     40  41  42  43  44  45  46  47  48  49 
     50  51  52  53  54  55  56  57  58  59 
     60  61  62  63  64  65  66  67  68  69 
     70  71  72  73  74  75  76  77  78  79 
     80  81  82  83  84  85  86  87  88  89 
     90  91  92  93  94  95  96  97  98  99 
    --  Receiver: Subarray -- after receive --
     53  54  55  56  57 
     63  64  65  66  67 
     73  74  75  76  77 
     83  84  85  86  87 
     93  94  95  96  97
    

    【讨论】:

    • +1 是一个很好的例子。使用MPI_Sendrecv 并保存一些代码。
    • 我发现新用户在向自己发送 sendrecv() 时会感到困惑,但也许在这里引入非阻塞通信并没有更好。最清楚的可能是只是发送到另一个级别。我暂时保留它,但如果它引起问题,我会做其他事情。
    • 啊,开枪,刚刚注意到我没有 MPI_Type_free。只要我无论如何都要改变它......
    • @JonathanDursi 非常感谢您的出色回答!对不起,如果我不能早点回复。
    • @RestlessC0bra 是的。在标准中,类型一致意味着数据的数量和底层类型(例如,MPI_INT)必须​​相同,但布局可以不同。
    猜你喜欢
    • 1970-01-01
    • 2013-10-29
    • 2011-07-31
    • 2011-07-31
    • 2011-07-18
    • 2011-08-03
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多