東京大学地震研究所地震火山情報センター

並列実行プログラムの最適化


自動並列化

-parallelオプションの指定により、コンパイラがソースコード内のループに対して、並列化が可能か否かの解析を行います。
  • -parallel
ソースファイル内の全てのループを解析し、安全に並列化できるループがあれば並列バイナリを生成します。
  • -par-threshold[n]
-parallelと共に指定します。
自動並列化の性能向上の見込みのしきい値(確信度)を設定します。([n]は0~100まで)
デフォルトは100。

n が 0 のとき、ループは、計算量にかかわらず、並列化可能ならば常に自動並列化されます。
n が 100 のとき、並列化が可能でかつ並列化による性能向上が見込まれる場合のみ自動並列化されます。
  • -par-report[n]
自動並列化の診断情報を出力します。

n が 0の場合、診断情報を出力しません。
n が 1の場合、並列化されたループの行番号を出力します。
n が 2の場合、並列化されたループ、並列化できなかったループの行番号を出力します。
n が 3の場合、2の情報に加えて、並列化できなかったループについて並列化できない理由を出力します。
デフォルトは0。

例)
$ cat mxm.f

  1       SUBROUTINEMXM(A,B,C,L,M,N,N1)
  2       DIMENSION A(M,L),B(N1,M),C(N1,L)
  3       DO  K =1,L
  4         DO  I =1,N
  5           C(I,K)=0.
  6         ENDDO
  7       ENDDO
  8       DO K =1,L
  9         DO I =1,N
 10           DO J =1,M
 11             C(I,K)=C(I,K)+B(I,J)*A(J,K)
 12           ENDDO
 13         ENDDO
 14       ENDDO
 15       RETURN
 16       END

$ ifort  -c  -O3  -xSSE4.2 -parallel  -par-report1 mxm.f
mxm.f(9): (col. 9) remark: LOOP WAS AUTO-PARALLELIZED.

$ ifort  -c  -O3  -xSSE4.2  -parallel  -par-threshold0  -par-report1  mxm.f
mxm.f(6): (col. 9) remark: LOOP WAS AUTO-PARALLELIZED.
mxm.f(9): (col. 9) remark: LOOP WAS AUTO-PARALLELIZED.
-par-threshold100(デフォルト)の場合は、初期化ループには充分な処理量が無く、性能向上が確実ではないと判断し、並列化しません。
-par-threshold0の場合は、性能向上の見込み値には関係なく、安全に並列化できるループは全て並列化します。

OpenMP

-openmp オプションの指定により、ソースコード内のOpenMP指示行を有効にします。
  • -openmp
openmp指示行を有効にします。
  • -openmp-report[n]
OpenMP並列化の診断情報を出力します。

n が 0の場合、診断情報を出力しません。
n が 1の場合、並列化されたループの行番号を出力します。
n が 2の場合、1の情報に加えて、MASTER、SINGLE、ORDERED、ATOMIC構造などの診断メッセージを出力します。
デフォルトは0。

$ cat mxm.f

  1       SUBROUTINE MXM (A,B,C,L,M,N,N1)
  2       DIMENSION A(M,L),B(N1,M),C(N1,L)
  3 !$OMP PARALLEL DO
  4       DO  K =1,L
  5         DO  I =1,N
  6           C(I,K)=0.
  7         ENDDO
  8       ENDDO
  9 !$OMP PARALLAL DO
 10       DO K =1,L
 11         DO I =1,N
 12           DO J =1,M
 13             C(I,K)=C(I,K)+B(I,J)*A(J,K)
 14           ENDDO
 15         ENDDO
 16       ENDDO
 17       RETURN
 18       END

$ ifort -c  -O3 -xSSE4.2  -openmp  -openmp-report1  mxm2.f
mxm.f(3): (col. 7) remark: OpenMP DEFINED LOOP WAS PARALLELIZED.
mxm.f(9): (col. 7) remark: OpenMP DEFINED LOOP WAS PARALLELIZED.

-openmpと-parallelを同時に指定したとき

OpenMP指示行の指定されたループは、-openmpによって並列化され、その他のループは、-parallelによって解析されます。
(旧システムのコンパイラバージョンでは、OpenMP指示行を含むルーチンでは-openmpだけが有効でした)

例)
$ cat mxm.f

  1       SUBROUTINE MXM (A,B,C,L,M,N,N1)
  2       DIMENSION A(M,L),B(N1,M),C(N1,L)
  3       DO  K =1,L
  4         DO  I =1,N
  5           C(I,K)=0.
  6         ENDDO
  7       ENDDO
  8 !$OMP PARALLEL DO
  9       DO K =1,L
 10         DO I =1,N
 11           DO J =1,M
 12             C(I,K)=C(I,K)+B(I,J)*A(J,K)
 13           ENDDO
 14         ENDDO
 15       ENDDO
 16       RETURN
 17       END

