15. 富士通スパコン

15.1 Fujitsu Supercomputer PRIMEHPC FX700

FOCUSスパコン[23]に導入されたFujitsu Supercomputer PRIMEHPC FX700[26](以下FX)について述べます。
FXは48個のコアによる並列計算と512ビットSIMDによるベクトル計算を用いて計算します。
アプリケーションが並列化とSIMDベクトル化に適したアルゴリズムであれば比較的容易な作業で高い性能を得ることができます。
FOCUSスパコンのXシステムの仕様は以下の通りです。

本章では5.のOpenMPと同じソースコード(omp.c)を使用します。
プログラミングの詳細についてはFOCUSのポータルサイトの「C言語使用手引書」を参考にしてください。

注意
現在は暫定運用なので本章の結果は今後修正する可能性があります。

詳しい仕様は下記の通りです。[26]

15.2 コンパイル・リンク方法

FOCUSスパコンのXシステムでコンパイル・リンクする方法は以下の通りです。
> fcc -Kfast,openmp -Nlibomp omp.c -o omp
デバッグ時は以下のようにします。
> fcc -Kfast,openmp,optmsg=2 -Nlibomp -Nlst=t omp.c -o omp
コンパイルオプション"-Koptmsg=2"をつけると最適化の状態が表示されます。 コンパイルオプション"-Nlst=t"をつけると標準出力ではなく.lstファイルに出力されます。
以下に.lstファイルの抜粋を示します。

(line-no.)(optimize)
(略)
       23             static inline void vadd(int n, const float a[], const float b[], float c[])
       24             {
       25               int    i;
       26             #ifdef _OPENMP
       27             #pragma omp parallel for
       28             #endif
                       <<< Loop-information Start >>>
                       <<<  [OPTIMIZATION]
                       <<<    SIMD(VL: 16)
                       <<< Loop-information  End >>>
       29   p     2v    for (i = 0; i < n; i++) {
       30   p     2v            c[i] = a[i] + b[i];
       31   p     2v    }
       32             }
       33
       34             static inline float sdot(int n, const float a[], const float b[])
       35             {
       36               float sum = 0;
       37               int    i;
       38             #ifdef _OPENMP
       39             #pragma omp parallel for reduction(+:sum)
       40             #endif
                       <<< Loop-information Start >>>
                       <<<  [OPTIMIZATION]
                       <<<    SIMD(VL: 16)
                       <<<    SOFTWARE PIPELINING(IPC: 1.75, ITR: 384, MVE: 2)
                       <<< Loop-information  End >>>
       41   p     8v    for (i = 0; i < n; i++) {
       42   p     8v            sum += a[i] * b[i];
       43   p     8v    }
       44
       45               return sum;
       46             }
(略)
Optimization messages
  jwd6001s-i  "omp.c", line 29: ループ制御変数'i'のループをSIMD化しました。
  jwd8664o-i  "omp.c", line 29: ループ内に関数呼出しなどの最適化対象外の命令があるため、ソフトウェアパイプライニングを適用できません。
  jwd8202o-i  "omp.c", line 29: このループを展開数2回でループアンローリングしました。
  jwd6004s-i  "omp.c", line 41: リダクション演算を含むループ制御変数'i'のループをSIMD化しました。
  jwd8204o-i  "omp.c", line 41: ループにソフトウェアパイプライニングを適用しました。
  jwd8205o-i  "omp.c", line 41: ループの繰返し数が384回以上の時、ソフトウェアパイプライニングを適用したループが実行時に選択されます。
  jwd8208o-i  "omp.c", line 42: ループ内の総和または乗積演算の計算方法を変更しました。
(略)

