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

pmi*_*hna 11 parallel-processing mpi

这里写的是MPI_Cart_shift的输出参数是源和目标进程的等级.但是,在本教程(下面的代码)中,作为源进程返回的内容稍后在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();
}
Run Code Online (Sandbox Code Playgroud)

Hen*_*ann 20

MPI_Cart_shift:给定移位方向和数量,返回移位的源和目标等级

int MPI_Cart_shift(MPI_Comm comm, int direction, int displ, int *source, int *dest)
Run Code Online (Sandbox Code Playgroud)

你交给这个函数的是comm,directiondispl.其中direction指定了位移的维度.该displacement是距离.

想象一下像这样的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
Run Code Online (Sandbox Code Playgroud)

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

一般的想法 MPI_Cart_shift是我们在拓扑中得到指定过程的等级.

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

所以电话会是这样的:

MPI_Cart_shift(cartcomm, 0, 2, &source, &dest);
Run Code Online (Sandbox Code Playgroud)

现在,放入sourcedest变量的等级分别是过程A3E3.

如何解释结果

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

如果你从以下观点做同样的事情A3:进程A3获得其dest字段的等级C3.

source就是说:如果调用相同的数据,那么向我发送这些数据的过程的等级是多少MPI_Cart_shift.

如果变量包含指定位置的进程MPI_PROC_NULL.因此,每个进程的调用结果将如下所示(每个进程使用source | dest,使用-for 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|-
Run Code Online (Sandbox Code Playgroud)

额外的信息

如果您创建具有任何尺寸集的购物车,则购物车periods = 1的第一个节点和最后一个节点之间存在虚拟边缘.在此示例中,periods[1] = 1将在A1A5之间,之间B1和之间建立连接B5,依此类推.如果你然后调用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
Run Code Online (Sandbox Code Playgroud)


Hri*_*iev 5

MPI_Cart_shift是一个方便的函数。它的主要用途是数据移位,即每个等级在某个方向(即 to destination)发送数据并从相反方向(即 from source)接收数据(正向操作)的操作。当source用作目标和destination源时,数据以相反的方向流动(反向操作)。这种操作的一个例子是光环交换,它通常需要沿每个维度进行两次移位 - 一次向前,一次向后。

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);
Run Code Online (Sandbox Code Playgroud)

也可以使用算术计算秩<->坐标变换而不调用MPI_Cart_rankorMPI_Cart_coords但是当拓扑的维数发生变化时,公式也会发生变化,这将非常不灵活。

一件很重要的事。由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]);
Run Code Online (Sandbox Code Playgroud)

这里在nbrs内计算cartcomm然后在 内使用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]);
Run Code Online (Sandbox Code Playgroud)

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