首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >柱的MPI_Gather

柱的MPI_Gather
EN

Stack Overflow用户
提问于 2014-02-17 14:17:43
回答 1查看 861关注 0票数 0

我有一个数组,该数组由进程之间的列来划分,以便进行计算。之后,我想在一个进程(0)中收集这个数组。

每个进程的列都保存在数组A中,进程0有一个用于收集数据的数组F。F-数组的大小为n*n,每个进程都有part_size列,因此局部数组A是n*part_size。列被发送到交替进程-- c0转到p0,c1再发送到p1,c2再次发送到p0,等等。

我为发送和接收列创建了新的数据类型。

关于所有进程:

代码语言:javascript
复制
MPI_Type_vector(n, 1, part_size, MPI::FLOAT, &col_send);
MPI_Type_commit(&col_send);

关于过程0:

代码语言:javascript
复制
MPI_Type_vector(n, 1, n, MPI::FLOAT, &col_recv);
MPI_Type_commit(&col_recv);

现在,我想按以下方式收集数组:

代码语言:javascript
复制
MPI_Gather(&A, part_size, col_send, &F, part_size, col_recv, 0, MPI::COMM_WORLD);

然而,结果并不像预期的那样。我的例子有n=4和两个过程。因此,p0的值应该存储在F的0和2列中,p1应该存储在1和3中,而p0的两列都存储在0和1中,而p1的值则根本不存在。

代码语言:javascript
复制
0: F[0][0]: 8.31786
0: F[0][1]: 3.90439
0: F[0][2]: -60386.2
0: F[0][3]: 4.573e-41
0: F[1][0]: 0
0: F[1][1]: 6.04768
0: F[1][2]: -60386.2
0: F[1][3]: 4.573e-41
0: F[2][0]: 0
0: F[2][1]: 8.88266
0: F[2][2]: -60386.2
0: F[2][3]: 4.573e-41
0: F[3][0]: 0
0: F[3][1]: 0
0: F[3][2]: -60386.2
0: F[3][3]: 4.573e-41

我承认在这件事上我没有什么想法。我显然误解了and或Type_vector是如何工作的,并保存了它们的价值。有人能给我指明正确的方向吗?任何帮助都将不胜感激。

EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2014-02-17 15:59:01

我看到的问题是,使用MPI_Type_vector()创建的数据类型的范围从第一项到最后一项。例如:

col_recv数据类型的范围介于><之间(我希望掩码的表示足够清楚):

代码语言:javascript
复制
>x . . .
 x . . .
 x . . .
 x<. . .

这是13个MPI_FLOAT项(必须逐行读取,即C顺序)。收到其中两份将导致:

代码语言:javascript
复制
>x . . .
 x . . .
 x . . .
 x y . .
 . y . .
 . y . .
 . y . .

这显然不是你想要的。

要让MPI_Gather()正确地跳过接收器上的数据,您需要将col_recv的范围设置为一个元素。您可以通过使用MPI_Type_create_resized()来做到这一点。

代码语言:javascript
复制
>x<. . .
 x . . .
 x . . .
 x . . .

以使接收到的连续块被正确地交错:

代码语言:javascript
复制
   x y . . 
   x y . . 
   x y . . 
   x y . . 

然而,接收两列而不是一列将导致:

代码语言:javascript
复制
   x x y y
   x x y y
   x x y y
   x x y y

这也不是你想要的,即使更接近。

由于您希望交错列,您需要创建一个更复杂的数据类型,能够像前面一样用1项范围描述所有列:

将每一列分隔为一个元素(即先前定义的列的范围而不是大小,即4个元素):

代码语言:javascript
复制
  >x<. x .
   x . x .
   x . x .
   x . x .

每个处理器接收一个,你就能得到你想要的:

代码语言:javascript
复制
   x y x y
   x y x y
   x y x y
   x y x y

您也可以使用MPI_Type_create_darray()来完成它,因为它允许创建适合与标量的块循环分布一起使用的数据类型,是它的一个一维子案例。

我也试过了。下面是两个处理器上的工作代码:

代码语言:javascript
复制
#include <mpi.h>

#define N      4
#define NPROCS 2
#define NPART  (N/NPROCS)

int main(int argc, char **argv) {
  float a_send[N][NPART];
  float a_recv[N][N] = {0};
  MPI_Datatype column_send_type;
  MPI_Datatype column_recv_type;
  MPI_Datatype column_send_type1;
  MPI_Datatype column_recv_type1;
  MPI_Datatype matrix_columns_type;
  MPI_Datatype matrix_columns_type1;

  MPI_Init(&argc, &argv);
  int my_rank;
  MPI_Comm_rank(MPI_COMM_WORLD, &my_rank);

  for(int i=0; i<N; ++i) {
    for(int j=0; j<NPART; ++j) {
      a_send[i][j] = my_rank*100+10*(i+1)+(j+1);
    }
  }

  MPI_Type_vector(N, 1, NPART, MPI_FLOAT, &column_send_type);
  MPI_Type_commit(&column_send_type);

  MPI_Type_create_resized(column_send_type, 0, sizeof(float), &column_send_type1);
  MPI_Type_commit(&column_send_type1);

  MPI_Type_vector(N, 1, N, MPI_FLOAT, &column_recv_type);
  MPI_Type_commit(&column_recv_type);

  MPI_Type_create_resized(column_recv_type, 0, sizeof(float), &column_recv_type1);
  MPI_Type_commit(&column_recv_type1);

  MPI_Type_vector(NPART, 1, NPROCS, column_recv_type1, &matrix_columns_type);
  MPI_Type_commit(&matrix_columns_type);

  MPI_Type_create_resized(matrix_columns_type, 0, sizeof(float), &matrix_columns_type1);
  MPI_Type_commit(&matrix_columns_type1);

  MPI_Gather(a_send, NPART, column_send_type1, a_recv, 1, matrix_columns_type1, 0, MPI_COMM_WORLD);

  if (my_rank==0) {
    for(int i=0; i<N; ++i) {
      for(int j=0; j<N; ++j) {
        printf("%4.0f  ",a_recv[i][j]);
      }
      printf("\n");
    }
  }

  MPI_Finalize();
}
票数 2
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/21831431

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档