$ ifort -c -parallel  -par-threshold0  -par-report1  -openmp  -openmp-repor1  mxdm.f
mxm.f(8): (col. 7) remark: OpenMP DEFINED LOOP WAS PARALLELIZED.
mxm.f(6): (col. 9) remark: LOOP WAS AUTO-PARALLELIZED.



自動並列化/OpenMPによる並列プログラムのデータ分散

Altix UVシステムでは、「ファーストタッチ」を採用しています。データは、最初にそのデータにタッチ(書き込みまたは読み込み)したプロセスのローカルメモリに配置されるというものです。もし、配列(配列Aとする)を初期化しているループが並列化されていないと1CPU実行であるために、配列Aはある1つのノードに配置されます。配列Aを処理する並列実行領域では、複数のプロセッサが1つのノードへアクセスすることになります。このような状況ではプログラムの性能向上は望めません。可能なかぎり初期化ループも並列化してください。

例)
    real*8 A(n), B(n), C(n), D(n)

    do i=1, n
        A(i) = 0.
        B(i) = i/2
        C(i) = i/3
        D(i) = i/7
    enddo
!$omp parallel do
    do i=1, n
        A(i) = B(i) + C(i) + D(i)
    enddo



    real*8 A(n), B(n), C(n), D(n)
!$omp parallel do
    do i=1, n
        A(i) = 0.
        B(i) = i/2
        C(i) = i/3
        D(i) = i/7
    enddo
!$omp parallel do
    do i=1, n
        A(i) = B(i) + C(i) + D(i)
    enddo




スレッドのスタックサイズ

各ユーザが使用可能なスタックサイズの上限を6GBに設定しています(メモリ使用量の上限ではありません)。関数や手続きの中で宣言されるローカル変数がスタック領域にアロケーションされます。上限を越えてスタックに領域を確保しようとすると、AddressErrorまたは、SegmentationFaultでプログラムは終了します。この場合、データを静的にアロケーションするために、COMMONブロックでデータ(配列)を宣言して下さい。
環境変数KMP_STACKSIZEには自動並列化/OpneMPプログラムのスレーブスレッドが使用できるスタック領域の最大容量を指定します。スレーブスレッドのプライベート変数が対象です。共有変数、マスタースレッドのプライベート変数は対象ではありません。デフォルトでは2GBが設定されています。
単位として、k(キロバイト)、m(メガバイト)、g(ギガバイト)、t(テラバイト)が使えます。

例)
$export KMP_STACKSIZE=4g

Topへ戻る

MPI

コマンド行の末尾にMPIライブラリのリンクを指示してください。

 例)
$ ifort  -O3  -xSSE4.2  ex_mpi.f -lmpi

実行時にはmpirunコマンドを使ってジョブを起動してください。

MPIのデータ型

FortranプログラムでのMPIのデータ型とそれに対応するFortran でのデータ型は以下の通りです。
MPIのデータ型
Fortranのデータ型
bit
MPI_DATATYPE_NULL
対応する型はありません

MPI_INTEGER
INTEGER
32
MPI_REAL
REAL
32
MPI_DOUBLE_PRECISION
DOUBLE_PRECISION
64
MPI_COMPLEX
COMPLEX
64
MPI_DOUBLE_COMPLEX
DOUBLE_COMPLEX
128
MPI_LOGICAL
LOGICAL
4
MPI_CHARACTER
CHARACTER
1
MPI_INTEGER1
INTEGER(KIND=1)
8
MPI_INTEGER2
INTEGER(KIND=2)
16
MPI_INTEGER4
INTEGER(KIND=4)
32
MPI_INTEGER8
INTEGER(KIND=8)
64
MPI_REAL2
REAL(KIND=2)
16
MPI_REAL8
REAL(KIND=8)
64
MPI_REAL16
REAL(KIND=16)
128
MPI_BYTE
BYTE
1

CプログラムでのMPIのデータ型とそれに対応するCでのデータの型は以下の通りです。
MPIのデータ型
Cのデータ型
bit
MPI_CHAR
char
8
MPI_SHORT
short
16
MPI_INT
int
32
MPI_LONG
long
64
MPI_UNSIGHNED_CHAR
unsighned char
8
MPI_UNSIGHNED_SHORT
unsighned short
16
MPI_UNSIGHNEDunsighned int
32
MPI_UNSIGHNED_LONGunsighned long
64
MPI_FLOATfloat
32
MPI_DOUBLE
double
64
MPI_LONG_DOUBLE
long_double
128
MPI_BYTE
対応する型はありません
1
MPI_PACKED
対応する型はありません


ハイブリッド

