gpt4 book ai didi

c - 如何在 MPI 中仅使用一个数组来组合不同宽度的子数组进行发送和接收

转载 作者:行者123 更新时间:2023-12-04 05:56:01 26 4
gpt4 key购买 nike

我在这个问题上遇到了很多麻烦:使用 MPI,我想将分布在多个 MPI 进程中的二维数组的几个连续、不重叠的柱状 block 组合成一个驻留在根进程中的数组。主要条件是所有发送和接收进程的数组必须相同。第二个条件是每个进程发送的柱状 block 可以有不同的宽度。这似乎是并行编程中的一个常见问题,因为我在 StackOverflow 上看到了至少 6 个与此问题相关的问题。不幸的是,没有一个答案对我有帮助。当我将问题分成行 block 而不是列时,我可以很好地解决这个项目。我意识到这与柱状子阵列的不同步幅有关。我尝试过 MPI vector 和子数组类型,但都无济于事。

使用我的代码的简化版本,如果我在 COLUMNS 等于 6 的情况下执行它,我得到:

    0:  1  1  1  2  2  2      1:  1  1  1  2  2  2      2:  1  1  1  2  2  2      3:  1  1  1  2  2  2      4:  1  1  1  2  2  2      5:  1  1  1  2  2  2      6:  1  1  1  2  2  2  

which is what I want.

On the other hand, if I execute it with COLUMNS = 5, I expect to get:

    0:  1  1  1  2  2    1:  1  1  1  2  2    2:  1  1  1  2  2    3:  1  1  1  2  2    4:  1  1  1  2  2    5:  1  1  1  2  2    6:  1  1  1  2  2

Instead, I get:

    0:  1  1  1  2  2    1:  2  1  1  2  2    2:  2  1  1  2  2    3:  2  1  1  2  2    4:  2  1  1  2  2    5:  1  1  1 -0 -0    6:  1  1  1 -0 -0

Listing of the simplified code:

#include <mpi.h>
#include <stdio.h>
#include <stdlib.h>
#include <assert.h>

#define ROWS 7
#define COLUMNS 6 // 5 or 6 only. I could pass this in the cmd line...
#define NR_OF_PROCESSES 2

void print_matrix (float ** X, int rows, int cols)
{
for (int i = 0; i < rows; ++i) {
printf ("%3d: ", i);
for (int j = 0; j < cols; ++j)
printf ("%2.0f ", X[i][j]);
printf ("\n");
}
}

float **allocate_matrix (int rows, int cols)
{
float *data = (float *) malloc (rows * cols * sizeof(float));
float **matrix = (float **) malloc (rows * sizeof(float *));
for (int i = 0; i < rows; i++)
matrix[i] = & (data[i * cols]);
return matrix;
}

int main (int argc, char *argv[])
{
int num_procs, my_rank, i, j, root = 0, ncols, ndims = 2, strts;
float **matrix;
MPI_Datatype sendsubarray, recvsubarray, resizedrecvsubarray;

assert (COLUMNS == 5 || COLUMNS == 6);

MPI_Init (&argc, &argv);
MPI_Comm_size (MPI_COMM_WORLD, &num_procs);
if (num_procs != NR_OF_PROCESSES) MPI_Abort (MPI_COMM_WORLD, -1);
MPI_Comm_rank (MPI_COMM_WORLD, &my_rank);

ncols = (my_rank == root) ? 3 : COLUMNS - 3;
strts = (my_rank == root) ? 0 : 3;
int sizes[2] = {ROWS, COLUMNS};
int subsizes[2] = {ROWS, ncols};
int starts[2] = {0, strts};

// Create and populate the matrix at each node (incl. the root):
matrix = allocate_matrix (ROWS, COLUMNS);
for (i = 0; i < ROWS; i++)
for (j = 0; j < COLUMNS; j++)
matrix[i][j] = my_rank * -1.0;
for (i = starts[0]; i < starts[0] + subsizes[0]; i++)
for (j = starts[1]; j < starts[1] + subsizes[1]; j++)
matrix[i][j] = my_rank + 1.0;

// Create the subarray type for use by each send node (incl. the root):
MPI_Type_create_subarray (ndims, sizes, subsizes, starts, MPI_ORDER_C,
MPI_FLOAT, &sendsubarray);
MPI_Type_commit (&sendsubarray);

// Create the subarray type for use by the receive node (the root):
if (my_rank == root) {
MPI_Type_create_subarray (ndims, sizes, subsizes, starts, MPI_ORDER_C,
MPI_FLOAT, &recvsubarray);
MPI_Type_commit (&recvsubarray);
MPI_Type_create_resized (recvsubarray, 0, 1 * sizeof(float),
&resizedrecvsubarray);
MPI_Type_commit (&resizedrecvsubarray);
}

// Gather the send matrices into the receive matrix:
int counts[NR_OF_PROCESSES] = {3, COLUMNS - 3};
int displs[NR_OF_PROCESSES] = {0, 3};
MPI_Gatherv (matrix[0], 1, sendsubarray,
matrix[0], counts, displs, resizedrecvsubarray,
root, MPI_COMM_WORLD);

// Have the root send the main array to the output:
if (my_rank == root) print_matrix (matrix, ROWS, COLUMNS);

// Free out all the allocations we created in this node...
if (my_rank == 0) {
MPI_Type_free (&resizedrecvsubarray);
MPI_Type_free (&recvsubarray);
}
MPI_Type_free (&sendsubarray);
free (matrix);

MPI_Finalize();
return 0;
}

我在想,我的小问题可能没有直接的解决方案,如上面的代码所示,因此我将不得不解决一些复杂的多步解决方案,我必须在收集之前以不同的方式处理不同宽度的子数组它们分两到三步进入接收阵列,而不仅仅是一步。

任何帮助都感激不尽!

最佳答案

做得很好!那里有很多关于 MPI 细节的杂耍,只有最后一件事丢失了——我只需要添加两行并更改第三行即可让您的代码正常工作。

即使在损坏的输出中也证明了您大部分都可以正常工作的事实。正在接收正确数量的“2”,因此您正在构建发送类型并正确发送数据。唯一的技巧是在接收中。

从 Gatherv 代码,

int counts[NR_OF_PROCESSES] = {3, COLUMNS - 3};
int displs[NR_OF_PROCESSES] = {0, 3};

您已正确决定以列为单位接收(因此第一列有 3 列要发送,第二列是其余的);考虑到您的调整大小,您的位移是有意义的;您已经以数组元素为单位调整了大小,因此每一列都正确地紧跟在下一列之后。

唯一的障碍是您的接收子数组类型构造;当你打这个电话
    MPI_Type_create_subarray (ndims, sizes, subsizes, starts, MPI_ORDER_C,
MPI_FLOAT, &recvsubarray);

您正在创建一个接收类型,对于接收过程来说,它是它发送的数据的大小、子大小和偏移量!相反,您只想创建一个正好是一列的接收子数组类型,并且以 {0,0} 开头——因此没有(固有)偏移量,因此您只需将其指向需要与您的位移一起去的位置:
    int colsubsizes[]={ROWS, 1};
int colstarts[]={0,0};
MPI_Type_create_subarray (ndims, sizes, colsubsizes, colstarts, MPI_ORDER_C,
MPI_FLOAT, &recvsubarray);

当我用它运行它时,它可以工作。

(作为一个(更多)次要注意事项,您不需要提交或因此免费 recvsubarray ,因为您从不将其用于实际通信;它仅用于构造 resizedrecvsubarray 类型,然后提交.)

关于c - 如何在 MPI 中仅使用一个数组来组合不同宽度的子数组进行发送和接收,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/9507834/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com