使用 MPI,当存在连续数组时,用户定义的数据类型是否无用?
With MPI are user-defined datatypes useless when there is a contiguous array?
在我的程序中,我向其他处理器发送了矩阵的一些行,我正在用 C 进行编码,并且我知道 C 是行优先的。
矩阵分配为一维数组。
matrixInArrayB = malloc(height * width * sizeof(int));
matrixB = malloc(height * sizeof(int*));
for (int y = 0; y < height; y++) {
matrixB[y] = &matrixInArrayB[y * width];
}
我是这样发的
MPI_Isend(&matrixB[0][0], width * height, MPI_INT, dest, tag,
MPI_COMM_WORLD, &requestesForB[k]);
我怀疑我是否必须临时使用某种数据类型来确保行的连续性,例如:
int MPI_Type_contiguous(int count,
MPI_Datatype oldtype,
MPI_Datatype *newtype)
不,如果您不想,则不需要定义自己的数据类型。但是,如果使用得当,它们会非常有用。
假设您使用以下结构来描述您的矩阵,而不是指向数据行的指针数组:
typedef struct {
int rows;
int cols;
ssize_t rowstep;
ssize_t colstep;
int *data;
} matrix;
其中矩阵 m
的行 r
、列 c
的数据元素是 m.data[r*rowstep + c*colstep]
。我概述了这个结构的一个更好的版本 .
然后,您可以使用 MPI_Type_create_hvector()
创建与该特定类型矩阵(特定大小和步长)的行、列或主对角线对应的类型:
int n = (m.rows <= m.cols) ? m.rows : m.cols; /* min(m.rows, m.cols) */
MPI_Type_create_hvector(m.rows, 1, m.rowstep * sizeof m.data[0],
MPI_INT, &row_vector_type);
MPI_Type_create_hvector(m.cols, 1, m.colstep * sizeof m.data[0],
MPI_INT, &col_vector_type);
MPI_Type_create_hvector(n, 1, (m.rowstep + m.colstep) * sizeof m.data[0],
MPI_INT, &diag_vector_type);
要引用行 r
,您可以使用 m.data + r*m.rowstep
。
要引用列 c
,您可以使用 m.data + c*m.colstep
.
要引用主对角线,请使用 m.data
.
大小字段始终为 1,因为您 send/receive 单独的行或列。
也可以定义对应于矩阵的任何连续矩形部分的数据类型。
然后 MPI 库将在发送时收集数据,并在接收时分散数据。实际数据项在内存中不需要连续
在上面的示例中,可以使用相同的代码发送和接收任何行、列或对角向量。使用自定义数据类型,除了如上所示定义类型之外,不需要区分它们。
简化代码往往会产生更健壮的代码,错误更少。 (你可以说 bug 要么是 off-by-one 类型,即难以发现但并不复杂,要么是复杂类型,其中代码的不同方面以意想不到或无意的方式相互作用导致 bug。)
因此,我想说即使数据在连续数组中,用户定义的 MPI 数据类型也不是无用的,因为它们可用于简化代码,从而使其更健壮且易于维护。
显然,并非所有 MPI 代码都能很好地使用用户定义的 MPI 数据类型。尽可能使用用户定义的数据类型绝对不是解决方案。
我的观点是,您要根据具体情况来确定有用性,具体取决于您是否可以使代码更简单、更易于阅读和健壮。
在我的程序中,我向其他处理器发送了矩阵的一些行,我正在用 C 进行编码,并且我知道 C 是行优先的。 矩阵分配为一维数组。
matrixInArrayB = malloc(height * width * sizeof(int));
matrixB = malloc(height * sizeof(int*));
for (int y = 0; y < height; y++) {
matrixB[y] = &matrixInArrayB[y * width];
}
我是这样发的
MPI_Isend(&matrixB[0][0], width * height, MPI_INT, dest, tag,
MPI_COMM_WORLD, &requestesForB[k]);
我怀疑我是否必须临时使用某种数据类型来确保行的连续性,例如:
int MPI_Type_contiguous(int count,
MPI_Datatype oldtype,
MPI_Datatype *newtype)
不,如果您不想,则不需要定义自己的数据类型。但是,如果使用得当,它们会非常有用。
假设您使用以下结构来描述您的矩阵,而不是指向数据行的指针数组:
typedef struct {
int rows;
int cols;
ssize_t rowstep;
ssize_t colstep;
int *data;
} matrix;
其中矩阵 m
的行 r
、列 c
的数据元素是 m.data[r*rowstep + c*colstep]
。我概述了这个结构的一个更好的版本
然后,您可以使用 MPI_Type_create_hvector()
创建与该特定类型矩阵(特定大小和步长)的行、列或主对角线对应的类型:
int n = (m.rows <= m.cols) ? m.rows : m.cols; /* min(m.rows, m.cols) */
MPI_Type_create_hvector(m.rows, 1, m.rowstep * sizeof m.data[0],
MPI_INT, &row_vector_type);
MPI_Type_create_hvector(m.cols, 1, m.colstep * sizeof m.data[0],
MPI_INT, &col_vector_type);
MPI_Type_create_hvector(n, 1, (m.rowstep + m.colstep) * sizeof m.data[0],
MPI_INT, &diag_vector_type);
要引用行 r
,您可以使用 m.data + r*m.rowstep
。
要引用列 c
,您可以使用 m.data + c*m.colstep
.
要引用主对角线,请使用 m.data
.
大小字段始终为 1,因为您 send/receive 单独的行或列。
也可以定义对应于矩阵的任何连续矩形部分的数据类型。
然后 MPI 库将在发送时收集数据,并在接收时分散数据。实际数据项在内存中不需要连续
在上面的示例中,可以使用相同的代码发送和接收任何行、列或对角向量。使用自定义数据类型,除了如上所示定义类型之外,不需要区分它们。
简化代码往往会产生更健壮的代码,错误更少。 (你可以说 bug 要么是 off-by-one 类型,即难以发现但并不复杂,要么是复杂类型,其中代码的不同方面以意想不到或无意的方式相互作用导致 bug。)
因此,我想说即使数据在连续数组中,用户定义的 MPI 数据类型也不是无用的,因为它们可用于简化代码,从而使其更健壮且易于维护。
显然,并非所有 MPI 代码都能很好地使用用户定义的 MPI 数据类型。尽可能使用用户定义的数据类型绝对不是解决方案。
我的观点是,您要根据具体情况来确定有用性,具体取决于您是否可以使代码更简单、更易于阅读和健壮。