0. 概要

並列アプリケーションのチューニングは、以下のステップを経て行われることが一般的です。

  • プロファイリング
    • asis (※1)の所要時間計測
    • プロファイリング取得時の所要時間計測
    • 両者に差がある場合プロファイリングオーバーヘッドの原因を特定
    • プロファイリングオーバーヘッド対象個所を除外してプロファイリング取得
    • プロファイリング情報から ホットスポット (※2)を特定
  • チューニング
    • ホットスポット に対するチューニング手法検討
    • チューニング適用時のプロファイリング取得
    • プロファイリング情報から ホットスポット に対するチューニングの効果を確認
    • チューニング適用時の所要時間計測
    • asis とチューニング適用時の所要時間比較・チューニング効果確認

※1)本パフォーマンス・プロファイリング関連Tipsでは、チューニング適用前のアプリケーションの状態を asis と呼称します。
※2)本パフォーマンス・プロファイリング関連Tipsでは、所要時間のうち上位を占めるプログラム単位(サブルーチン・関数、MPI通信関数、IO等)を ホットスポット と呼称します。

以上のステップでチューニングの効果が得られた場合は、チューニング適用状態を asis として上記ステップを繰り返し、更なる性能向上を図ります。

以上を踏まえて本パフォーマンス・プロファイリング関連Tipsは、プロファイリングツールに以下のオープンソースソフトウェアを使用し、

OpenMPI を使用する並列アプリケーションを ホットスポット となるMPI通信関数にフォーカスしてチューニングし、その性能を向上させる手順を解説します。

本手順は、 クラスタ・ネットワーク で相互接続する BM.Optimized3.36 を計算ノードとするHPCクラスタ環境で実行することを前提とし、 NAS Parallel Benchmarks (以降 NPB と呼称します。)の FT Class D をプロファイリング・チューニング対象の並列アプリケーションに使用します。

またMPI通信関数のチューニング手法は、 OCI HPCパフォーマンス関連情報OpenMPIのMPI集合通信チューニング方法(BM.Optimized3.36編) で得られた結果を元に検討します。

以降では、以下の順に解説します。

  1. プロファイリング・チューニング環境構築
  2. プロファイリング
  3. チューニング

1. プロファイリング・チューニング環境構築

本章は、本プロファイリング・チューニング関連Tipsで使用する環境を構築します。

この構築は、 OCI HPCプロファイリング関連Tips集Score-P・Scalasca・CubeGUIで並列アプリケーションをプロファイリング1. プロファイリング環境構築 の手順に従い実施します。

本プロファイリング・チューニング関連Tipsは、 クラスタ・ネットワーク の同一リーフスイッチに接続する8ノードの計算ノードを使用しているため、その他の構成では以降のプロファイリング・チューニングの結果が異なります。(※3)

※3)クラスタ・ネットワーク の同一リーフスイッチに接続するインスタンス間のノード間接続に於ける効果は、 OCI HPCパフォーマンス関連情報クラスタ・ネットワークのトポロジーを考慮したノード間通信最適化方法 を参照してください。


2. プロファイリング

2-0. 概要

本章は、 NPBFT Class D を使用し、 Scalasca から起動する Score-P でプロファイリング手法によるプロファイリングを実施します。
ここでMPIの実行は、8ノードの計算ノードにノード当たり32個のMPIプロセスを配置する256並列のフラットMPIとし、プロセス分割方法にブロック分割を使用(※4)します。
この際、プロファイリングによるオーバーヘッドを考慮した精度の良いプロファイリングを実施するため、以下の手順で実施します。

  • NPB バイナリの作成
  • asis所要時間 (※5)計測
  • プロファイリング取得時の 所要時間 計測
  • 両者に差がある場合プロファイリングオーバーヘッドの原因を特定
  • プロファイリングオーバーヘッド対象個所を除外してプロファイリング取得
  • プロファイリング情報から ホットスポット を特定

