MPI 二维切割子程序 MPI_CART_CREATE、MPI_CART_COORDS 和 MPI_CART_SHIFT

写在前面

注:这里只介绍了 MPI 二维切割在 Fortran 语言中的应用,于 C 语言,类似但略有差别。

专用词语转录说明如下:

原词 转录
程式 程序
副程式 子程序
阵列 数组
叫用 调用
引数 参数
communicator 通信域
CPU id 进程编号
整数阵列 整型数组
逻辑阵列 逻辑型数组
变数 变量
安排 排布
运作 运行
邻居 邻位

垂直坐标图示法则(Cartesian Topology)

二维数组 A(NN, MM) 要做二维切割时,需先说明在第一维和第二维各切成几块。例如第一维要切成四块,第二维要切成三块,则切割后第一维的长度 N 为 NN/4,第二维的长度 M 为 MM/3,当然两者都必须能整除才行。如果 NN = 200 和 MM = 150,就可以使用 PARAMETER 来设定 M、N 的值,切割后数组的第一维和第二维都要预留前后各一个数组元素位置时,其参数可设定为:

1
2
PARAMETER (NN=200, MM=150, JP=4, IP=3, N=NN/JP, M=MM/IP,)
DIMENSION A(0:N+1, 0:M+1)

数组 A 切成 4×3 十二块,第一块由一个 CPU 来执行时,则需要十二个 CPU。这十二个 CPU 的编号和坐标如下图所示:
二维切割区块图
十二个 CPU 之中每一个 CPU 的上、下、左、右邻位关系如上图所示。水平方向 X 轴为第一维 (J) ,垂直方向 Y 轴为第二维 (I) 。

MPI_CART_CREATE

二维切割方式必须在调用 MPI_CART_SIZE、MPI_COMM_RANK 分别取得通信域的进程数和进程编号等之后,再调用 MPI 子程序 MPI_CART_CREATE 来加以设定。如上图所示的二维切割方式,其相应的参数设定如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
PARAMETER (NDIM=2, JP=4, IP=3)
INTEGER NPROC, MYID
INTEGER IPART(NDIM), COMM2D, MY_CID, MY_COORD(NDIM)
INTEGER SIDEWAYS, UPDOWN, RIGHT, UP, L_NBR, R_NBR, T_NBR, B_NBR
LOGICAL PERIODS(NDIM), REORDER
...
CALL MPI_INIT (IERR)
CALL MPI_COMM_SIZE (MPI_COMM_WORLD, NPROC, IERR)

IPART(1)=JP
IPART(2)=IP
PERIODS(1)=.FALSE.
PERIODS(2)=.FALSE.
REORDER=.TRUE.
CALL MPI_CART_CREATE (MPI_COMM_WORLD, NDIM, IPART, PERIODS, REORDER, COMM2D, IERR)
参数 含义
MPI_COMM_WORLD 原来的通信域
NDIM 切割的维数,上图中二维切割的例子需设定为 2
IPART NDIM 个元素的整型数组
IPART(1) 第一维切成的块数,上图中的例子需设定为 4
IPART(2) 第二维切成的块数,上图中的例子需设定为 3
PERIODS NDIM 个元素的逻辑型数组
PERIODS(1) 第一维首尾区块是否相邻,是为 .TRUE. 否为 .FALSE. ,上图中的例子需设定为 .FALSE.
PERIODS(2) 第二维首尾区块是否相邻,是为 .TRUE. 否为 .FALSE. ,上图中的例子需设定为 .FALSE.
REORDER 逻辑型变量,已排定的 CPU 是否重排,是为 .TRUE. 否为 .FALSE. ,一般设为 .TRUE.
COMM2D 切割后得到的新通信域

在调用 MPI_CART_CREATE 之前已经调用过 MPI_COMM_RANK,已经排布好各个 CPU 了,这是一种线性排布。在调用 MPI_CART_CREATE 时,是一种平面排布,当 REORDER 的值设定为 .TRUE. 时,允许系统重新排布各个 CPU,使得相邻的 CPU 排布在相邻的位置上,从而得到最佳的传输效率。

MPI_CART_COORDS

此后,程序在新的的通信域 COMM2D 中运行,之前获取的进程编号已经不再适用。必须重新调用 MPI_COMM_RANK 获取当前 CPU 在新的通信域中的进程号。MPI_COMM_RANK 的调用格式如下:

1
CALL MPI_COMM_RANK (COMM2D, MYID, IERR)
参数 含义
COMM2D 新设定的通信域
MYID 在通信域 COMM2D 中的新的进程号

MYID 的排布方式如上图中的 CPU0、CPU1、CPU2 等所示。
接下来就须调用 MPI_CART_COORDS 获取当前 CPU 在二维 CPU 数组中的坐标 MY_COORD。调用格式如下:

1
CALL MPI_CART_COORDS (COMM2D, MY_CID, NDIM, MY_COORD, IERR)
参数 含义
COMM2D 新设定的通信域
MY_CID 在通信域 COMM2D 中的进程号
NDIM 切割的维数,如上图中的例子需设定为 2
MY_COORD NDIM 个元素的整型数组,进程号为 MY_CID 的 CPU 的 CPU 数组坐标
MY_COORD(1) 第一维方向上的坐标,从 0 起算
MY_COORD(2) 第二维方向上的坐标,从 0 起算

CPU 坐标 MY_COORD 的排布方式如上图中 CPU0、CPU1、CPU2 等进程号下的括号内的数字。
由上图易知:当 MY_COORD(1) 为 0 时,该 CPU 位于 CPU 数组的最左边;当 MY_COORD(1) 为 JP - 1 时,该 CPU 位于 CPU 数组的最右边;当 MY_COORD(2) 为 0 时,该 CPU 位于 CPU 数组的最下面(底边);当 MY_COORD(2) 为 IP - 1 时,该 CPU 位于 CPU 数组的最上面(顶边)。

MPI_CART_SHIFT

现在,还须调用 MPI_CART_SHIFT 来获取当前 CPU 的上、下、左、右邻位的进程号。调用格式如下:

1
2
3
4
5
6
7
8
INTEGER SIDEWAYS, UPDOWN, RIGHT, UP
SIDEWAYS=0
UPDOWN=1
RIGHT=1
UP=1

CALL MPI_CART_SHIFT (COMM2D, SIDEWAYS, RIGHT, L_NBR, R_NBR, IERR)
CALL MPI_CART_SHIFT (COMM2D, UPDOWN, UP, B_NBR, T_NBR, IERR)
参数 含义
COMM2D 新设定的通信域
SIDEWAYS 整型变量,其值为 0 表示获取第一维 (J) 方向的邻位
RIGHT 整型变量,其值为 1 表示获取左、右邻位
L_NBR 整型变量,其值为获取的当前 CPU 的左邻位的进程号
R_NBR 整型变量,其值为获取的当前 CPU 的右邻位的进程号
参数 含义
UPDOWN 整型变量,其值为 1 表示获取第二维 (I) 方向的邻位
UP 整型变量,其值为 1 表示获取下、上邻位
B_NBR 整型变量,其值为获取的当前 CPU 的下邻位的进程号
T_NBR 整型变量,其值为获取的当前 CPU 的上邻位的进程号

这里,L_NBR、R_NBR、B_NBR 和 T_NBR 分别代表 left_neighbor、right_neighbor、bottom_neighbor 和 top_neighbor。

参考

郑守成,2002,《Fortran 語言 MPI 平行计算程式设计》第五章 5.4 节

---------- 文结至此 静待下章 ----------