0

我正在尝试将两个数组(每个长度为 n)组合到根进程(rank=0)上的接收缓冲区中,以形成一个长度为 2*n 的数组,即包含所有值的单个数组。

为简洁起见,我的代码类似于以下内容:

#define ROOT 0

int myFunction(int* rBuf, int n) {
  int* sBuf = malloc(n*sizeof(int));

  // Do work, calculate offset, count etc.

  MPI_Reduce(sBuf, rBuf+offset[rank], counts[rank], 
             MPI_INT, MPI_SUM, ROOT, MPI_COMM_WORLD);
}
// where offset[rank] is amount to offset where it is to be received
// offset[0] = 0, offset[1] = n
// counts contains the length of arrays on each process

但是,当我检查 rBuf 时,它会减少为没有偏移量的 rBuf,例如:

// Rank 0: sBuf = {3, 2}
// Rank 1: sBuf = {5, 1}
// Should be rBuf = {3, 2, 5, 1}    
rBuf = {8, 3, 0, 0}

附加信息:

  • rBuf 被初始化为在减少之前使用 0 值的正确大小
  • 所有进程都有偏移数组
  • 当时使用 MPI_Reduce 的原因是,如果 rBuf 设置为 0s,那么使用 MPI_SUM 减少将给出所需的答案

我查看了文档、一些在线教程/指南,当然还有 SO,但我仍然无法弄清楚我做错了什么。

对于答案,我特别在寻找:

  1. 这在技术上是否可以使用 MPI_Reduce?
  2. 我的 MPI_Reduce 调用是否正确?(指针算术错误?)
  3. 使用 MPI 是可行/正确的做法还是更好的方法?

谢谢

4

2 回答 2

2

聚集(和分散)在这个答案中有一些详细的描述。

ReduceGather是相关但不同的操作。当你调用MPI_Reduce这些向量时

// Rank 0: sBuf = {3, 2}
// Rank 1: sBuf = {5, 1}

Reduce 做了正确的事;它采用各种sBufs 并添加它们(因为您告诉它对数据执行操作MPI_SUM),给出{8,3} == {3,2} + {5,1},并将结果放入根处理器接收缓冲区。(如果您希望每个人事后都有答案,MPI_Allreduce()请改用。)但请注意,您对 Reduce 的调用,

 MPI_Reduce(sBuf, rBuf+offset[rank], counts[rank], 
             MPI_INT, MPI_SUM, ROOT, MPI_COMM_WORLD);

实际上是无效的;对于 Reduce,每个人都需要以相同的计数进行调用。唯一rBuf重要的是根进程上的那个,在这种情况下是等级 0。

另一方面,Gather 也收集所有数据,但不是用 sum、product、xor 等操作折叠它,而是连接结果。

于 2013-04-12T11:58:06.507 回答
0

所以我尝试了 MPI_Gatherv,这似乎解决了问题,验证了更大数量和大小的数组。

这是我所做的:

MPI_Gatherv(sBuf, counts[rank], MPI_INT, c, counts, offset, MPI_INT, 
            ROOT, MPI_COMM_WORLD);

我也尝试过 MPI_Gather 但这没有用(它似乎但实际上以与我的 reduce 调用类似的方式传递偏移量没有实际效果)。

由此,我对我的具体问题的理解如下:

  1. 这是不可能的/不是 MPI_Reduce 的预期用例
  2. 因此,reduce 调用是不正确的,包括调用中的偏移量无效
  3. 正确的方法是使用 MPI_Gatherv,因为这是这个库专门调用的地址(接收缓冲区中的位移)

如果更有经验的 MPI 用户愿意参与进来,那就太好了。

谢谢

于 2013-04-12T07:50:58.600 回答