写在前面
注:这里只介绍了 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 | PARAMETER (NN=200, MM=150, JP=4, IP=3, N=NN/JP, M=MM/IP,) |
数组 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 | PARAMETER (NDIM=2, JP=4, IP=3) |
参数 | 含义 |
---|---|
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 | INTEGER SIDEWAYS, UPDOWN, RIGHT, UP |
参数 | 含义 |
---|---|
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 节