※4)プロセス分割方法にブロック分割を使用する場合の実行方法は、 OCI HPCパフォーマンス関連情報パフォーマンスを考慮したプロセス・スレッドのコア割当て指定方法(BM.Optimized3.36編) を参照してください。
※5)以降では、 NPBFT Class D の出力の Time in seconds所要時間 として扱います。

2-1. プロファイリング手順

以下コマンドを計算ノードのプロファイリング利用ユーザで実行し、 NPBFT Class D のプロファイリング未取得用バイナリ(ft.D.x_wo_scorep)とプロファイリング取得用バイナリ(ft.D.x_wi_scorep)を作成します。

$ mkdir ~/`hostname` && cd ~/`hostname` && wget https://www.nas.nasa.gov/assets/npb/NPB3.4.3.tar.gz
$ tar -xvf ./NPB3.4.3.tar.gz
$ cd NPB3.4.3/NPB3.4-MPI
$ cp config/make.def.template config/make.def
$ make ft CLASS=D
$ mv bin/ft.D.x bin/ft.D.x_wo_scorep
$ sed -i 's/^MPIFC = mpif90/MPIFC = scorep-mpif90/g' config/make.def
$ diff config/make.def.template config/make.def
32c32
< MPIFC = mpif90
---
> MPIFC = scorep-mpif90
$ make clean
$ make ft CLASS=D
$ mv bin/ft.D.x bin/ft.D.x_wi_scorep

次に、以下コマンドを計算ノードのプロファイリング利用ユーザで実行し、 asis所要時間 を計測します。

$ mpirun -n 256 --hostfile ~/hostlist.txt --bind-to core --map-by ppr:16:package --rank-by fill -x UCX_NET_DEVICES=mlx5_2:1 ./bin/ft.D.x_wo_scorep 2>&1 | grep "Time in seconds ="
 Time in seconds =                    32.41
$

次に、以下コマンドを計算ノードのプロファイリング利用ユーザで実行し、プロファイリング取得時の 所要時間 を計測します。
この実行により、カレントディレクトリにディレクトリ scorep_ft_256_sum が作成され、ここに取得したプロファイリングデータが格納されます。

$ scalasca -analyze mpirun -n 256 -machinefile ~/hostlist.txt "--bind-to core" "--map-by ppr:16:package" "--rank-by fill" "-x UCX_NET_DEVICES=mlx5_2:1" ./bin/ft.D.x_wi_scorep 2>&1 | grep "Time in seconds ="
 Time in seconds =                    32.74
$

以上より、 asis とプロファイリング取得時の 所要時間 に大きな差が無い(32.41秒と32.74秒)ことが確認できました。
もし両者に大きな差がある場合は、プロファイリングのオーバーヘッドの原因を調査し、プロファイリング対象を限定するフィルタを作成し、これを使用してプロファイリングのオーバーヘッドを排除します。
この手順は、 OCI HPCプロファイリング関連Tips集Score-P・Scalasca・CubeGUIで並列アプリケーションをプロファイリング2-1. 事前準備 を参照してください。

次に、以下コマンドを計算ノードのプロファイリング利用ユーザで実行し、トータル時間を評価指標としたプロファイリング情報を作成します。

$ scalasca -examine -s -x "-s totaltime" scorep_ft_256_sum/

次に、以下コマンドを計算ノードのプロファイリング利用ユーザで実行し、作成したプロファイリング情報を表示します。

$ head -n 35 scorep_ft_256_sum/scorep.score

Estimated aggregate size of event trace:                   2462MB
Estimated requirements for largest trace buffer (max_buf): 10MB
Estimated memory requirements (SCOREP_TOTAL_MEMORY):       12MB
(hint: When tracing set SCOREP_TOTAL_MEMORY=12MB to avoid intermediate flushes
 or reduce requirements using USR regions filters.)

