ノード内並列
まずは,内積計算プログラムが1つのRaspberry Pi上の複数のCPUコアを利用できるよう に拡張しましょう.これを,ノード内並列化と呼びます.
OpenMPとは
複数のCPUコアを活用するには様々な方法がありますが,スパコンにおいて広く 用いられているのは,OpenMPと呼ばれるAPIです. OpenMPに対応するコンパイラを用いると,ソースコード中にディレクティブと 呼ばれるコメントのようなものを挿入するだけで, コンパイラが自動的に並列化しててくれます.
下記がOpenMPを用いて並列化した内積計算プログラムです.
逐次版のソースコードに追加したのは,
#pragma omp parallel for reduction(+:sum)
という1行だけです.
このディレクティブを挿入することにより,直後のforループが自動的にコアの数に分割され,
並列に実行されます.
例えば,ARRAY_SIZE
が100でCPUが4コアだとすると,
- コア0が
i
=0〜24 - コア1が
i
=25〜49 - コア2が
i
=50〜74 - コア3が
i
=75〜99
という風に4つのコアがループを均等に分担して実行します.
#include <stdio.h>
#define TRIALS (1000)
#define ARRAY_SIZE (1000 * 1000)
double a[ARRAY_SIZE];
double b[ARRAY_SIZE];
void compute()
{
double sum = 0;
#pragma omp parallel for reduction(+:sum)
for (int i = 0; i < ARRAY_SIZE; i++) {
sum += a[i] * b[i];
}
}
int main(int argc, char *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();
}
return 0;
}
OpenMP版プログラムのコンパイル・実行
このプログラムをgccコンパイラでコンパイルします.
OpenMPを使用するプログラムするためには,-fopenmp
というオプションを指定する必要があります.
$ gcc -fopenmp -o dot_omp dot_omp.c
このプログラムを実行します.
$ time ./dot_omp
OpenMPを使用しない場合の26.886秒に対して,7.372秒に実行時間を短縮できました. Raspberry Pi 3B+は4つのCPUコアを搭載しています.4つのCPUコアを活用することで, 3.6倍の高速化を達成できたことになります.
real 0m7.372s
user 0m29.175s
sys 0m0.040s
OpenMPはデフォルトでは全てのCPUコアを用いて計算を行いますが,
OMP_NUM_THREADS
という環境変数を設定することにより,使用するコア数を制限することができます.
例えば,2コアを使用して計算を行うためには,次のようにします.
$ time OMP_NUM_THREADS=2 ./dot_omp
やってみよう
OMP_NUM_THREADS
を使用して使用するコア数を1から4まで変更し, プログラムの実行時間がどのように変化するか調べてみましょう.ARRAY_SIZE
やTRIALS
をより大きな値に変更して,実行時間を測ってみましょう.