MPI_Cart_shift中的“source”和“destination”参数是什么?

时间:2013-12-28 09:54:35

标签: parallel-processing mpi

Here写的是MPI_Cart_shift的输出参数是源进程和目标进程的等级。但是,在this tutorial(下面的代码)中,作为源进程返回的内容稍后在MPI_Isend中用于发送消息。任何人都可以清理它 - 实际上“来源”和“目的地”是什么意思?

#include "mpi.h"
#include <stdio.h>
#define SIZE 16
#define UP    0
#define DOWN  1
#define LEFT  2
#define RIGHT 3

int main(argc,argv)
int argc;
char *argv[];  {
int numtasks, rank, source, dest, outbuf, i, tag=1, 
   inbuf[4]={MPI_PROC_NULL,MPI_PROC_NULL,MPI_PROC_NULL,MPI_PROC_NULL,}, 
   nbrs[4], dims[2]={4,4}, 
   periods[2]={0,0}, reorder=0, coords[2];

MPI_Request reqs[8];
MPI_Status stats[8];
MPI_Comm cartcomm;

MPI_Init(&argc,&argv);
MPI_Comm_size(MPI_COMM_WORLD, &numtasks);

if (numtasks == SIZE) {
  MPI_Cart_create(MPI_COMM_WORLD, 2, dims, periods, reorder, &cartcomm);
  MPI_Comm_rank(cartcomm, &rank);
  MPI_Cart_coords(cartcomm, rank, 2, coords);
  MPI_Cart_shift(cartcomm, 0, 1, &nbrs[UP], &nbrs[DOWN]);
  MPI_Cart_shift(cartcomm, 1, 1, &nbrs[LEFT], &nbrs[RIGHT]);

  printf("rank= %d coords= %d %d  neighbors(u,d,l,r)= %d %d %d %d\n",
         rank,coords[0],coords[1],nbrs[UP],nbrs[DOWN],nbrs[LEFT],
         nbrs[RIGHT]);

  outbuf = rank;

  for (i=0; i<4; i++) {
     dest = nbrs[i];
     source = nbrs[i];
     MPI_Isend(&outbuf, 1, MPI_INT, dest, tag, 
               MPI_COMM_WORLD, &reqs[i]);
     MPI_Irecv(&inbuf[i], 1, MPI_INT, source, tag, 
               MPI_COMM_WORLD, &reqs[i+4]);
     }

  MPI_Waitall(8, reqs, stats);

  printf("rank= %d                  inbuf(u,d,l,r)= %d %d %d %d\n",
         rank,inbuf[UP],inbuf[DOWN],inbuf[LEFT],inbuf[RIGHT]);  }
else
  printf("Must specify %d processors. Terminating.\n",SIZE);

MPI_Finalize();
}

2 个答案:

答案 0 :(得分:19)

MPI_Cart_shift:给定移位方向和数量

,返回移位的源和目标等级
int MPI_Cart_shift(MPI_Comm comm, int direction, int displ, int *source, int *dest)

您提交给该函数的内容是commdirectiondispl。其中direction指定进行置换的维度。 displ acement是距离。

实施例

想象一下像这样的2D购物车拓扑(名称不是排名而是流程名称,仅用于解释):

A1  A2  A3  A4  A5
B1  B2  B3  B4  B5
C1  C2  C3  C4  C5
D1  D2  D3  D4  D5
E1  E2  E3  E4  E5

正如您可能已经理解的那样,您正在编写SPMD - MPI中的代码,因此我们现在可以选择一个流程来显示正在发生的事情。我们选择C3

MPI_Cart_shift的一般概念是我们在拓扑中获得指定进程的等级。

首先,我们必须决定我们想要去哪个方向,让我们选择0,这是列维度。 然后我们必须指定到另一个进程的距离,假设这是2

所以这个电话就像是:

MPI_Cart_shift(cartcomm, 0, 2, &source, &dest);

现在,放入sourcedest变量的排名分别是流程A3E3

如何解释结果

I(C3)想要将数据发送到距离为2的同一列中的进程。因此,这是dest等级。

如果您从A3的角度执行相同的操作:处理A3dest字段作为C3的等级。

这就是source所说的内容:如果调用相同的MPI_Cart_shift,则向我发送这些数据的流程的等级是什么。

如果指定位置没有进程,则变量包含MPI_PROC_NULL。 因此,每个流程的调用结果如下所示(每个流程都使用source | dest,-使用MPI_PROC_NULL):