flt     type max_buf[B]     visits time[s] time[%] time/visit[us]  region
         ALL 10,082,337 99,243,224 9134.33   100.0          92.04  ALL
         USR 10,075,130 99,198,680 4654.88    51.0          46.92  USR
         MPI      4,332     16,384 4479.29    49.0      273394.14  MPI
         COM      2,834     27,904    0.15     0.0           5.43  COM
      SCOREP         41        256    0.01     0.0          40.52  SCOREP

         MPI      1,836      6,912 3631.26    39.8      525355.87  MPI_Alltoall
         USR  9,165,312 90,243,072 2181.55    23.9          24.17  fftz2
         USR        702      6,912  717.82     7.9      103850.86  transpose2_local
         MPI      1,700      6,400  587.28     6.4       91762.80  MPI_Reduce
         USR        650      6,400  448.36     4.9       70056.11  evolve
         USR      1,404     13,824  386.17     4.2       27935.09  cffts1
         USR        702      6,912  385.43     4.2       55762.38  cffts2
         USR        702      6,912  258.85     2.8       37449.58  transpose2_finish
         MPI         84        256  248.91     2.7      972291.31  MPI_Init
         USR         26        256  164.06     1.8      640862.56  free_space
         USR         52        512   47.06     0.5       91917.14  compute_indexmap
         USR    898,560  8,847,360   43.95     0.5           4.97  cfftz
         USR        208      2,048   21.56     0.2       10525.81  vranlc
         MPI         68        256    7.20     0.1       28111.36  MPI_Barrier
         MPI         84        256    4.43     0.0       17290.94  MPI_Finalize
         MPI        168        512    0.16     0.0         319.79  MPI_Comm_split
         MPI        340      1,280    0.05     0.0          42.35  MPI_Bcast
         COM        650      6,400    0.04     0.0           6.43  checksum
         COM        702      6,912    0.03     0.0           4.26  transpose2_global
         COM        650      6,400    0.03     0.0           4.51  transpose_x_yz
         COM         26        256    0.03     0.0         100.69  ft


$

この出力から、MPI通信関数にフォーカスすると、以下のことがわかります。

  • MPI_Alltoall に3,631秒を要しトータル時間の約 40% を占めている
  • MPI_Reduce に587秒を要しトータル時間の約 6% を占めている
  • MPI_Init に249秒を要しトータル時間の約 3% を占めている

次に、以下コマンドを計算ノードのプロファイリング利用ユーザで実行し、プロファイリングデータ格納ディレクトリを次の実行に備えて別名に変更します。

$ mv scorep_ft_256_sum scorep_ft_256_sum_def

以降は、Bastionノードの CubeGUI でプロファイリングを継続するため、計算ノードのディレクトリ scorep_ft_256_sum_def をBastionノードにコピーします。

次に、以下コマンドをBastionノードのプロファイリング利用ユーザで実行し、 CubeGUI を起動します。

$ cube path_to_dir/scorep_ft_256_sum_def/profile.cubex

次に、評価指標軸の Time をクリックします。

画面ショット

次に、コールツリー軸領域の任意の箇所をクリックしたのちに Ctrl-F キーを入力し、表示される検索フィールドに Alltoall と入力します。

画面ショット

次に、表示された MPI_Alltoall(2) プルダウンメニューを選択します。

画面ショット

次に、コールツリー軸の表示から MPI_Alltoall がサブルーチン/関数の transpose_xy_ztranspose_x_yz の2か所から呼ばれており、後者のほうが圧倒的に時間を要していることがわかります。

画面ショット

次に、評価指標軸の bytes_sent をクリックします。

画面ショット

次に、コールツリー軸の MPI_Alltoall の時間を要している側をクリックします。

画面ショット

次に、システム位置軸の machine Linux をクリックします。

画面ショット

次に、システム位置軸の8ノードの計算ノードのうち1ノードをクリックします。

画面ショット

次に、選択した計算ノード配下に32個のMPIプロセスが表示され、各MPIプロセスが3.36 GBのデータを MPI_Alltoall で送信していることを突き止めます。

画面ショット

次に、他の計算ノードを選択し、同様に計算ノード配下の32個のMPIプロセスが同サイズのデータを MPI_Alltoall で送信していることを確認します。

