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();
}
答案 0 :(得分:19)
MPI_Cart_shift:给定移位方向和数量
,返回移位的源和目标等级int MPI_Cart_shift(MPI_Comm comm, int direction, int displ, int *source, int *dest)
您提交给该函数的内容是comm
,direction
和displ
。其中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);
现在,放入source
和dest
变量的排名分别是流程A3
和E3
。
I(C3
)想要将数据发送到距离为2的同一列中的进程。因此,这是dest
等级。
如果您从A3
的角度执行相同的操作:处理A3
将dest
字段作为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
会在A1
和A5
之间,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
答案 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_rank
或MPI_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]);
此处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]);
某些算法要求数据以相反的方式传播,即交换前向和后向。对于此类算法,指定的位移displ
可能为负。一般来说,使用负位移调用MPI_Cart_shift
相当于具有正位移但是source
和destination
交换的调用。