【问题标题】:What are "source" and "destination" parameters in MPI_Cart_shift?MPI_Cart_shift 中的“源”和“目标”参数是什么?
【发布时间】:2014-01-15 18:47:31
【问题描述】:

Here写的是MPI_Cart_shift的输出参数是源进程和目的进程的rank。但是,在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();
}

【问题讨论】:

    标签: parallel-processing mpi


    【解决方案1】:

    MPI_Cart_shift:在给定移位方向和数量的情况下,返回移位后的源排名和目标排名

    int MPI_Cart_shift(MPI_Comm comm, int direction, int displ, int *source, int *dest)
    

    你提交给函数的是commdirectiondispl。其中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
    

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

    MPI_Cart_shift 的一般思想是我们在拓扑中获得指定进程的排名。

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

    所以调用会是这样的:

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

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

    如何解释结果

    我 (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[0] = 1 将在 A1E1A2E2 之间建立连接,等等。如果您随后调用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
    

    【讨论】:

    • 很好的答案,但不应该让 period[0]=1 在 A1 和 E1、A2 和 E2、A3 和 E3、A4 和 E4 之间建立联系?
    • 根据我之前对维度 0 的使用,您是正确的 -> 编辑为句点[1]
    • @Henkersmann 我同意前面的评论:您不应该将文本“A1A5 之间的连接”更改为“A1E1”吗?因为设置periods[1]=1 对应于水平移位,表格给出了source|dest 垂直对。
    【解决方案2】:

    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);
    

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

    非常重要的事情。由MPI_Cart_shift(或上面的等效代码)计算的排名与cartcomm 通信器相关。仅当reorder = 0 时,它们才与原始通信器(MPI_Cart_create 中使用的通信器)中的等级匹配。当允许重新排序时,等级可能会有所不同,因此不应在原始通信器的上下文中使用这些等级。您的以下代码是有效的,但强烈依赖于 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 交换了。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2017-03-07
      • 2015-08-13
      • 2019-12-02
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多