画面ショット

次に、評価指標軸の Visits をクリックします。

画面ショット

次に、コールツリー軸の MPI_Alltoall の時間を要している側をクリックし、システム位置軸の表示から計算ノード配下の32個の全てのMPIプロセスが時間を要している側の MPI_Alltoall を25回呼び出していることを突き止めます。

画面ショット


3. チューニング

3-0. 概要

本章は、先に取得したプロファイリング情報を元に、以下の手順でチューニングを実施します。

  • ホットスポット に対するチューニング手法検討
  • チューニング適用時のプロファイリング取得
  • プロファイリング情報から ホットスポット に対するチューニングの効果を確認
  • チューニング適用時の 所要時間 計測
  • asis とチューニング適用時の 所要時間 比較・チューニング効果確認

3-1. チューニング手順

先の 2. プロファイリング の結果から、以下のことが判明しました。

  • 最も時間を要しているMPI関数は MPI_Alltoall で2か所から呼び出されている
  • transpose_x_yz から呼ばれる MPI_Alltoall が殆どの時間を占めこれを ホットスポット と特定
  • ホットスポットMPI_Alltoall は以下の特性を有する
    • 256個のMPIプロセスから均等に総量3.36 GBのデータが送信されている
    • 256個のMPIプロセスから均等に25回コールされている

ここで、 ホットスポットMPI_Alltoall が各回とも同一メッセージサイズであると仮定し、このメッセージサイズを以下の計算式から求めます。

3.36 (GB) / 25 (回) / 256 (MPIプロセス) = 525 KB

以上の情報から、 OpenMPI の以下MPI通信をターゲットにチューニング手法を検討します。

  • MPI関数: MPI_Alltoall
  • ノード数: 8ノード
  • ノード当たりプロセス数: 32
  • メッセージサイズ: 525 KB

ここで、 OpenMPIのMPI集合通信チューニング方法(BM.Optimized3.36編) の当該箇所である 4-3-1. Alltoall に於いて、最後に記載されている以下グラフの512 KBメッセージサイズ部分を確認し、

Alltoall 8 node 32 ppn

最も所要時間の短い黄色のグラフである以下のパラメータ設定が適していると判断、これをチューニング手法として採用します。

  • UCX_TLS: self,sm,ud
  • UCX_RNDV_THRESH: intra:16kb,inter:128kb
  • UCX_ZCOPY_THRESH: 128kb
  • NPS: 1
  • プロセス配置: サイクリック分割(※5)
  • coll_hcoll_enable: 0

※5)プロセス分割方法にサイクリック分割を使用する場合の実行方法は、 OCI HPCパフォーマンス関連情報パフォーマンスを考慮したプロセス・スレッドのコア割当て指定方法(BM.Optimized3.36編) を参照してください。

次に、以下コマンドを計算ノードのプロファイリング利用ユーザで実行し、チューニング手法適用時のプロファイリングを取得します。
この実行により、カレントディレクトリにディレクトリ scorep_ft_256_sum が作成され、ここに取得したプロファイリングデータが格納されます。

$ scalasca -analyze mpirun -n 256 -machinefile ~/hostlist.txt "--map-by pe-list=`for i in \`seq 0 15\`; do seq -s, $i 18 35 | tr '\n' ','; done | sed 's/,$//g'`:ordered" "--mca coll_hcoll_enable 0" "-x UCX_NET_DEVICES=mlx5_2:1" "-x UCX_TLS=self,sm,ud" "-x UCX_RNDV_THRESH=intra:16kb,inter:128kb" "-x UCX_ZCOPY_THRESH=128kb" ./bin/ft.D.x_wi_scorep

次に、以下コマンドを計算ノードのプロファイリング利用ユーザで実行し、トータル時間を評価指標としたプロファイリング情報を作成します。

$ scalasca -examine -s -x "-s totaltime" scorep_ft_256_sum/