MPI_Cart_shift(cartcomm, 0, 2, &source, &dest);

 A1      A2      A3      A4      A5
-|C1    -|C2    -|C3    -|C4    -|C5

 B1      B2      B3      B4      B5
-|D1    -|D2    -|D3    -|D4    -|D5

 C1      C2      C3      C4      C5
A1|E1   A2|E2   A3|E3   A4|E4   A5|E5

 D1      D2      D3      D4      D5
B1|-    B2|-    B3|-    B4|-    B5|-

 E1      E2      E3      E4      E5
C1|-    C2|-    C3|-    C4|-    C5|-

附加信息

如果您创建任何尺寸设置为periods = 1的购物车,那么购物车的第一个节点和最后一个节点之间会有一个虚拟边缘。在此示例中,periods[1] = 1会在A1A5之间,B1B5之间建立连接,依此类推。如果你然后调用MPI_Cart_shift,那么计数必须围绕着角落,所以你的输出将是:

 A1      A2      A3      A4      A5
D1|C1   D2|C2   D3|C3   D4|C4   D5|C5

 B1      B2      B3      B4      B5
E1|D1   E2|D2   E3|D3   E4|D4   E5|D5

 C1      C2      C3      C4      C5
A1|E1   A2|E2   A3|E3   A4|E4   A5|E5

 D1      D2      D3      D4      D5
B1|A1   B2|A2   B3|A3   B4|A4   B5|A5

 E1      E2      E3      E4      E5
C1|B1   C2|B2   C3|B3   C4|B4   C5|B5

答案 1 :(得分:3)

MPI_Cart_shift是一项便利功能。它的主要用途是用于数据移位,即每个等级在某个方向上发送数据(即到destination)并从相反方向(即从source)接收数据的操作(前向操作)。当source用作目标而destination用作源时,数据以相反方向流动(向后操作)。这种操作的一个例子是halo swapping,它通常需要沿着每个维度进行两次移位 - 一次向前移动,一次向后移动。

MPI_Cart_shift是一个便利函数,因为它的操作等同于以下一组MPI调用:

// 1. Determine the rank of the current process
int rank;
MPI_Comm_rank(cartcomm, &rank);

// 2. Transform the rank into topology coordinates
int coords[ndims];
MPI_Cart_coords(cartcomm, rank, ndims, coords);

// 3. Save the current coordinate along the given direction
int saved_coord = coords[direction];

// 4. Compute the "+"-shifted position and convert to rank
coords[direction] = saved_coord + displ;
// Adjust for periodic boundary if necessary
if (periods[direction])
   coords[direction] %= dims[direction];

// 5. Convert to rank
MPI_Cart_rank(cartcomm, coords, &destination);

// 6. Compute the "-"-shifted position and convert to rank
coords[direction] = saved_coord - displ;
// Adjust for periodic boundary
if (periods[direction])
   coords[direction] %= dims[direction];

// 7. Convert to rank
MPI_Cart_rank(cartcomm, coords, &source);

还可以使用算术计算秩&lt; - &gt;坐标变换而不调用MPI_Cart_rankMPI_Cart_coords但是当拓扑的维度发生变化时,公式会发生变化,因此非常不灵活。 / p>

非常重要的东西。由MPI_Cart_shift(或上面的等效代码)计算的等级与cartcomm通信器相关。那些匹配原始传播者(MPI_Cart_create中使用的)中的等级仅在reorder = 0时。当允许重新排序时,排名可能不同,因此不应在原始通信器的上下文中使用这些排名。您的以下代码有效,但在很大程度上取决于reorder = 0调用中MPI_Cart_create的事实:

dest = nbrs[i];
source = nbrs[i];
MPI_Isend(&outbuf, 1, MPI_INT, dest, tag, 
          MPI_COMM_WORLD, &reqs[i]);
MPI_Irecv(&inbuf[i], 1, MPI_INT, source, tag, 
          MPI_COMM_WORLD, &reqs[i+4]);

此处nbrscartcomm内计算,然后在MPI_COMM_WORLD中使用。正确的代码应在两个通信调用中使用cartcomm

MPI_Isend(&outbuf, 1, MPI_INT, dest, tag, 
          cartcomm, &reqs[i]);
MPI_Irecv(&inbuf[i], 1, MPI_INT, source, tag, 
          cartcomm, &reqs[i+4]);

某些算法要求数据以相反的方式传播,即交换前向和后向。对于此类算法,指定的位移displ可能为负。一般来说,使用负位移调用MPI_Cart_shift相当于具有正位移但是sourcedestination交换的调用。