ノード間並列

ここでは,内積計算プログラムが複数のRaspberry Pi上の複数のCPUコアを利用できるよう 拡張しましょう.これを,ノード間並列化と呼びます.

MPIとは

ノード内並列化と同様に,ノード間並列化にも様々な方法がありますが, スパコンにおいて広く用いられているのは,MPIと呼ばれるAPIです.

#include <stdio.h>
#include <mpi.h>

#define TRIALS (1000)
#define ARRAY_SIZE (1000 * 1000)

double a[ARRAY_SIZE];
double b[ARRAY_SIZE];

void compute()
{
    int rank, nprocs;

    MPI_Comm_rank(MPI_COMM_WORLD, &rank);
    MPI_Comm_size(MPI_COMM_WORLD, &nprocs);

    double sum = 0;

    int subarray_size = ARRAY_SIZE / nprocs;

    for (int i = subarray_size * rank; i < subarray_size * (rank + 1); i++) {
        sum += a[i] * b[i];
    }

    double sum_total;

    MPI_Reduce(&sum, &sum_total, 1, MPI_DOUBLE, MPI_SUM, 0, MPI_COMM_WORLD);
}

int main(int argc, char *argv[])
{
    MPI_Init(&argc, &argv);

    for (int i = 0; i < ARRAY_SIZE; i++) {
        a[i] = 1.0;
        b[i] = 2.0;
    }

    for (int i = 0; i < TRIALS; i++) {
        compute();
    }

    MPI_Finalize();

    return 0;
}

MPI版プログラムのコンパイル・実行

このプログラムをMPI用コンパイラでコンパイルします.

$ mpicc -o dot_mpi dot_mpi.c

MPIプログラム用ランチャでプログラムを起動し,実行時間を計測します.

$ time mpirun --hostfile hosts dot_mpi

OpenMPを使用しない場合の26.886秒に対して,3.377秒に実行時間を短縮できました. 4ノード上の計16のCPUコアを活用することで, 8.0倍の高速化を達成できたことになります.

real	0m3.377s
user	0m8.979s
sys	0m0.851s

MPIはデフォルトでは全てのノードの全てのCPUコアを用いて計算を行います. mpirun-npというオプションを指定することにより, 使用するコア数を制限することができます. 例えば,8コアを使用して計算を行うためには,次のようにします.

$ time mpirun -np 8 --hostfile hosts dot_mpi

やってみよう

  • -npオプションを用いて使用するコア数を変更し,プログラムの実行時間がどのように変化するか調べてみましょう.