並列化を有効にするコンパイルオプションを指定して、リンク時にMPIライブラリをリンクします。

例)
$  ifort  -O3  -xSSE4.2 -openmp  -openmp-report1  hybrid.f  -lmpi

実行時にはmpirunコマンドを使ってジョブを起動してください。
ジョブスクリプトの作成、ジョブの起動方法は、「バッチジョブの利用方法」または、「バッチジョブ(より高度な並列計算)」を参照ください。

性能解析ツール

実行時間のかかっている箇所を探す

自動並列化/OpenMPプログラム

psrunコマンドにオプション -p を指定してください。 -p オプションの指定で子スレッドまでの解析が可能です。psrunコマンドと共に自動並列化/OpenMPプログラムを実行すると、OMP_NUM_THREADSで指定した数のスレッドの他に1つの管理スレッドが起動されます。そのため解析結果ファイルも実行スレッド数+1個作られます。
行毎の解析を行いたいときには、コンパイル時に -g オプションを指定してください。

例)
$ export  OMP_NUM_THREADS=4
$ dplace  -x5  psrun  -p  ./a.out   <---dplaceコマンドのオプションは -x5 です。

実行終了後、解析結果ファイルがカレントディレクトリに作られます。
$ ls*.xml
a.out.3.4032.eich1.xml
a.out.2.4032.eich1.xml
a.out.4.4032.eich1.xml
a.out.1.4032.eich1.xml
a.out.0.4032.eich1.xml


解析結果ファイル名
バイナリ名.スレッド番号.PID.ホスト名.xml

psprocessコマンドで整形してください。
$ psprocess  a.out.0.4032.eich1.xml


(*)解析結果ファイルを複数指定して、全スレッドの解析結果を表示するということはできません。
$ psprocess  a.out.0.4032.eich1.xml  a.out.2.4032.xml  a.out.3.4032.xml  <---不可

実行例

行毎の解析を行うために -g オプションを指定し、並列化のために自動並列化オプション指定します。

$ ifort  -g  -O3 -xSSE4.2 -parallel  -par-threshold0  -par-report1  test.f
$ dplace  -x5  psrun  -p  ./a.out
$ ls *.xml
a.out.4.16904.eich1.xml
a.out.3.16904.eich1.xml
a.out.2.16904.eich1.xml
a.out.1.16904.eich1.xml
a.out.0.16904.eich1.xml
$ psprocess  a.out.0.16904.eich1.xml

Samples      Self%    Total%  Function  
     7922   87.82%   87.82%  L_jacobi__202__par_region0_2_137  
    1043   11.56%   99.38%  __intel_new_memcpy
        34     0.38%   99.76%  main$himenobmtxp_m_omp_$BLK
          6     0.07%   99.82%  _intel_fast_memcpy.J

Samples     Self%  Total%   Function:File:Line
     1260  13.97% 13.97%   L_jacobi__202__par_:himeno_omp.f:215
     1162  12.88% 26.85%   L_jacobi__202__par_:himeno_omp.f:219
     1043  11.56% 38.41%   __intel_new_memcpy:??:0
      993   11.01% 49.42%   L_jacobi__202__par:himeno_omp.f:216


MPIプログラム

MPIプログラムを解析するときはpsrunコマンドに-fオプションを指定してください。
dplaceのオプションは、-s2となります。

ハイブリッドプログラム

ハイブリッドプログラムを解析するときは、psrunコマンドに-fオプションと-pオプションを指定してください。
実行時にはomplaceコマンドを指定して下さい。omplaceコマンドのオプションは、psrunを指定しないときと変わりません。

MFLOPS値を測る

Xeon7500番台は浮動小数点演算にSSE命令を採用しています。SSE命令は4つの単精度演算、または2つ倍精度演算を1命令で行います。従って、カウントされる演算数は実際の演算数よりも少なくなります。より正確な浮動少数点演算数をカウントしたいときには、コンパイル時にSSE命令を無効にする-no-vecオプションを指定してください。(-xSSE4.2が指定されていなくても-no-vecオプションが必要です)
-xSSE4.2と-no-vecが同時に指定されたときには、-no-vecが優先されます。

-no-vecオプションは実行性能が落ちる場合がありますので、性能解析が終わりましたら、指定をはずしてください。


OpenMP/自動並列化プログラム

環境変数PS_HWPC_CONFIGに以下のように設定してください。
psrunコマンドに-pオプションを指定ください。
$ export  PS_HWPC_CONFIG=${PS_DIR}papi3_mflops.xml
$ exportOMP_NUM_THREADS=4
$ dplace -x5 psrun  -p  ./a.out <--dplace のオプションは -x5 です。

