3.3 MPIによる並列計算

3.3.1 MPIによる並列計算

MPIを用いて並列計算するには図3-3-1のように計算領域を分割します。 本シミュレーターではX方向に等分割します。
プロセス数をPとすると計算時間が1/Pになります。
MPIによる並列計算はCPU版とGPU版の両方に適用することができます。
各プロセスの必要メモリーについては3.2で述べるように全領域の電圧分布をファイルに保存するときは逐次版と同じですが、 ファイルに保存しないときは1/Pになります。 ただしGPU版ではファイルの保存はCPUで行いますので、GPUの必要メモリーは常に1/Pです。


図3-3-1 計算領域のプロセスへの分割(4プロセスの場合)

2.1で述べたように差分法では隣の節点の電圧値を使用しますので、 各プロセスのX方向の両側の境界面では隣のプロセスの電圧値が必要になります。 従って図3-3-2のようにMPIの通信によって送信と受信を行います。 通信は各反復計算ごとに必要になります。red-black法では反復計算ごとに2回必要になります。 通信量は(Ny+1)*(Nz+1)ワードなのでNx/Pが十分大きければ通信に要する時間は無視することができます。


図3-3-2 隣接プロセスとの通信

リスト3-3-1に通信部を示します。 送受信時にデッドロックが発生しないように設計されているMPI_Sendrecv関数を使用します。 -X方向の境界面と+X方向の境界面の2回必要になります。


リスト3-3-1 隣接プロセスとの送受信(comm.cの一部)
     1	void comm_boundary(real_t *sendbuf, real_t *recvbuf)
     2	{
     3	#ifdef MPI
     4		MPI_Status status;
     5		const int tag = 0;
     6		const int count = (Ny + 1) * (Nz + 1);
     7	
     8		// -X boundary
     9		if (commRank > 0) {
    10			// copy to buffer
    11			int isend = 0;
    12			for (int j = 0; j <= Ny; j++) {
    13			for (int k = 0; k <= Nz; k++) {
    14				sendbuf[isend++] = V[D(1, j, k)];
    15			}
    16			}
    17			assert(isend == count);
    18	
    19			// MPI
    20			int dst = commRank - 1;
    21			MPI_Sendrecv(sendbuf, count, MPI_REAL_T, dst, tag,
    22			             recvbuf, count, MPI_REAL_T, dst, tag, MPI_COMM_WORLD, &status);
    23	
    24			// copy from buffer
    25			int irecv = 0;
    26			for (int j = 0; j <= Ny; j++) {
    27			for (int k = 0; k <= Nz; k++) {
    28				V[D(0, j, k)] = recvbuf[irecv++];
    29			}
    30			}
    31			assert(irecv == count);
    32		}
    33	
    34		// +X boundary
    35		if (commRank < commSize - 1) {
    36			// copy to buffer
    37			int isend = 0;
    38			for (int j = 0; j <= Ny; j++) {
    39			for (int k = 0; k <= Nz; k++) {
    40				sendbuf[isend++] = V[D(iMax2 - iMin2 - 1, j, k)];
    41			}
    42			}
    43			assert(isend == count);
    44	
    45			// MPI
    46			int dst = commRank + 1;
    47			MPI_Sendrecv(sendbuf, count, MPI_REAL_T, dst, tag,
    48			             recvbuf, count, MPI_REAL_T, dst, tag, MPI_COMM_WORLD, &status);
    49	
    50			// copy from buffer
    51			int irecv = 0;
    52			for (int j = 0; j <= Ny; j++) {
    53			for (int k = 0; k <= Nz; k++) {
    54				V[D(iMax2 - iMin2, j, k)] = recvbuf[irecv++];
    55			}
    56			}
    57			assert(irecv == count);
    58		}
    59	#endif
    60	}


3.3.2 MPIの計算時間

表3-3-1にnovectorモードとvectorモードでプロセス数を変えたときの計算時間を示します。
表3-2-1と合わせて考えると、 コア数の多いCPUではMPIで並列計算しプロセス数は物理コア数と同じにしたときが最適であることがわかります。 またnovectorモードが使用メモリーと計算時間の両方で有利です。

表3-3-1 MPIの計算時間(FOCUSスパコンFシステム, benchmark600)
プロセス数novectorモードvectorモード
4352.2秒316.1秒
10122.7秒112.2秒
20 84.2秒 86.0秒
40 73.1秒 89.8秒