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,direction和displ.其中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)
现在,放入source和dest变量的等级分别是过程A3和E3.
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将在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
Run Code Online (Sandbox Code Playgroud)
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带有负位移的调用等同于带有正位移的调用,但是source和destination交换了。
| 归档时间: |
|
| 查看次数: |
6656 次 |
| 最近记录: |