実行終了後、解析結果ファイルがカレントディレクトリに作られます。
$ ls*.xml
a.out.3.2956.eich1.xml
a.out.2.2954.eich1.xml
a.out.4.2954.eich1.xml
a.out.1.2954.eich1.xml
a.out.0.2954.eich1.xml

(注)並列数+1個の解析結果ファイルが作られます。1つは管理スレッドを
解析した結果です。管理スレッドは仕事をしないので解析結果の数値は
ほぼゼロとなります。

$psprocessa.out.0.2954.eich1.xml
解析結果ファイルの内容が表示されます。

解析結果の例)
IndexDescription  Counter Value
===============================================
    1Floatingpointoperations...  64695240024
    2Totalcycles...................146421545771

EventIndex
===============================================
    1:PAPI_FP_OPS        2:PAPI_TOT_CYC

Statistics
===============================================
Countingdomain........................user
Multiplexed...............................no
Floatingpointoperationspercycle....0.442
MFLOPS(cycles)...................1178.442 <---MFLOPS値
MFLOPS(wallclock)................1146.432 <---MFLOPS値
CPUtime(seconds)...................54.899
Wallclocktime(seconds).............56.432
%CPUutilization......................97.284


(*)全スレッドの統計値を表示するには
psprocessコマンドの-cオプションを使って、解析結果ファイルを1つの
ファイルにまとめます。そして、まとめたファイルをpsprocessコマンドで
整形します。
(統計を求める際には、管理スレッドの解析結果ファイルは対象からはず
して下さい。)

$psprocess  -c  a.out.*.xml  > kekka.xml <--ファイル名は任意
$ psprocess kekka.xml

Minimum and Maximum                            Min          Max
====================================================
% CPU utilization.......................   12.88 [eic]     20.02 [eic]
CPU time (seconds)....................    0.05 [eic]       0.08 [eic]
Floating point operations per cycle..     0.42 [eic]      0.61 [eic]
MFLOPS (cycles)....................... 1111.68 [eic] 1625.49 [eic]
MFLOPS (wall clock)...................  143.14 [eic]   263.23 [eic]
Wall clock time (seconds).............     0.32 [eic]      0.59 [eic]

Aggregate Statistics                         Median    Mean  StdDev     Sum
============================================================
% CPU utilization........................    14.86    15.61      2.43   93.65
CPU time (seconds).....................     0.06      0.06      0.01     0.36
Floating point operations per cycle...      0.55      0.53      0.07     3.19
MFLOPS (cycles)........................ 1457.24 1416.35  186.27 8498.11
MFLOPS (wall clock)....................   227.60  221.04    40.62 1326.23
Wall clock time (seconds)..............      0.37      0.39      0.10     2.36

MPIプログラム

環境変数PS_HWPC_CONFIGに以下を設定してください。
psrunコマンドに-fオプションを指定してください。
dplaceのオプションは-s2となります。

$export  PS_HWPC_CONFIG=${PS_DIR}/papi3_mflops.xml
$mpirun  -np 4 dplace -s2 psrun  -f  ./a.out
実行終了後、解析結果ファイルがカレントディレクトリに作られます。

psprocessコマンドで整形してください。

(*)全プロセスの統計値を表示するには
OpenMP/自動並列化の項目を参照下さい。

ハイブリッドプログラム

環境変数PS_HWPC_CONFIGに以下を設定してください。
psrunコマンドに-f-pオプションを指定してください。

$ export   PS_HWPC_CONFIG=${PS_DIR}/papi3_mflops.xml
$ export  OMP_NUM_THREADS=4
$ mpirun  -np 4  omplace(オプション) psrun  -f  -p  ./a.out
実行終了後、解析結果ファイルがカレントディレクトリに作られます。
psprocessコマンドで整形してください。

(*)全プロセス/スレッドの統計値を表示するには
OpenMP/自動並列化の項目を参照下さい。

perfcatcher(MPIの通信量を測る)

perfcatcherを使ってMPI関数の実行回数や、通信時間を知ることができます。
コマンド名はperfcatchです。dplaceのオプションは-s1のままです。

例)
$ mpirun  -np 4 dplace -s1perfcatch a.out

実行が終わるとカレントディレクトリに "MPI_PROFILING_STATS"というファイルが作成されます。ランク毎、MPI関数毎の通信時間がわかります。
Activity on process rank 0
......
irecv calls: 400 time: 0.624307 s datacnt 632836800
......
isend calls: 400 time: 0.00628472 s 1.57118e-05 s/call
........
wait calls: 800 time: 0.00118888 s avg datacnt1.57814e+06
........
上記はランク0の解析です。
irecvが400回コールされ、通信時間は0.624307秒、
isendが400回コールされ、通信時間は0.006284秒、
waitが800回コールされ、通信時間は、0.0011888秒