MPI_Cart_Shift.Corner 街区
MPI_Cart_Shift.Corner Neighborhood
我需要创建一个具有立方体拓扑结构的通信器,然后 select 立方体的表面,使用 MPI_Cart_Shift 在处于边缘的进程之间实现的消息传递。例如,我处理的等级为 0(R0),我的邻域是 R2、R4、R6(立方体的下表面)。我可以找到R2和R4,但我不明白如何找到R6。我的代码:
#include<mpi.h>
#include<stdio.h>
int main(int argc, char *argv[])
{
int rank, k;
int size;
int ndims = 3;
int source, dest;
int up,down,right,left,up3, down3;
int edges[6][4] = {{0,1,5,4},
{4,5,7,6},
{2,3,1,0},
{6,7,3,2},
{1,3,7,5},
{0,2,6,7}};
int t, incep=0;
char processor_name[MPI_MAX_PROCESSOR_NAME];
MPI_Comm comm, comm3d;
int dims[3]={0,0,0}, coords[3]={0,0,0},
periods[3]={1,1,1}, reorder = 0;
MPI_Status status;
int user_edge;
MPI_Init(&argc, &argv);
MPI_Comm_size(MPI_COMM_WORLD, &size);
MPI_Comm_rank(MPI_COMM_WORLD, &rank);
MPI_Dims_create(size, ndims, dims);
MPI_Cart_create(MPI_COMM_WORLD, ndims, dims, periods, reorder, &comm);
MPI_Cart_coords(comm, rank, 3, coords);
fflush(stdout);
printf("Rank %d coordinates are %d %d %d\n", rank, coords[0], coords[1], coords[2]);
MPI_Barrier(comm);
int leftrank, rightrank;
int downrank, uprank;
MPI_Comm_rank(comm, &rank);
MPI_Cart_coords(comm, rank, 2, coords);
MPI_Cart_shift(comm, 0, -1, &downrank, &uprank);
MPI_Sendrecv(buffer, 10, MPI_INT, downrank, 123, buffer2, 10, MPI_INT, uprank, 123, comm, &status);
MPI_Cart_shift(comm, 1, -1, &rightrank, &leftrank);
MPI_Sendrecv(buffer, 10, MPI_INT, leftrank, 123, buffer2, 10, MPI_INT, rightrank, 123, comm, &status);
printf("P:%d My neighbors are rightRank: %d downRank:%d leftRank:%d upRank:%d diagonal:%d diagonalX:%d\n", rank,rightrank,downrank,leftrank,uprank,diagonal,diagonalX);
MPI_Finalize();
return 0;
}
我会尝试添加类似这样的东西 MPI_Cart_shift(comm, 2, 1, &diagonal, &diagonalX);但是对于 R0,它显示 R1,我明白了....我怎样才能得到角落街区?
您忘记标记 R5。我没有想到直接的方法。但这里有一个间接的方式:
(1) 对于坐标为 (A,y,z)
的任何等级,请考虑坐标:(A,y+1,z+1), (A,y-1,z-1), (A,y+1,z-1)
和 (A,y-1,z+1)
- 这些可以是 4 个对角线邻居。显然,在考虑减号时,例如z-1
,很明显 z-1 >= 0
并且在考虑加号时,例如y+1 <= (dimension_in_y - 1)
。例如考虑 R5(您忘记标记)。 R5
根据 MPI 有坐标 R5(0,1,0)
。它可以有 4 个对角邻居:(0,1+1,0+1), (0,1-1,0-1),(0,1+1,0-1),(0,1-1,0+1)
- 其中只有第四个存在(很明显,因为没有邻居可以有 负坐标 并且每个坐标必须是 1 小于 比那个方向的维度)。接下来简单查询MPI_coordinate_to_rank()
。
(2) 另一种方法是查询 right
和 left
邻居关于他们的 front
和 back
邻居(这在性能方面会很糟糕)。
(3) 要将其推广到 8 个邻居 - 您还需要改变 X 坐标 - 但您的问题仅限于立方体的表面。
您可以使用MPI_Cart_rank查找您需要的信息。
int MPI_Cart_rank(MPI_Comm comm, const int coords[], int *rank)
这里comm是笛卡尔拓扑的通讯器。 coords 是一个整数数组(该数组的大小是笛卡尔拓扑的维数)包含过程的坐标(在您的例子中,R6 为 1,1,0) .然后输出 rank 将 return 您可以在后续通信中使用的该进程的全局排名。
顺便说一句,MPI_Cart_coords执行相反的方向,即从等级到坐标。
MPI_Cart_shift
只能在任何主要方向上找到邻居,但不能在对角线上找到邻居 - 你必须自己实现它,这并不难做到。笛卡尔位移本身只不过是一个方便的函数,它包装了对 MPI_Cart_coords
和 MPI_Cart_rank
:
的调用
//
// The following is equivalent to
// MPI_Cart_shift(cart_comm, i, disp, &rank_source, &rank_dest);
//
// Obtain the rank of the calling process and translate it into coordinates
int rank, coords[ndims];
MPI_Comm_rank(cart_comm, &rank);
MPI_Cart_coords(cart_comm, rank, ndims, coords);
int mycoord_i = coords[i];
// Compute the coordinates of the destination in direction i and convert them into rank
coords[i] = mycoord_i + disp;
// Take care of non-periodic dimensions
if (!periods[i] && (coords[i] >= dims[i] || coords[i] < 0))
rank_dest = MPI_PROC_NULL;
else
MPI_Cart_rank(cart_comm, coords, &rank_dest);
// Compute the coordinates of the source in direction i and convert them into rank
coords[i] = mycoord_i - disp;
// Take care of non-periodic dimensions
if (!periods[i] && (coords[i] >= dims[i] || coords[i] < 0))
rank_source = MPI_PROC_NULL;
else
MPI_Cart_rank(cart_comm, coords, &rank_source);
请注意对于非周期性维度,应该如何显式处理越界。对于周期性的,MPI_Cart_rank
本身会折叠坐标。您的笛卡尔拓扑是周期性的,因此可以跳过检查(不推荐)。
您可以轻松地调整上面的代码以产生二维或更多维度的偏移,然后使用它来枚举位移和方向的所有可能组合以找到位于给定面上的等级。例如:
int rank, coords[ndims];
MPI_Comm_rank(cart_comm, &rank);
MPI_Cart_coords(cart_comm, rank, ndims, coords);
int my_coord1 = coords[1];
int my_coord2 = coords[2];
coords[1] = my_coord1 + 1;
coords[2] = my_coord2 + 1;
MPI_Cart_rank(cart_comm, coords, &rank_dest);
coords[1] = my_coord1 - 1;
coords[2] = my_coord2 - 1;
MPI_Cart_rank(cart_comm, coords, &rank_source);
当被R0执行时,会给你R6在rank_dest
中的排名。如果您将代码提取到单独的例程中并调用它 MyMPI_Cart_shift2
:
MyMPI_Cart_shift2(cart_comm, 1, 1, 2, 1, &rank_source, &rank_dest);
另一种选择是使用 MPI_Cart_sub
将笛卡尔拓扑拆分为平行于面的板。然后,您可以直接执行仅涉及任何给定 slab 中的等级的通信。
我需要创建一个具有立方体拓扑结构的通信器,然后 select 立方体的表面,使用 MPI_Cart_Shift 在处于边缘的进程之间实现的消息传递。例如,我处理的等级为 0(R0),我的邻域是 R2、R4、R6(立方体的下表面)。我可以找到R2和R4,但我不明白如何找到R6。我的代码:
#include<mpi.h>
#include<stdio.h>
int main(int argc, char *argv[])
{
int rank, k;
int size;
int ndims = 3;
int source, dest;
int up,down,right,left,up3, down3;
int edges[6][4] = {{0,1,5,4},
{4,5,7,6},
{2,3,1,0},
{6,7,3,2},
{1,3,7,5},
{0,2,6,7}};
int t, incep=0;
char processor_name[MPI_MAX_PROCESSOR_NAME];
MPI_Comm comm, comm3d;
int dims[3]={0,0,0}, coords[3]={0,0,0},
periods[3]={1,1,1}, reorder = 0;
MPI_Status status;
int user_edge;
MPI_Init(&argc, &argv);
MPI_Comm_size(MPI_COMM_WORLD, &size);
MPI_Comm_rank(MPI_COMM_WORLD, &rank);
MPI_Dims_create(size, ndims, dims);
MPI_Cart_create(MPI_COMM_WORLD, ndims, dims, periods, reorder, &comm);
MPI_Cart_coords(comm, rank, 3, coords);
fflush(stdout);
printf("Rank %d coordinates are %d %d %d\n", rank, coords[0], coords[1], coords[2]);
MPI_Barrier(comm);
int leftrank, rightrank;
int downrank, uprank;
MPI_Comm_rank(comm, &rank);
MPI_Cart_coords(comm, rank, 2, coords);
MPI_Cart_shift(comm, 0, -1, &downrank, &uprank);
MPI_Sendrecv(buffer, 10, MPI_INT, downrank, 123, buffer2, 10, MPI_INT, uprank, 123, comm, &status);
MPI_Cart_shift(comm, 1, -1, &rightrank, &leftrank);
MPI_Sendrecv(buffer, 10, MPI_INT, leftrank, 123, buffer2, 10, MPI_INT, rightrank, 123, comm, &status);
printf("P:%d My neighbors are rightRank: %d downRank:%d leftRank:%d upRank:%d diagonal:%d diagonalX:%d\n", rank,rightrank,downrank,leftrank,uprank,diagonal,diagonalX);
MPI_Finalize();
return 0;
}
我会尝试添加类似这样的东西 MPI_Cart_shift(comm, 2, 1, &diagonal, &diagonalX);但是对于 R0,它显示 R1,我明白了....我怎样才能得到角落街区?
您忘记标记 R5。我没有想到直接的方法。但这里有一个间接的方式:
(1) 对于坐标为 (A,y,z)
的任何等级,请考虑坐标:(A,y+1,z+1), (A,y-1,z-1), (A,y+1,z-1)
和 (A,y-1,z+1)
- 这些可以是 4 个对角线邻居。显然,在考虑减号时,例如z-1
,很明显 z-1 >= 0
并且在考虑加号时,例如y+1 <= (dimension_in_y - 1)
。例如考虑 R5(您忘记标记)。 R5
根据 MPI 有坐标 R5(0,1,0)
。它可以有 4 个对角邻居:(0,1+1,0+1), (0,1-1,0-1),(0,1+1,0-1),(0,1-1,0+1)
- 其中只有第四个存在(很明显,因为没有邻居可以有 负坐标 并且每个坐标必须是 1 小于 比那个方向的维度)。接下来简单查询MPI_coordinate_to_rank()
。
(2) 另一种方法是查询 right
和 left
邻居关于他们的 front
和 back
邻居(这在性能方面会很糟糕)。
(3) 要将其推广到 8 个邻居 - 您还需要改变 X 坐标 - 但您的问题仅限于立方体的表面。
您可以使用MPI_Cart_rank查找您需要的信息。
int MPI_Cart_rank(MPI_Comm comm, const int coords[], int *rank)
这里comm是笛卡尔拓扑的通讯器。 coords 是一个整数数组(该数组的大小是笛卡尔拓扑的维数)包含过程的坐标(在您的例子中,R6 为 1,1,0) .然后输出 rank 将 return 您可以在后续通信中使用的该进程的全局排名。
顺便说一句,MPI_Cart_coords执行相反的方向,即从等级到坐标。
MPI_Cart_shift
只能在任何主要方向上找到邻居,但不能在对角线上找到邻居 - 你必须自己实现它,这并不难做到。笛卡尔位移本身只不过是一个方便的函数,它包装了对 MPI_Cart_coords
和 MPI_Cart_rank
:
//
// The following is equivalent to
// MPI_Cart_shift(cart_comm, i, disp, &rank_source, &rank_dest);
//
// Obtain the rank of the calling process and translate it into coordinates
int rank, coords[ndims];
MPI_Comm_rank(cart_comm, &rank);
MPI_Cart_coords(cart_comm, rank, ndims, coords);
int mycoord_i = coords[i];
// Compute the coordinates of the destination in direction i and convert them into rank
coords[i] = mycoord_i + disp;
// Take care of non-periodic dimensions
if (!periods[i] && (coords[i] >= dims[i] || coords[i] < 0))
rank_dest = MPI_PROC_NULL;
else
MPI_Cart_rank(cart_comm, coords, &rank_dest);
// Compute the coordinates of the source in direction i and convert them into rank
coords[i] = mycoord_i - disp;
// Take care of non-periodic dimensions
if (!periods[i] && (coords[i] >= dims[i] || coords[i] < 0))
rank_source = MPI_PROC_NULL;
else
MPI_Cart_rank(cart_comm, coords, &rank_source);
请注意对于非周期性维度,应该如何显式处理越界。对于周期性的,MPI_Cart_rank
本身会折叠坐标。您的笛卡尔拓扑是周期性的,因此可以跳过检查(不推荐)。
您可以轻松地调整上面的代码以产生二维或更多维度的偏移,然后使用它来枚举位移和方向的所有可能组合以找到位于给定面上的等级。例如:
int rank, coords[ndims];
MPI_Comm_rank(cart_comm, &rank);
MPI_Cart_coords(cart_comm, rank, ndims, coords);
int my_coord1 = coords[1];
int my_coord2 = coords[2];
coords[1] = my_coord1 + 1;
coords[2] = my_coord2 + 1;
MPI_Cart_rank(cart_comm, coords, &rank_dest);
coords[1] = my_coord1 - 1;
coords[2] = my_coord2 - 1;
MPI_Cart_rank(cart_comm, coords, &rank_source);
当被R0执行时,会给你R6在rank_dest
中的排名。如果您将代码提取到单独的例程中并调用它 MyMPI_Cart_shift2
:
MyMPI_Cart_shift2(cart_comm, 1, 1, 2, 1, &rank_source, &rank_dest);
另一种选择是使用 MPI_Cart_sub
将笛卡尔拓扑拆分为平行于面的板。然后,您可以直接执行仅涉及任何给定 slab 中的等级的通信。