3通りで最適化の状態が出力されます。

  1. コンパイルオプション"-Nsrc"または"-Nlst=p"をつけたとき
    行番号とソースコードの間に最適化の状態が表示されます。それぞれ以下の意味があります。
    p: 並列化されている
    数字: unrollのサイズ
    v: SIMDベクトル化されている
  2. コンパイルオプション"-Nlst=t"をつけたとき
    for文の上の <<< 行に最適化状態が表示されます。それぞれ以下の意味があります。
    SIMD(VL: SIMDのベクトル長 (上の例では512ビット/単精度32ビット=16となっている)
    SOFTWARE PIPELINING: ソフトウェアパイプライニングの情報
  3. コンパイルオプション"-Koptmsg=2"をつけたとき
    各行の最適化の状態が日本語で表示されます。

15.3 並列化

FXでは48コアで並列計算するには、コンパイラの自動並列化を使用するか、 OpenMPの指示文を記入して並列化するかの2通りがあります。
コンパイルオプションとリンクオプションについては前者は"-Kparallel"、後者は"-Kopenmp"となります。

15.4 最適化制御行(OCL)

ソースコードに最適化制御行を記入することによってコンパイル時に最適化を制御することができます。 最適化制御行を有効にするにはコンパイルオプション"-Kocl"が必要です。
例えば自動でSIMDベクトル化できないfor文がSIMDベクトル化できることがあります。
最適化制御行の書式は以下の通りです。
#pragma loop directive
なお、富士通C/C++コンパイラーではマクロ"__FUJITSU"が定義されています。

15.5 プログラムの実行方法

プログラムの実行方法は以下の通りです。
> omp {1|2} 配列の大きさ 繰り返し回数 スレッド数
例えば以下のようになります。
> omp 1 10000000 10000 8 (ベクトルの和を計算するとき)
> omp 2 10000000 10000 8 (ベクトルの内積を計算するとき)
繰り返し回数は計算時間の測定誤差を小さくするためです。

15.6 ベクトル和の計算時間

表15-1にベクトル和の計算時間を示します。
配列の大きさ(=N)と繰り返し回数(=L)の積は一定(=1011)です。従って全体の演算量は同じです。
No.2のとき最も並列計算の速度比が高くなっています。
No.4で時間がかかるのはスレッドを多数回起動するオーバーヘッドと考えられます。

表15-1 ベクトル和の計算時間(Fujitsu PRIMEHPC FX700、OpenMP、単精度、()内は1スレッドとの速度比)
No.配列の大きさN繰り返し回数L 1スレッド 4スレッド 16スレッド 32スレッド 48スレッド
1 10,000,000 10,00025.24秒(1.0) 9.03秒(2.79) 13.14秒(1.92) 13.28秒(1.90) 15.17秒(1.66)
2 1,000,000 100,00025.89秒(1.0) 7.62秒(3.40) 2.88秒(8.99) 2.63秒(9.84) 2.75秒(9.41)
3 100,000 1,000,00026.35秒(1.0)14.92秒(1.77) 13.09秒(2.01) 17.25秒(1.53) 20.16秒(1.31)
4 10,000 10,000,00039.27秒(1.0)79.84秒(0.49)118.46秒(0.33)149.83秒(0.26)342.51秒(0.11)

15.7 ベクトル内積の計算時間

表15-2にベクトル内積の計算時間を示します。
配列の大きさ(=N)と繰り返し回数(=L)の積は一定(=1011)です。従って全体の演算量は同じです。
No.2のとき最も並列計算の速度比が高くなっています。
No.4で時間がかかるのはスレッドを多数回起動するオーバーヘッドと考えられます。

表15-2 ベクトル内積の計算時間(Fujitsu PRIMEHPC FX700、OpenMP、単精度、()内は1スレッドとの速度比)
No.配列の大きさN繰り返し回数L 1スレッド 4スレッド 16スレッド 32スレッド 48スレッド
1 10,000,000 10,00013.15秒(1.0) 4.78秒(2.75) 9.55秒(1.38) 9.39秒(1.40) 16.56秒(0.79)
2 1,000,000 100,00019.24秒(1.0) 3.65秒(5.27) 2.38秒(8.08) 2.75秒(7.00) 8.50秒(2.26)
3 100,000 1,000,00012.63秒(1.0)12.31秒(1.03) 15.44秒(0.82) 22.37秒(0.56) 74.63秒(0.17)
4 10,000 10,000,00026.72秒(1.0)93.09秒(0.29)142.16秒(0.19)195.37秒(0.14)718.71秒(0.04)

15.8 ベクトル内積の計算時間(MPI)

表15-3にMPIを使用した時のベクトル内積の計算時間を示します。
ソースコードは7.のsdot_mpi.cと同じです。
コンパイル方法は以下の通りです。

$ mpifcc -Kfast -DMPI sdot_mpi.c -o sdot_mpi
配列の大きさ(=N)と繰り返し回数(=L)の積は一定(=1011)です。従って全体の演算量は同じです。
No.1,No.2ではプロセス数を増やすと速くなり、特にNo.1ではOpenMPのときの速度低下がありません。
No.3ではプロセスを多数回起動するオーバーヘッドが見られますがOpenMPよりかなり速くなっています。

表15-3 ベクトル内積の計算時間(Fujitsu PRIMEHPC FX700、MPI、単精度、()内は1プロセスとの速度比)
No.配列の大きさN繰り返し回数L 1プロセス 12プロセス 24プロセス 36プロセス
1 10,000,000 10,00014.58秒(1.0)1.33秒(11.0)0.97秒(15.0)1.04秒(14.0)
2 1,000,000 100,00023.36秒(1.0)1.54秒(15.2)0.99秒(23.6)0.89秒(26.2)
3 100,000 1,000,00014.62秒(1.0)4.57秒( 3.2)4.70秒( 3.1)4.74秒( 3.1)