如何获得区块循环分布?

问题描述 投票:0回答:1

我正在尝试以块循环方式分布我的矩阵。我从这个问题中学到了很多东西(MPI IO读写块循环矩阵),但这不是我真正需要的。

让我解释一下我的问题。

假设我有一个尺寸为 12 x 12 的矩阵,我想将其分布在尺寸为 2 x 3 的处理器网格上,以便第一个处理器获得粗体元素:

A =

     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 100 101 102 103 104 105 106 107 108
   109 110 111 112 113 114 115 116 117 118 119 120
   121 122 123 124 125 126 127 128 129 130 131 132
   133 134 135 136 137 138 139 140 141 142 143 144

所以,基本上,我想将矩阵划分为尺寸为 2 x 2 的块,然后以这种方式将这些块分配给处理器(编号从 1 到 6):

1 2 3 1 2 3
4 5 6 4 5 6
1 2 3 1 2 3
4 5 6 4 5 6

我尝试实现上述链接问题中的目标,但问题是我的第一个处理器的本地数组是按列形成的,即它看起来像这样

1, 13, 49, 61, 97, 109, 2, 14, 50, 62, 98, 110, 7, 19, 55, 67, 103, 115, 8, 20, 56, 68, 104, 116

这是我的 C 代码:

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

#define     N           12
#define     P           2
#define     Q           3

int main(int argc, char **argv) {
    int rank;
    int size;

    double *A;
    int A_size;
    
    MPI_Datatype filetype;
    MPI_File fin;

    MPI_Status status;

    MPI_Init(&argc, &argv);

    MPI_Comm_rank(MPI_COMM_WORLD, &rank);
    MPI_Comm_size(MPI_COMM_WORLD, &size);

    /**
     * Reading from file.
     */
    int gsizes[2], distribs[2], dargs[2], psizes[2];

    gsizes[0] = N; /* no. of rows in global array */
    gsizes[1] = N; /* no. of columns in global array*/

    distribs[0] = MPI_DISTRIBUTE_CYCLIC;
    distribs[1] = MPI_DISTRIBUTE_CYCLIC;

    dargs[0] = 2; // no of rows in block
    dargs[1] = 2; // no of cols in block

    psizes[0] = P; /* no. of processes in vertical dimension
     of process grid */
    psizes[1] = Q; /* no. of processes in horizontal dimension
     of process grid */

    MPI_Type_create_darray(P * Q, rank, 2, gsizes, distribs, dargs, psizes,
            MPI_ORDER_FORTRAN, MPI_DOUBLE, &filetype);
    MPI_Type_commit(&filetype);

    MPI_File_open(MPI_COMM_WORLD, "A.txt",
            MPI_MODE_RDONLY,
            MPI_INFO_NULL, &fin);

    MPI_File_set_view(fin, 0, MPI_DOUBLE, filetype, "native",
            MPI_INFO_NULL);

    A_size = (N * N) / (P * Q);
    A = (double*) malloc(A_size * sizeof(double));
    MPI_File_read_all(fin, A, A_size,
            MPI_DOUBLE, &status);

    MPI_File_close(&fin);

    printf("\n======\ni = %d\n", rank);
    printf("A : ");
    for (int i = 0; i &lt A_size; i++) {
        printf("%lg ", A[i]);
    }

    MPI_Finalize();
    return 0;
}

我真正想要的是那些 2 x 2 块是连续写入的,即第一个处理器的本地数组如下所示;

1, 13, 2, 14, 49, 61, 50, 62, 97, 109, 98, 110, ... 

我假设我需要定义另一个 MPI_Datatype (如向量或子数组),但我只是不知道如何实现这一点。

编辑

我想我已经部分解决了我的问题。基本上,每个处理器最终都会得到 FORTRAN 顺序的 4 x 6 矩阵,然后使用 MPI_Create_subarray(...) 我可以轻松提取 2 x 2 块。

但我希望每个处理器将其块行发送到同一列中的每个处理器,反之亦然。处理器在网格中编号

1 2 3
4 5 6

因此,例如,在第一步中,处理器 1 应该发送其块行

1 2 7 8
13 14 19 20

至处理器 4;及其块列

1 2
13 14
49 50
61 62
97 98
109110

至处理器 2 和 3。

我创建了笛卡尔通信器,并使用 MPI_Cart_sub() 创建了行式和列式通信器。

我想我应该使用MPI_Bcast(),但是我不知道如何将MPI_Bcast()与MPI_Type_create_subarray()结合起来。我应该首先将提取的子数组复制到某个 local_array,然后 Bcast(local_array)。然而,MPI_Type_create_subarray() 只给我子数组的“视图”,而不是实际上它,所以我想出的最好的解决方案是 Isend-Irecv root->root。

有更优雅的解决方案吗?

c matrix io block mpi
1个回答
0
投票

当您使用

MPI_Type_create_darray(..., MPI_ORDER_FORTRAN, ...)
时,MPI 会读取 Fortran 顺序矩阵。如果用 C 打印本地数组,它看起来可以是“列优先” 或者与您在典型的 C 行优先数组中所期望的相比是混乱的。

如果您确实希望本地块在本地内存中按行优先顺序排列,只需告诉 MPI 您想要 C 订购。

MPI_ORDER_C
中使用
MPI_Type_create_darray(...)
来获取行优先的局部数组。

例如:

MPI_Type_create_darray(
P*Q, // total number of processes
rank, // this rank
2, // dimension = 2D
gsizes, // global sizes [N, N]
distribs, // [MPI_DISTRIBUTE_CYCLIC, MPI_DISTRIBUTE_CYCLIC]
dargs, // [2, 2] block sizes
psizes, // [P, Q]
MPI_ORDER_C, // <<-- use C ordering
MPI_DOUBLE,
&filetype
);

这通常会产生一个与典型的“C 风格”行优先更一致的局部数组 块。

最新问题
© www.soinside.com 2019 - 2025. All rights reserved.