次に、以下コマンドを計算ノードのプロファイリング利用ユーザで実行し、作成したプロファイリング情報を表示します。

$ head -n 35 scorep_ft_256_sum/scorep.score

Estimated aggregate size of event trace:                   2462MB
Estimated requirements for largest trace buffer (max_buf): 10MB
Estimated memory requirements (SCOREP_TOTAL_MEMORY):       12MB
(hint: When tracing set SCOREP_TOTAL_MEMORY=12MB to avoid intermediate flushes
 or reduce requirements using USR regions filters.)

flt     type max_buf[B]     visits time[s] time[%] time/visit[us]  region
         ALL 10,082,337 99,243,224 8211.33   100.0          82.74  ALL
         USR 10,075,130 99,198,680 4596.88    56.0          46.34  USR
         MPI      4,332     16,384 3614.27    44.0      220597.31  MPI
         COM      2,834     27,904    0.17     0.0           6.00  COM
      SCOREP         41        256    0.01     0.0          34.58  SCOREP

         MPI      1,836      6,912 3378.02    41.1      488718.85  MPI_Alltoall
         USR  9,165,312 90,243,072 2181.79    26.6          24.18  fftz2
         USR        702      6,912  723.68     8.8      104699.28  transpose2_local
         USR        702      6,912  412.58     5.0       59690.86  cffts2
         USR      1,404     13,824  396.78     4.8       28702.14  cffts1
         USR        650      6,400  394.26     4.8       61603.52  evolve
         USR        702      6,912  278.05     3.4       40226.67  transpose2_finish
         MPI         84        256  186.26     2.3      727571.60  MPI_Init
         USR         26        256   97.82     1.2      382113.92  free_space
         USR         52        512   47.86     0.6       93468.91  compute_indexmap
         USR    898,560  8,847,360   43.55     0.5           4.92  cfftz
         MPI      1,700      6,400   34.49     0.4        5389.22  MPI_Reduce
         USR        208      2,048   20.45     0.2        9986.40  vranlc
         MPI         84        256   10.93     0.1       42714.15  MPI_Finalize
         MPI         68        256    3.03     0.0       11818.25  MPI_Barrier
         MPI        340      1,280    0.91     0.0         709.50  MPI_Bcast
         MPI        168        512    0.62     0.0        1217.71  MPI_Comm_split
         COM        650      6,400    0.05     0.0           8.34  checksum
         COM        702      6,912    0.03     0.0           4.46  transpose2_global
         COM        650      6,400    0.03     0.0           4.73  transpose_x_yz
         COM         26        256    0.03     0.0         103.13  ft
$

この出力から、 MPI_Alltoall の時間が3,631秒から3,378秒に減少しており、チューニング の効果が確認できます。
またチューニング適用の副次的な効果として、 MPI_Reduce の時間が587秒から34秒に減少していることも確認できます。

次に、以下コマンドを計算ノードのプロファイリング利用ユーザで実行し、チューニング適用時の 所要時間 を計測します。

$ mpirun -n 256 --hostfile ~/hostlist.txt --map-by pe-list=`for i in \`seq 0 15\`; do seq -s, $i 18 35 | tr '\n' ','; done | sed 's/,$//g'`:ordered --mca coll_hcoll_enable 0 -x UCX_NET_DEVICES=mlx5_2:1 -x UCX_TLS=self,sm,ud -x UCX_RNDV_THRESH=intra:16kb,inter:128kb -x UCX_ZCOPY_THRESH=128kb ./bin/ft.D.x_wo_scorep 2>&1 | grep "Time in seconds ="
 Time in seconds =                    28.97
$

この結果から、 asis とチューニング適用時の 所要時間 を比較し、チューニングの効果を確認します。

以下は、本プロファイリング・チューニング関連Tips環境で 所要時間 を計測した結果です。
この計測結果は、 asis とチューニング適用時をそれぞれ5回計測し、最大値と最小値を除く3回の算術平均です。

asis チューニング適用時 性能向上比
32.6秒 29.1秒 12.0%

更新日時: