性能分析ツール活用方法
平成
26年度「京」における高速化ワークショップ
登録施設利用促進機関
一般財団法人 高度情報科学技術研究機構
富山 栄治
アウトライン
•
高速化について
•
性能分析ツールを活用した最適化手順
•
簡易計測する
•
FIPP
•
詳細計測する
•
FAPP
高速化
結果を得るまでの時間を短くする事
計算機に適したジョブ形状・投入方法にする
プログラム最適化
ジョブ最適化
単体性能向上
無駄な計算の除去
数値計算ライブラリ使用
キャッシュミス低減
命令スケジューリング改善
並列性能向上
並列化率の向上
通信の削減
ロードインバランス解消
アルゴリズム変更
プログラム最適化の手順
プログラムの理解
簡易計測
詳細計測
ロードバランス
スケーラビリティ
キャッシュ有効利用ホットスポット
データ構造
並列化構造
処理フロー
命令スケジューリング目標設定
•
実現可能な並列数の把握
•
タイムステップループ、
I/O処理などの把握
•
並列数、並列化率、実行時間などの目標設定
•
性能評価に適した条件設定
•
ホットスポットの特定
•
ロードバランス、スケーラビリティ評価
•
チューニングの実施
•
演算効率
、
キャッシュ利用効率評価
•
チューニングの実施
性能分析ツールを活用した
最適化手順
プログラム例:
LAMMPS
•
分子動力学プログラム
•
ベンチマーク:
LJ
•
atomic fluid
•
32,000 atoms for
100
timesteps
•
実行環境
•
FX10
簡易計測する
•
目的:注目すべき場所を特定する
•
ホットスポット
•
ロードバランス
•
スケーラビリティ
•
方法:時間を測る
•
タイマールーチンを処理ブロック毎に挿入する
•
プロファイラを使う
•
京では基本プロファイラ
(
FIPP
)
•
サンプリング計測によってコスト情報を計測する
•
手軽、計測オーバーヘッドが小さい
•
注意:サンプル数が少ないと不正確
•
実行時のコマンドを変更するだけ
•
fipp -‐C -‐d dir/ -‐Ihwm,call -‐i10 mpiexec ./a.out
•
区間指定可能
•
出力:
GUI,テキスト
•
fipppx -‐A -‐d dir/ -‐Ihwm,cpu,balance,call,src > fipp.txt
FIPP
アプリケーション全体
プロセス毎
スレッド毎
procedure
loop
line
単位で順位が確認出来る
*プロセス毎のコストはスレッドコストが合計されたもの
ホットスポットを特定する
177 Procedures profile 178 179 ************************************************************************************* 180 Application - procedures 181 ************************************************************************************* 182183 Cost % Operation (S) Barrier % Start End 184 --- 185 1226 100.0000 12.3147 0 0.0000 -- -- Application 186 --- 187 515 42.0065 5.1730 0 0.0000 -- --
LAMMPS_NS::PairLJCutOMP::eval
188 139 11.3377 1.3962 0 0.0000 -- -- LAMMPS_NS::Neighbor._OMP_3 189 105 8.5644 1.0547 0 0.0000 -- -- __GI___printf_fp198 MPI % Communication (S) Start End 199 --- 200 0 0.0000 0.0000 -- -- Application 201 --- 202 0 0.0000 0.0000 -- -- LAMMPS_NS::PairLJCutOMP::eval 203 0 0.0000 0.0000 -- -- LAMMPS_NS::Neighbor._OMP_3 204 0 0.0000 0.0000 -- -- __GI___printf_fp
•
コスト上位がホットスポット
•
コスト内訳に
Barrier,
MPI処理があるか確認する
コールグラフで場所を確認する
Call graph Process 0 - Thread 0 ---+ | 0% <0> main [0 / 216] | 0% <1> LAMMPS_NS::CiteMe::CiteMe(LAMMPS_NS::LAMMPS *) [1]| 0% <1> LAMMPS_NS::LAMMPS::LAMMPS(int, char **, ompi_communicator_t *) [0 / 1] | 0% <2> LAMMPS_NS::LAMMPS::post_create() [0 / 1]
| 0% <3> LAMMPS_NS::Input::one(const char *) [0 / 1] | 0% <4> LAMMPS_NS::Input::execute_command() [0 / 1] | 0% <5> LAMMPS_NS::Input::package() [0 / 1]
| 0% <6> LAMMPS_NS::Modify::add_fix(int, char **, int) [0 / 1] | 0% <8> __GI_strcmp [1]
| 0% <6> LAMMPS_NS::PairLJCutOMP::compute(int, int) [0 / 26] | 0% <7> __jwe_opar_fullset [0 / 26]
##| 11% <8> LAMMPS_NS::PairLJCutOMP::eval<(int)0, (int)0, (int)1>(int, int) [24] | 0% <8> LAMMPS_NS::PairLJCutOMP::compute(int, int)._OMP_1 [0 / 2]
| 0% <9> LAMMPS_NS::ThrOMP::reduce_thr(void *, int, int) [0 / 2]
| 1% <10> LAMMPS_NS::data_reduce_thr(double *, int, int, int, int) [2] | 3% <6> LAMMPS_NS::AtomVecAtomic::unpack_reverse(int, int *, double *) [6] | 0% <6> LAMMPS_NS::Output::write(long) [0 / 158] | 0% <7> LAMMPS_NS::Dump::write() [0 / 158] | 0% <8> LAMMPS_NS::DumpAtom::convert_string(int, double *) [0 / 153] | 0% <9> LAMMPS_NS::DumpAtom::convert_noimage(int, double *) [0 / 152] | 0% <10> __sprintf [0 / 152]
•
ホットスポットがどこで呼ばれているのかを確認する
•
呼び出し箇所が複数の場合もあるので注意
コスト割合
ネストレベル
[自身のコスト
/
積算コスト]
ロードバランスを見る(プロセス)
365 LAMMPS_NS::PairLJCutOMP::eval<(int)0, (int)0, (int)1>(int, int, LAMMPS_NS::ThrData *) 366 +-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐+-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐+ 367 | | | -‐ 2 % 140 Process 0 368 | |** | + 11 % 159 Process 1 369 | **| | -‐ 8 % 131 Process 2 370 | | | -‐ 1 % 142 Process 3 371 +-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐+-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐+ 372
373 LAMMPS_NS::Neighbor::half_bin_newton_omp(LAMMPS_NS::NeighList *)._OMP_3 374 +-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐+-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐+ 375 | | | -‐ 1 % 35 Process 0 376 | |******* | + 28 % 45 Process 1 377 | *******| | -‐ 29 % 25 Process 2 378 | | | + 2 % 36 Process 3 379 +-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐+-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐+
•
evalはインバランスが殆ど無い→
OK
•
half_...は最小と最大で倍以上のインバランスがある→
問題あり?
よく見ると
…
16スレッドの合計コストが25など →
サンプル数が少ない!
ロードバランスを見る(プロセス)
362 LAMMPS_NS::PairLJCutOMP::eval<(int)0, (int)0, (int)1>(int, int, LAMMPS_NS::ThrData *) 363 +-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐+-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐+ 364 | | | + 1 % 7629 Process 0 365 | | | + 3 % 7736 Process 1 366 | *| | -‐ 5 % 7150 Process 2 367 | | | + 1 % 7588 Process 3 368 +-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐+-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐+ 369 370 LAMMPS_NS::Neighbor::half_bin_newton_omp(LAMMPS_NS::NeighList *)._OMP_3 371 +-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐+-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐+ 372 | |* | + 5 % 1699 Process 0 373 | | | -‐ 2 % 1583 Process 1 374 | |* | + 5 % 1691 Process 2 375 | **| | -‐ 8 % 1477 Process 3 376 +-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐+-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐+
•
100stepから5,000stepに増やした
•
インバランスは小さい事が確認出来た
•
適切な条件設定が大事
時間方向のインバランスにも注意!
ロードバランスを見る(スレッド)
478 LAMMPS_NS::PairLJCutOMP::eval<(int)0, (int)0, (int)1>(int, int, LAMMPS_NS::ThrData *) 479 +-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐+-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐+ 480 | *| | -‐ 7 % 445 Thread 0 481 | |**** | + 17 % 556 Thread 15 482 | |***** | + 20 % 572 Thread 9 483 | |***** | + 21 % 579 Thread 10 484 | | | -‐ 3 % 464 Thread 3 485 | |* | + 7 % 511 Thread 12 486 | |** | + 10 % 524 Thread 11 487 | |* | + 6 % 507 Thread 13 488 | |* | + 6 % 507 Thread 4 489 | |** | + 11 % 529 Thread 14 490 | *| | -‐ 5 % 455 Thread 5 491 | **| | -‐ 9 % 433 Thread 8 492 | ****| | -‐ 19 % 386 Thread 6 493 | **| | -‐ 11 % 422 Thread 2 494 | *******| | -‐ 29 % 338 Thread 7 495 | ****| | -‐ 16 % 401 Thread 1 496 +-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐+-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐+
スレッドのロードバランスもプロセスと同様に確認出来る
スレッド間インバランスは同期待ちを発生させる
ロードバランスを見る(
GUI)
fipp:Application View:Profile:Cost Stacked Chart:Procedure
•
ランク0が他より非常に時間がかかっている
•
ランク0の大部分は
スレッドバリア
待ち
•
どこにインバランスがあるか見極める
•
MPI_barrierを注目箇所の直前に挿入し
、
計測タイミングを揃
えて計測してみる
•
チューニング
•
分割方法を確認し
、
変更する
•
ブロック分割
•
サイクリック分割
•
ブロックサイクリック分割
•
ダイナミック
インバランスが現れた時は
…
スケーラビリティを見る(プロセス)
条件を変えて複数の計測を行い、経過時間の変化を見る
プロセス数
p
2p
4p
問題規模
N
2N
4N
ストロング
•
ウィークスケーリング
•
プロセス辺りの問題規模一定
•
理想:実行時間が一定
•
ストロングスケーリング
•
問題規模固定
•
理想:実行時間がプロセス数に反比例
ホットスポットの問題点を調査する
詳細計測する
簡易計測によって判明したホットスポットについてソースを見て、
•
不要な計算、初期化を(何度も)していないか
•
最適化されたライブラリを使用できないか
を確認・検討する。
解決しない場合、
詳細計測する
•
目的:問題点を探る
•
flops
•
キャッシュミス率
•
SIMD化
•
メモリバンド幅
•
MPI通信
•
方法:様々なハードウェア情報を計測する
•
プロファイラを使う
•
京では詳細プロファイラ
(
FAPP
)を使う
FAPP
•
ハードウェアモニタ情報を計測する
•
手軽、多くの情報が得られる
•
注意:計測オーバーヘッド
•
実行時のコマンドを変更するだけ
•
fapp -‐C -‐d dir/ -‐Ihwm -‐Hevent=Statistics mpiexec ./a.out
•
区間指定可能
•
出力:
GUI,テキスト
計測領域を区間指定する
#include <fj_tool/fapp.h>
void PairLJCutOMP::eval(int iifrom, int iito, ThrData * const thr)
{
fapp_start
("eval", 0, 0)
...
fapp_stop
("eval", 0, 0)
}
•
処理ブロック単位で性能評価出来る
•
ネストした区間も計測出来る
•
可能ならカーネル化出来ると良い
Flopsを見る
fapp -‐C -‐d dir -‐Ihwm -‐Hevent=
Statistics
mpiexec ./a.out
339 Performance monitor : Statistics
351 Kind Elapsed(s) MFLOPS MFLOPS/PEAK(%) MIPS MIPS/PEAK(%) 352 ---
353 AVG 1.2271 100.4571 0.7610 836.4384 12.6733 eval 0 354 MAX 1.2684 100.9861 0.7650 853.5688 12.9329
355 MIN 1.1858 99.9281 0.7570 819.3080 12.4138
371 Mem throughput Mem throughput
372 Kind Elapsed(s) _chip(MB/S) /PEAK(%) SIMD(%) 373 --- 374 AVG 1.2271 380.8218 0.4464 0.0000 eval 0 375 MAX 1.2684 390.7164 0.4580 0.0000 376 MIN 1.1858 370.9272 0.4348 0.0000
128
GFlops
=
8
コア
x
2
GHz
x
4
命令(
SIMD)
x
2
(積和)
が実現して初めて高性能が達成できる
スレッド並列
命令スケジューリング
・
SIMD化
・積和演算のバランス
ホットスポットの状況を見る
•
コンパイルリストを見る
•
演算性能に関係する最適化情報が確認出来る
•
方法:コンパイル時にオプションを追加
•
-‐Koptmsg=2 -‐Nlst=t
•
src.f90 → src.lstが生成される
113 2 for (jj = 0; jj < jnum; jj++) { 114 2 j = jlist[jj]; 115 i 2 factor_lj = special_lj[sbmask(j)]; 116 2 j &= NEIGHMASK; 117 118 2 delx = xtmp - x[j].x; 119 2 dely = ytmp - x[j].y; 120 2 delz = ztmp - x[j].z;
121 2 rsq = delx*delx + dely*dely + delz*delz; 122 2 jtype = type[j];
123
124 2 if (rsq < cutsqi[jtype]) { 125 2 r2inv = 1.0/rsq;
126 2 r6inv = r2inv*r2inv*r2inv;
127 2 forcelj = r6inv * (lj1i[jtype]*r6inv - lj2i[jtype]); 128 2 fpair = factor_lj*forcelj*r2inv;
129
130 2 fxtmp += delx*fpair; 131 2 fytmp += dely*fpair; 132 2 fztmp += delz*fpair;
133 2 if (NEWTON_PAIR || j < nlocal) { 134 2 f[j].x -= delx*fpair;
135 2 f[j].y -= dely*fpair; 136 2 f[j].z -= delz*fpair; 137 2 }
138
jwd6229s-i "../pair_lj_cut_omp.cpp", line 113: ループ内でif文が存在するため、このループはSIMD化できません。
jwd8664o-i "../pair_lj_cut_omp.cpp", line 113: ループ内に関数呼出しなどの最適化対象外の命令があるため、ソフトウェアパイプライニング
を適用できません。
jwd8202o-i "../pair_lj_cut_omp.cpp", line 113: このループを展開数2回でループアンローリングしました。
jwd8670o-i "../pair_lj_cut_omp.cpp", line 113: ループ内に分岐命令があるため、ソフトウェアパイプライニングを適用できません。
jwd8101o-i "../pair_lj_cut_omp.cpp", line 115: 利用者定義の関数'_ZN9LAMMPS_NS4Pair6sbmaskEi'をインライン展開しました。
jwd8209o-i "../pair_lj_cut_omp.cpp", line 121: 多項式の演算順序を変更しました。
jwd8209o-i "../pair_lj_cut_omp.cpp", line 128: 多項式の演算順序を変更しました。
jwd5202p-i "../pair_lj_cut_omp.cpp", line 134: ループ中で変数'f'を定義する順序が逐次実行と異なるため、このループは並列化できません。
jwd6202s-i "../pair_lj_cut_omp.cpp", line 134: ループ中で変数'f'を定義する順序が逐次実行と異なるため、このループはSIMD化できません。
キャッシュミス率を見る
fapp -‐C -‐d dir -‐Ihwm -‐Hevent=
Cache
mpiexec ./a.out
L2
L1
演算器
メモリ
core
…
L1
演算器
core
CPU
339 Performance monitor : Cache
344
351 Kind Elapsed(s) Inst LS_SIMD-or(%) LS-or(%) Prefetch
352 ---
353 AVG 1.2669 1034821112 0.0000 27.1868 3335019 eval 0
354 MAX 1.3076 1057457764 0.0000 27.3535 3336378
355
MIN 1.2261 1012184461 0.0000 27.0201 3333660
370 Kind Elapsed(s) L1-op miss(%) L2 miss(%) L2 dm miss(%) L2 pf miss(%) mTLB-op(%)
371 ---
372 AVG 1.2669
9.1565 0.0917
57.9636 42.0364 0.3220 eval 0
373 MAX 1.3076 9.2694 0.0918 58.1835 42.2563 0.4249
374 MIN 1.2261 9.0437 0.0916 57.7437 41.8165 0.2190
目安
•
L1Dミス率
•
単精度ストリーム
3.125
%
•
倍精度ストリーム
6.25
%
•
L2ミス率
•
0
%台が理想
•
データアクセスパターンを見極める
•
使用されている配列サイズを把握する
•
ループ回転に伴って配列にどうアクセスするかを把握する
•
チューニング
•
多重ループの順番入れ替え
•
連続アクセスになるようにする
•
キャッシュブロッキング
•
セクタキャッシュの活用(京)
キャッシュミス率が高い時は
…
113 2 for (jj = 0; jj < jnum; jj++) {
114 2 j =
jlist[jj]
;
115 i 2 factor_lj = special_lj[
sbmask(j)
];
116 2 j &= NEIGHMASK;
117
118 2 delx = xtmp -‐
x[j].x
;
119 2 dely = ytmp -‐
x[j].y
;
120 2 delz = ztmp -‐
x[j].z
;
121 2 rsq = delx*delx + dely*dely + delz*delz;
122 2 jtype =
type[j]
;
123
124 2 if (rsq <
cutsqi[jtype]
) {
125 2 r2inv = 1.0/rsq;
126 2 r6inv = r2inv*r2inv*r2inv;
127 2 forcelj = r6inv * (
lj1i[jtype]
*r6inv -‐
lj2i[jtype]
);
128 2 fpair = factor_lj*forcelj*r2inv;
129
130 2 fxtmp += delx*fpair;
131 2 fytmp += dely*fpair;
132 2 fztmp += delz*fpair;
133 2 if (NEWTON_PAIR || j < nlocal) {
134 2
f[j].x
-‐= delx*fpair;
135 2
f[j].y
-‐= dely*fpair;
136 2
f[j].z
-‐= delz*fpair;
jjのループだが、配列にはjでアクセスする間接参照になっている
→
キャッシュの活用が出来ずプリフェッチもうまく働かない
アクセスパターンを確認する
MPI通信性能を見る
53 MPI profile 54 55 ************************************************************************************* 56 Application 57 ************************************************************************************* 5859 Kind Elapsed(s) Wait(s) Byte Call ( 0-‐4K 4K-‐64K 64K-‐1024K 1024KByte-‐)
60 -‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐ 61 2.5639 0.1392 -‐-‐-‐-‐ 3088 1410 20 1637 21 all 0 62 -‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐ 63 AVG 0.9362 0.0000 0.0000 3.0000 3.0000 0.0000 0.0000 0.0000 MPI::Comm::Barrier 64 MAX 1.8723 0.0000 0.0000 3 3 0 0 0 65 MIN 0.0001 0.0000 0.0000 3 3 0 0 0 66 -‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐ 67 AVG 0.0431 0.0418 14.7231 65.0000 65.0000 0.0000 0.0000 0.0000 MPI::Comm::Bcast 68 MAX 0.0443 0.0437 19.6308 65 65 0 0 0 69 MIN 0.0418 0.0400 9.8154 65 65 0 0 0 70 -‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐-‐ 71 AVG 0.0293 0.0278 13.6716 134.0000 134.0000 0.0000 0.0000 0.0000 MPI::Comm::Allreduce 72 MAX 0.0558 0.0540 13.6716 134 134 0 0 0 73 MIN 0.0029 0.0015 13.6716 134 134 0 0 0