使用 MPI 对未按预期工作的矩阵进行逐列分解

Column-wise decomposition of a matrix not working as intended using MPI

提问人:Amato.g 提问时间:11/14/2023 最后编辑:Amato.g 更新时间:11/14/2023 访问量:76

问:

我有一个 NxM 矩阵,N=7 和 M=8,如下所示:

[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]

它被编码到大小为 NxM 的一维数组中。

我想在 3 个进程之间执行按列分布,以便

进程 0 将具有:

[ 0,  1,  2,
  8,  9, 10,
 16, 17, 18,
 24, 25, 26,
 32, 33, 34,
 40, 41, 42,
 48, 49, 50]

进程 1 将具有:

[ 3,  4,  5,
 11, 12, 13,
 19, 20, 21,
 27, 28, 29,
 35, 36, 37,
 43, 44, 45,
 51, 52, 53]

进程 2 将具有:

[ 6,  7,
 14, 15,
 22, 23,
 30, 31,
 38, 39,
 46, 47,
 54, 55]

每个进程都以这种方式计算其局部 N 和 M 以及局部向量的长度:

int nloc = N;
int mloc = rank < M%nproc ? (M/nproc)+1 : M/nproc;
int *recv_vec = (int *)malloc(nloc*mloc*sizeof(int));

请注意,这是进程在它所属的通信器中的等级。(我有 3 个进程,所以分别是 0、1、2)。rank

为了执行我使用的分发,因为我必须向每个进程发送不同数量的列。 为了做到这一点,我创建了一个新的数据类型,以便可以将数字放在正确的位置并将其发送到正确的进程。MPI_ScattervMPI_Scatterv

MPI_Datatype col, col_type;
MPI_Type_vector(nloc, 1, M, MPI_INT, &col);
MPI_Type_commit(&col);
//I resized the newly created vector so that MPI_Scatterv knows the right offset for the subsequent elements
MPI_Type_create_resized(col, 0, sizeof(int), &col_type);
MPI_Type_commit(&col_type);

此时,可以完成数据的分发:

int sendcounts[]={3,3,2};
int displs[]={0,3,6};
MPI_Scatterv(matrix, sendcounts, displs, col_type, recv_vec, nloc*mloc, MPI_INT, 0, MPI_COMM_WORLD);

但实际情况是,由于我们发送了专栏

进程 0 接收此矩阵(显然在一维向量中)

[ 0,  8, 16, 24, 32, 40, 48,
  1,  9, 17, 25, 33, 41, 49,
  2, 10, 18, 26, 34, 42, 50]

等等其他过程。

所以我也创建了一个接收类型。MPI_Scatterv

MPI_Datatype recv_row, recv_row_type;
MPI_Type_vector(mloc,1,nloc,MPI_INT, &recv_row);
MPI_Type_commit(&recv_row);
MPI_Type_create_resized(recv_row, 0, sizeof(int), &recv_row_type);
MPI_Type_commit(&recv_row_type);

并以这种方式调用:MPI_Scatterv

MPI_Scatterv(matrix, sendcounts, displs, col_type, recv_vec, nloc, recv_row_type, 0, MPI_COMM_WORLD);

我期望收到的是我最初所说的,但收到的流程是这样的:

Process 0: 0 24 48 17 41 10 34 8 32 1 25 49 18 42 16 40 9 33 2 26 50
Process 1: 3 27 51 20 44 13 37 11 35 4 28 52 21 45 19 43 12 36 5 29 53
Process 2: 6 22 38 54 15 31 47 14 30 46 7 23 39 55

,有问题,但我不知道是什么。有人可以帮助我吗?recv_row_type

这是完整的代码:

#define N 7
#define M 8

int main(int argc, char *argv[]){
    int matrix[N*M];
    int menum, nproc, i, j;
    
    MPI_Init(&argc, &argv);
    
    MPI_Comm_rank(MPI_COMM_WORLD, &menum);
    MPI_Comm_size(MPI_COMM_WORLD, &nproc);
    
    //Matrix initialization
    if (menum == 0) {
        for (i = 0; i < N; i++) {
            for (j = 0; j < M; j++) {
                matrix[(i*M)+j] = i * M + j;
            }
        }
    }
    
    //Every process has its vector of size nloc*mloc
    int nloc = N;
    int mloc = menum < M%nproc ? (M/nproc)+1 : M/nproc;
    int *recv_vec = (int *)malloc(nloc*mloc*sizeof(int));
    
    //Create a custom datatype for a vector of nloc integers
    MPI_Datatype col, col_type, recv_row, recv_row_type;
    
    MPI_Type_vector(nloc, 1, M, MPI_INT, &col);
    MPI_Type_commit(&col);
    MPI_Type_create_resized(col, 0, sizeof(int), &col_type);
    MPI_Type_commit(&col_type);
    
    MPI_Type_vector(mloc,1,nloc,MPI_INT, &recv_row);
    MPI_Type_commit(&recv_row);
    MPI_Type_create_resized(recv_row, 0, sizeof(int), &recv_row_type);
    MPI_Type_commit(&recv_row_type);
    
    
    
    //Distributing data to other processes
    int sendcounts[]={3,3,2};
    int displs[]={0,3,6};
    MPI_Scatterv(matrix, sendcounts, displs, col_type, recv_vec, nloc, recv_row_type, 0, MPI_COMM_WORLD);
    
    
    //Printing data received by the process
    printf("Il processo %d: ",menum);
    for(i=0; i<nloc*mloc; i++){
        printf("%d ",recv_vec[i]);
    }
    printf("\n");
    
    //Freeing up memory and terminate MPI environment
    free(recv_vec);
    MPI_Type_free(&col);
    MPI_Type_free(&col_type);
    MPI_Type_free(&recv_row);
    MPI_Type_free(&recv_row_type);
    MPI_Finalize();

    return 0;
}
C 并行处理 MPI

评论

0赞 Gilles Gouaillardet 11/14/2023
请编辑您的问题并附加完整的代码。请注意,在调整类型大小之前,您不需要提交类型,因为它永远不会在通信中使用。
0赞 Amato.g 11/14/2023
我附加了完整的代码。问题出在我用于MPI_Scatterv
0赞 Gilles Gouaillardet 11/14/2023
创建接收类型时,需要交换和nlocmloc
0赞 Lundin 11/14/2023
一般需要注意的是,C 语言不对数组应用任何数学意义。因此,您可以将其分配为对应于列优先或行优先的更高层矩阵概念的 C 数组。但从效率上讲,数组应该从最低地址到最高地址进行访问。这种格式也适合 MPI、缓存存储器等。因此,请确保以对 C/计算机最有效的方式存储它们,而不一定是数学上最有意义的方式。
1赞 Amato.g 11/15/2023
好的,我想我明白了,谢谢!

答: 暂无答案