計算科学特論B
第5回
アプリケーションの性能最適化の実例2
JAXA 熊畑清
2022.5.19(⽊)
2
講義の概要
• 4⽉7⽇ スーパーコンピュータとアプリケーションの性能
• 4⽉14⽇ アプリケーションの性能最適化1(⾼並列性能最適化)
• 4⽉21⽇ アプリケーションの性能最適化の実例1とCPU単体性能
• 5⽉12⽇ アプリケーションの性能最適化2(CPU単体性能最適化)
• 5⽉19⽇ アプリケーションの性能最適化の実例2
3
本⽇の内容
• 流体解析ソルバー FrontFlow/blue
• キャッシュ利⽤効率の改善・スレッド並列化の⽅法の⼯夫
• ストアのシーケンシャル化
• ストリーム削減・セクタキャッシュ・プリフェッチ
• 乱流燃焼コード LS-FLOW-HO
• インライン展開のやり過ぎに注意
• ⼩回転ループはさけたい
• OpenMPのスケジュール調整
• 重複した処理の回避
• 配列初期化時の性能劣化
• その他Tips
• なるべく⻑いループでSIMDに
• Z-Fillの効果
• ifを含むループはリストベクトル化
• 多次元配列の配列初期化
流体解析ソルバーFrontFlow/blue
キャッシュ利⽤効率の改善
スレッド並列化の⽅法の⼯夫
4
5
FrontFlow/blue
• FrontFlow/blue (FFB) は非圧縮性流れシミュレー
ションコード
• 東京大学生産技術研究所によって開発され、
パソコンから各種スパコンで利用可能
Developed by
• 有限要素法、分離解法、LES(Large Eddy
Simulation)に基づく
• 超並列スーパーコンピュータで高い並列性能を
持っている
• 産業界で重要なアプリで、京や富岳開発プロ
ジェクトにおける重要アプリとして選定
• 数万プロセスのオーダーで高い並列性能
• 京での単体性能チューニングを実施
6
チューニング対象カーネル
• 10万個の4⾯体要素+α
• 14.11s(30%)が4⾯体要素の勾配計算
• 13.04s(27%)が疎⾏列ベクトル積
• 8.32s(17%)が4⾯体要素の発散計算
• Callap._PRL_2_のチューニングを実施
要素圧⼒モードでの処理時間内訳,上位10件
14.11
13.04
8.32
4.83
2.95
2.10
1.89
callap._PRL_2_
calaxc_
fild3x._PRL_1_
callap_
vel3d1._PRL_16_
int3dx_
callap._PRL_5_
vel3d1._PRL_8_
vel3d1_
nodlex_
全体
#$%#$
単位( 秒
圧⼒
速度
速度
速度
速度・圧⼒
速度・圧⼒
速度・圧⼒
要素圧⼒モード 節点圧⼒モード
7
チューニング対象カーネル
å
= ¶
¶
@
¶
¶
=
Ñ
1
j
e
i
j
i
p
x
N
x
p
p
4⾓形要素について∇pの有限要素近似
を計算するループ
型 配列名とサイズ 内容
INTEGER*4 NODE(9,NE) 節点リスト
REAL*4 S(NE) 圧⼒
REAL*4
DNX(9,NE), DNY(9,NE),
DNZ(9,NE)
形状関数の導関数
REAL*4 FX(NP), FY(NP), FZ(NP) 圧⼒勾配ベクトル
DO ICOLOR=1,NCOLOR(1)
IES=LLOOP(ICOLOR ,1)+1
IEE=LLOOP(ICOLOR+1,1)
DO IE=IES,IEE・・・・・・・ここで並列
IP1=NODE(1,IE)
IP2=NODE(2,IE)
IP3=NODE(3,IE)
IP4=NODE(4,IE)
SWRK=S(IE)
FX(IP1)=FX(IP1)-SWRK*DNX(1,IE)
FX(IP2)=FX(IP2)-SWRK*DNX(2,IE)
FX(IP3)=FX(IP3)-SWRK*DNX(3,IE)
FX(IP4)=FX(IP4)-SWRK*DNX(4,IE)
FY(IP1)=FY(IP1)-SWRK*DNY(1,IE)
FY(IP2)=FY(IP2)-SWRK*DNY(2,IE)
FY(IP3)=FY(IP3)-SWRK*DNY(3,IE)
FY(IP4)=FY(IP4)-SWRK*DNY(4,IE)
FZ(IP1)=FZ(IP1)-SWRK*DNZ(1,IE)
FZ(IP2)=FZ(IP2)-SWRK*DNZ(2,IE)
FZ(IP3)=FZ(IP3)-SWRK*DNZ(3,IE)
FZ(IP4)=FZ(IP4)-SWRK*DNZ(4,IE)
ENDDO
ENDDO
8
チューニング対象カーネル
DO ICOLOR=1,NCOLOR(1)
IES=LLOOP(ICOLOR ,1)+1
IEE=LLOOP(ICOLOR+1,1)
DO IE=IES,IEE・・・・・・・ここで並列
IP1=NODE(1,IE)
IP2=NODE(2,IE)
IP3=NODE(3,IE)
IP4=NODE(4,IE)
SWRK=S(IE)
FX(IP1)=FX(IP1)-SWRK*DNX(1,IE)
FX(IP2)=FX(IP2)-SWRK*DNX(2,IE)
FX(IP3)=FX(IP3)-SWRK*DNX(3,IE)
FX(IP4)=FX(IP4)-SWRK*DNX(4,IE)
FY(IP1)=FY(IP1)-SWRK*DNY(1,IE)
FY(IP2)=FY(IP2)-SWRK*DNY(2,IE)
FY(IP3)=FY(IP3)-SWRK*DNY(3,IE)
FY(IP4)=FY(IP4)-SWRK*DNY(4,IE)
FZ(IP1)=FZ(IP1)-SWRK*DNZ(1,IE)
FZ(IP2)=FZ(IP2)-SWRK*DNZ(2,IE)
FZ(IP3)=FZ(IP3)-SWRK*DNZ(3,IE)
FZ(IP4)=FZ(IP4)-SWRK*DNZ(4,IE)
ENDDO
ENDDO
FX(1) FX(2) FX(3)
FX(5) FX(6) FX(7)
S(4)*DNX(1,6) S(4)*DNX(2,6)
S(4)*DNX(4,6) S(4)*DNX(3,6)
FX(4)
FX(8)
S(4)*DNX(1,4) S(4)*DNX(2,4)
S(4)*DNX(4,4) S(4)*DNX(3,4)
S(4)*DNX(1,5) S(4)*DNX(2,5)
S(4)*DNX(4,5) S(4)*DNX(3,5)
å
= ¶
¶
@
¶
¶
=
Ñ
1
j
e
i
j
i
p
x
N
x
p
p
4⾓形要素について∇pの有限要素近似
を計算するループ
9
チューニング対象カーネル
DO ICOLOR=1,NCOLOR(1)
IES=LLOOP(ICOLOR ,1)+1
IEE=LLOOP(ICOLOR+1,1)
DO IE=IES,IEE・・・・・・・ここで並列
IP1=NODE(1,IE)
IP2=NODE(2,IE)
IP3=NODE(3,IE)
IP4=NODE(4,IE)
SWRK=S(IE)
FX(IP1)=FX(IP1)-SWRK*DNX(1,IE)
FX(IP2)=FX(IP2)-SWRK*DNX(2,IE)
FX(IP3)=FX(IP3)-SWRK*DNX(3,IE)
FX(IP4)=FX(IP4)-SWRK*DNX(4,IE)
FY(IP1)=FY(IP1)-SWRK*DNY(1,IE)
FY(IP2)=FY(IP2)-SWRK*DNY(2,IE)
FY(IP3)=FY(IP3)-SWRK*DNY(3,IE)
FY(IP4)=FY(IP4)-SWRK*DNY(4,IE)
FZ(IP1)=FZ(IP1)-SWRK*DNZ(1,IE)
FZ(IP2)=FZ(IP2)-SWRK*DNZ(2,IE)
FZ(IP3)=FZ(IP3)-SWRK*DNZ(3,IE)
FZ(IP4)=FZ(IP4)-SWRK*DNZ(4,IE)
ENDDO
ENDDO
1 5 2 6
9 13 10 14
3 7 4 8
11 15 12 16
カラーリングによりデータ依存が⽣ずる
要素を別のグループ(カラー)に分ける
1 5 2 6
9 13 10 14
3 7 4 8
11 15 12 16
要素(メッ
シュ)
11 15
12 16
9 13
10 14
1 5
2 6
3 7
4 8
配列 LLOOP/NODE/DNX〜Z
・・・
・・・
カラー1 カラー2
カラー3 カラー4
メモリ上配置
要素(メッシュ)
10
性能評価 要求バイト数の算出
配列FX,FY,FZ
• 配列NODEの値に依存するリストアクセス故にシーケンシャルではない
• 再利用性がある
• リストによって変化してしまい一概には算出できない
リストアクセス
FX(1) FX(2) FX(3)
FX(5) FX(6) FX(7)
S(4)*DNX(1,6) S(4)*DNX(2,6)
S(4)*DNX(4,6) S(4)*DNX(3,6)
FX(4)
FX(8)
S(4)*DNX(1,4) S(4)*DNX(2,4)
S(4)*DNX(4,4) S(4)*DNX(3,4)
S(4)*DNX(1,5) S(4)*DNX(2,5)
S(4)*DNX(4,5) S(4)*DNX(3,5)
DO IE=IES, IEE
IP1=NODE(1,IE)
IP2=NODE(2,IE)
IP3=NODE(3,IE)
IP4=NODE(4,IE)
FX(IP1)=FX(IP1)-SWRK*DNX(1,IE)
FX(IP2)=FX(IP2)-SWRK*DNX(2,IE)
FX(IP3)=FX(IP3)-SWRK*DNX(3,IE)
FX(IP4)=FX(IP4)-SWRK*DNX(4,IE)
ENDDO
IE=1 IE=2 IE=3
11
性能評価 要求バイト数の算出
配列FX,FY,FZ
• 配列NODEの値に依存するリストアクセス故にシーケンシャルではない
• 再利用性がある
• リストによって変化してしまい一概には算出できない
DO IE=IES, IEE
IP1=NODE(1,IE)
IP2=NODE(2,IE)
IP3=NODE(3,IE)
IP4=NODE(4,IE)
FX(IP1)=FX(IP1)-SWRK*DNX(1,IE)
FX(IP2)=FX(IP2)-SWRK*DNX(2,IE)
FX(IP3)=FX(IP3)-SWRK*DNX(3,IE)
FX(IP4)=FX(IP4)-SWRK*DNX(4,IE)
ENDDO
100
Elem
Elem
1 2
3 2
3
1
10 51
4
FX(100)
リストアクセス 再利⽤性
キャッシュ 4
IP1=NODE(1,IE)
FX(IP1)
終了か
YES
NO
IE=1 IE=2 IE=3 IE=4 IE=5 IE=ME
・・・・
1,3 10 5
n
25
2
全てこの範囲で収まる
のが理想的
最後
IE=IE+1
従って理論性能の算出に当たり,メモリプレッシャーはないと仮定する
12
性能評価 要求バイト数の算出
配列S
• 再内のループ変数IEに従い連続アクセス
• 再利用性はない
• 1回目のアクセスでキャッシュミスし1ライン分128Byteがメモリ
から転送される
• ループ1回転で4Byte、128Byteでは32回転を賄える
• メモリプレッシャーは32回転につき128Byte
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32
S(1)でキャッシュミス
・・・
・・・
↑
1ライン分128Byte=32個
S(32)まで1ラインで賄える
↑
DO IE=IES,IEE
・・・
SWRK=S(IE)
・・・
ENDDO
13
性能評価 要求バイト数の算出
配列NODE
• 再内のループ変数IEに従い規則的にアクセス
• 再利用性はない
• 1回目のアクセスでキャッシュミスし1ライン分128Byteがメモリ
から転送される
• 第1次元のサイズが9でありループ1回転で36Byte、128Byte
では3.56回転を賄える
• 32回転で9回ミスしメモリプレッシャーは32回転につき
1152Byte
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32
NODE(1,1)
・・・
・・・
NODE(1,2)
NODE(1,3) NODE(1,4)
↑ ↑
↓ ↓
INTEGER*4
NODE(9,NE)
DO IE=IES,IEE
IP1=NODE(1,IE)
IP2=NODE(2,IE)
IP3=NODE(3,IE)
IP4=NODE(4,IE)
ENDDO
14
性能評価 要求バイト数の算出
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32
・・・
・・・
DNX(5〜9,1)は使われない DNX(5〜9,2)は使われない
DNX(5〜9,3)は使われない
DNX(1,1) DNX(1,2)
↑ ↑
配列DNX, DNY, DNZ
• 第1次元のサイズが9であり配列NODEと同じ性質
• メモリプレッシャーは32回転につきそれぞれ1152Byte
INTEGER*4
NODE(9,NE)
DO IE=IES,IEE
・・DNX(1,IE)
・・DNX(2,IE)
・・DNX(3,IE)
・・DNX(4,IE)
ENDDO
NODE(1,3)
↓
NODE(1,4)
↓
使われないがメモリ帯域を使う分を考慮する必要
15
性能評価
• 要求バイト
128+1152+1152×3=4736Byte
• 浮動小数点演算数
32回転×24FLOP=768Flop
• B/F値は 4736/768=6.17
• STREAMベンチマークによる「京」の
実効メモリバンド幅は46.6GB/s
• 「京」の実効B/F値は46.6/128=0.36
• メモリバンド幅がネックとなり実効上
の性能上限は128GFLOPSの
0.36/6.17=5.83%
• 82万個の4⾯体要素
• マルチスレッドで1.6%
• メモリスループットは10.29GB/s
• メモリアクセス関連待ちが70%程度
• L1Dキャッシュミス率21%
• キャッシュ利⽤効率が悪い
0.0
1.0
2.0
3.0
4.0
5.0
1 2 3 4 5 6 7 8
Time
[s]
スレッド
命令実行
待ち
メモリアクセス関連待
ち
計算時間内訳
16
キャッシュの利⽤効率改善
• 配列FX, FY, FZへのアクセスには再利用性がある
• 常にオンキャッシュであると仮定(理想的)
• 実際の入力データでは再利用性はあるものの,幾何的に近い節点に,近い番号がつけ
られているとは限らない
1=NODE(1,IE)
18=NODE(2,IE)
40=NODE(3,IE)
75=NODE(4,IE)
・・・
FX( 1)=FX( 1)-SWRK*DNX(1,IE)
FX(18)=FX(18)-SWRK*DNX(2,IE)
FX(40)=FX(40)-SWRK*DNX(3,IE)
FX(75)=FX(75)-SWRK*DNX(4,IE)
要素1
1 18
75 40
節点
1
2
4
3
幾何的に近い節点には近い番号をつける必要
参照 #$$%&'' ()*&
FX( 1) + +
FX(75) ,-. ,
FX(40) /0. /
FX(18) .1 +
互いに遠い節点を参照(跳び)
キャッシュの利⽤効効率が悪い
17
キャッシュの利⽤効率改善
• 幾何的に近い節点には近い番号をつける
• 行列・ベクトル席の前処理として,バンド幅の縮小や,直説法を用いる際のFill-inの抑
制を目的として行や列の並びを変更する手法
• Minimum Degree法, Nested Dissection法, グラフ理論を応用した方法など
• 行列を作らずに要素毎に計算する実装なため行や列の並べ替え操作は,節点の番
号を入れ替えることに相当
椃
Z
Y
棑 棒 棓
棖
棙
10 11 '
(
Object
Axial-Aligned Bounding Box (AABB)
①
③
⑥
⑨
⑪
外
中
11
10
1 2 3
4
5
18
キャッシュの利⽤効率改善
椃
Z
Y
棑 棒 棓
棖
棙
10 11 '
(
Object
Axial-Aligned Bounding Box (AABB)
①
①
⑥
⑨
⑪
外
中
11
10
1 2 3
4
5
• 幾何的に近い節点には近い番号をつける
• 行列・ベクトル席の前処理として,バンド幅の縮小や,直説法を用いる際のFill-inの抑
制を目的として行や列の並びを変更する手法
• Minimum Degree法, Nested Dissection法, グラフ理論を応用した方法など
• 行列を作らずに要素毎に計算する実装なため行や列の並べ替え操作は,節点の番
号を入れ替えることに相当
19
キャッシュの利⽤効率改善
椃
Z
Y
棑 棒 棓
棖
棙
10 11 '
(
Object
Axial-Aligned Bounding Box (AABB)
①
①
②
⑨
⑪
外
中
11
10
1 2 3
4
5
• 幾何的に近い節点には近い番号をつける
• 行列・ベクトル席の前処理として,バンド幅の縮小や,直説法を用いる際のFill-inの抑
制を目的として行や列の並びを変更する手法
• Minimum Degree法, Nested Dissection法, グラフ理論を応用した方法など
• 行列を作らずに要素毎に計算する実装なため行や列の並べ替え操作は,節点の番
号を入れ替えることに相当
20
キャッシュの利⽤効率改善
椃
Z
Y
棑 棒 棓
棖
棙
10 11 '
(
Object
Axial-Aligned Bounding Box (AABB)
①
①
②
③
⑪
外
中
11
10
1 2 3
4
5
• 幾何的に近い節点には近い番号をつける
• 行列・ベクトル席の前処理として,バンド幅の縮小や,直説法を用いる際のFill-inの抑
制を目的として行や列の並びを変更する手法
• Minimum Degree法, Nested Dissection法, グラフ理論を応用した方法など
• 行列を作らずに要素毎に計算する実装なため行や列の並べ替え操作は,節点の番
号を入れ替えることに相当
21
キャッシュの利⽤効率改善
椃
Z
Y
棑 棒 棓
棖
棙
10 11 '
(
Object
Axial-Aligned Bounding Box (AABB)
④
①
②
③
⑪
外
中
11
10
1 2 3
4
5
• 幾何的に近い節点には近い番号をつける
• 行列・ベクトル席の前処理として,バンド幅の縮小や,直説法を用いる際のFill-inの抑
制を目的として行や列の並びを変更する手法
• Minimum Degree法, Nested Dissection法, グラフ理論を応用した方法など
• 行列を作らずに要素毎に計算する実装なため行や列の並べ替え操作は,節点の番
号を入れ替えることに相当
22
キャッシュの利⽤効率改善
椃
Z
Y
棑 棒 棓
棖
棙
10 11 '
(
Object
Axial-Aligned Bounding Box (AABB)
④
①
②
③
⑤
外
中
11
10
1 2 3
4
5
• 幾何的に近い節点には近い番号をつける
• 行列・ベクトル席の前処理として,バンド幅の縮小や,直説法を用いる際のFill-inの抑
制を目的として行や列の並びを変更する手法
• Minimum Degree法, Nested Dissection法, グラフ理論を応用した方法など
• 行列を作らずに要素毎に計算する実装なため行や列の並べ替え操作は,節点の番
号を入れ替えることに相当
23
キャッシュの利⽤効率改善
• 幾何的に近い節点に近い番号がつけられた
• 幾何的に近い節点の情報が,メモリ上でも近い位置になるようにメモリ上でソートして
おく
リオーダリング
節点○の配置
直⽅体1 直⽅体2
7
5 8
6 11
9 10
3
1 4
2
⑦
⑤ ⑧
⑥ ⑪
⑨ ⑩
③
① ④
②
7
5 8
6 11
9 10
3
1 4
2
⑧
⑤ ⑨
② ⑥
③ ⑪
①
④ ⑦
⑩
7
5 8
6 11
9 10
3
1 4
2
節点情報
index
節点情報
index
節点情報
index
節点の情報を保持する配列の並び
番号の付け直しと
メモリ上でのソート
幾何的に近い節点で
もメモリ上は遠い
幾何的に近い節点は
メモリ上でも近い
②
⑩
①
③
④
⑤
⑥ ⑦
⑧
⑨
⑪
④
①
⑦
⑤
② ⑨
⑧
③
⑥
⑩
⑪
① ② ③
④ ⑤ ⑥
⑦ ⑧ ⑨
⑩ ⑪
① ② ③ ④ ⑤ ⑥ ⑦ ⑧ ⑨ ⑩ ⑪
24
Appendix) リオーダーの効果
4面体要素 6面体要素
同じアプリFrontFlow/blueの別部分
図は、横軸がループの回転、縦軸が、そのループで
アクセスする配列インデックスを⽰したもの
DO I=1,N
IDX=LIST(I)
V=ARRAY(IDX)
・・・
ENDDO
Before
※一部抜粋
25
Appendix) リオーダーの効果
4面体要素 6面体要素
同じアプリFrontFlow/blueの別部分
図は、横軸がループの回転、縦軸が、そのループで
アクセスする配列インデックスを⽰したもの
ICRS=1〜5M
After
DO I=1,N
IDX=LIST(I)
V=ARRAY(IDX)
・・・
ENDDO
26
Appendix) リオーダーの効果
同じアプリFrontFlow/blueの別部分
Before(6⾯体) After(6⾯対)
スレッド0
スレッド1
スレッド2
スレッド3
スレッド4
27
スレッド並列化の⽅法の⼯夫
• 要素のカラーリング領域全体で行っているので,最内ループで中には幾何的に遠い
要素が出現する
• 参照する節点がメモリ上でも遠い位置あり不利
メッシュ カラーリング
要素1個
28
スレッド並列化の⽅法の⼯夫
• 要素のカラーリング領域全体で行っているので,最内ループで中には幾何的に遠い
要素が出現する
• 参照する節点がメモリ上でも遠い位置あり不利
カラーリング
最内ループ1単位分
5 6
9 10
1 2
7
11
3
8
12
4
13 14 15 16
29
スレッド並列化の⽅法の⼯夫
カラー内に含まれる要素を,幾何的に近いものにする必要
• 要素のカラーリング領域全体で行っているので,最内ループで中には幾何的に遠い
要素が出現する
• 参照する節点がメモリ上でも遠い位置あり不利
最内ループ1単位分
5 6
9 10
1 2
7
11
3
8
12
4
13 14 15 16
・
・
・
メモリ
上
・
・
・
キャッシュから外れる可能性
30
スレッド並列化の⽅法の⼯夫
• カラー内に含まれる要素を,幾何的に
近いものにする
• ブロックで動くループが追加
DO IBLOCK=1,NBLOCK(1)
DO ICOLOR=1,NCOLOR(IBLOCK,1)
IES=LLOOP(IBLOCK,ICOLOR ,1)+1
IEE=LLOOP(IBLOCK,ICOLOR+1,1)
DO IE=IES,IEE・・・・・・・ここで並列
IP1=NODE(1,IE)
IP2=NODE(2,IE)
IP3=NODE(3,IE)
IP4=NODE(4,IE)
SWRK=S(IE)
FX(IP1)=FX(IP1)-SWRK*DNX(1,IE)
FX(IP2)=FX(IP2)-SWRK*DNX(2,IE)
FX(IP3)=FX(IP3)-SWRK*DNX(3,IE)
FX(IP4)=FX(IP4)-SWRK*DNX(4,IE)
FY(IP1)=FY(IP1)-SWRK*DNY(1,IE)
FY(IP2)=FY(IP2)-SWRK*DNY(2,IE)
FY(IP3)=FY(IP3)-SWRK*DNY(3,IE)
FY(IP4)=FY(IP4)-SWRK*DNY(4,IE)
FZ(IP1)=FZ(IP1)-SWRK*DNZ(1,IE)
FZ(IP2)=FZ(IP2)-SWRK*DNZ(2,IE)
FZ(IP3)=FZ(IP3)-SWRK*DNZ(3,IE)
FZ(IP4)=FZ(IP4)-SWRK*DNZ(4,IE)
ENDDO
ENDDO
ENDDO
1ノード分の
計算領域
R B R
R B R
G Y G
カラーリング
□ は要素1個
□ はブロック1個
ブロック化
31
スレッド並列化の⽅法の⼯夫
IP1=NODE(1,IE)
IP2=NODE(2,IE)
IP3=NODE(3,IE)
IP4=NODE(4,IE)
SWRK=S(IE)
FX(IP1)=FX(IP1)-SWRK*DNX(1,IE)
FX(IP2)=FX(IP2)-SWRK*DNX(2,IE)
FX(IP3)=FX(IP3)-SWRK*DNX(3,IE)
FX(IP4)=FX(IP4)-SWRK*DNX(4,IE)
FY(IP1)=FY(IP1)-SWRK*DNY(1,IE)
FY(IP2)=FY(IP2)-SWRK*DNY(2,IE)
FY(IP3)=FY(IP3)-SWRK*DNY(3,IE)
FY(IP4)=FY(IP4)-SWRK*DNY(4,IE)
FZ(IP1)=FZ(IP1)-SWRK*DNZ(1,IE)
FZ(IP2)=FZ(IP2)-SWRK*DNZ(2,IE)
FZ(IP3)=FZ(IP3)-SWRK*DNZ(3,IE)
FZ(IP4)=FZ(IP4)-SWRK*DNZ(4,IE)
ケースNo
ブロック
分割数
平均要素数/
ブロック
アクセスデー
タ量 [KB]
1スレッド当り
メモリ [KB]
on L1 on L2
1 640 1291 247.1 30.9 ○ ○
2 320 2583 494.4 61.8 × ○
3 160 5166 988.8 123.6 × ○
4 80 10333 1977.8 247.2 × ○
5 40 20666 3955.6 494.5 × ○
6 20 41332 7911.2 988.9 × ×
7 10 82665 15822.6 1977.8 × ×
8 5 165331 31645.4 3955.7 × ×
9 3 275552 52742.4 6592.8 × ×
10 2 413328 79113.6 9889.2 × ×
11 1 826656 158227.1 19778.4 × ×
1
10
100
1000
10000
100000
1000000
1000 10000 100000 1000000
アクセスデータ量
[KB]
平均要素数/ブロック (対数表示)
1要素当たりの必要メモリ量
NODE(1〜9, IE)
36バイト
S(IE)→4バイト
DNX(1-9,IE)
36バイト
DNY(1-9,IE)
36バイト
DNZ(1-9,IE)
36バイト
FX(IP1〜IP4)
FY(IP1〜IP4)
FZ(IP1〜IP4)
48バイト
196バイト/要素
ブロック当たりに
アクセスするデータ量
ブロックの大きさ(含む要素数)について検討
32
スレッド並列化の⽅法の⼯夫
100
1
88
301
アクセスの跳び
=301-1=300
0
10000
20000
30000
40000
1000 10000 100000 1000000
インデックスの飛び
平均要素数/ブロック (対数表示)
!"!!#
!"$!#
%"!!#
%"$!#
&"!!#
%!!! %!!!! %!!!!! %!!!!!!
'()*+,
#
-./012345) 67189:
ピーク性能⽐
ブロックの大きさ(含む要素数)について検討
33
スレッド並列化の⽅法の⼯夫
ケースNo
ブロック
分割数
平均要素数/
ブロック
平均カラー数
/ブロック
平均要素数/
カラー
平均最内回
転数/スレッド
1 640 1291 37.4 34.0 4
2 320 2583 38.7 66.0 8
3 160 5166 39.7 130.0 16
4 80 10333 41.0 252.0 32
5 40 20666 41.5 498.0 62
6 20 41332 42.1 981.0 123
7 10 82665 42.2 1958.0 245
8 5 165331 42.6 3881.0 485
9 3 275552 43.7 6310.0 789
10 2 413328 43.5 9501.0 1188
11 1 826656 44.0 18787.0 2348
ブロックの大きさ(含む要素数)について検討
0
500
1000
1500
2000
2500
1000 10000 100000 1000000
平均最内回転数/スレッド
平均要素数/ブロック (対数表示)
最内ループ回転数が⼩さ
くなりすぎた
回転数不⾜の回避が必要
最内ループ平均回転数/スレッド
34
スレッド並列化の⽅法の⼯夫
DO ICOLOR=1,NCOLOR(1)
DO IBLOCK=1,NBLOCK(IBLOCK,1)
IES=LLOOP(IBLOCK,ICOLOR ,1)+1
IEE=LLOOP(IBLOCK,ICOLOR+1,1)
DO IE=IES,IEE
IP1=NODE(1,IE)
IP2=NODE(2,IE)
IP3=NODE(3,IE)
IP4=NODE(4,IE)
SWRK=S(IE)
FX(IP1)=FX(IP1)-SWRK*DNX(1,IE)
FX(IP2)=FX(IP2)-SWRK*DNX(2,IE)
FX(IP3)=FX(IP3)-SWRK*DNX(3,IE)
FX(IP4)=FX(IP4)-SWRK*DNX(4,IE)
FY(IP1)=FY(IP1)-SWRK*DNY(1,IE)
FY(IP2)=FY(IP2)-SWRK*DNY(2,IE)
FY(IP3)=FY(IP3)-SWRK*DNY(3,IE)
FY(IP4)=FY(IP4)-SWRK*DNY(4,IE)
FZ(IP1)=FZ(IP1)-SWRK*DNZ(1,IE)
FZ(IP2)=FZ(IP2)-SWRK*DNZ(2,IE)
FZ(IP3)=FZ(IP3)-SWRK*DNZ(3,IE)
FZ(IP4)=FZ(IP4)-SWRK*DNZ(4,IE)
ENDDO
ENDDO
ENDDO
1ノード分の
計算領域
カラーリン
グ
□ はブロック1個
ブロック化
• カラー内に含まれる要素を,幾何的に
近いものにする
• ブロックとカラーの関係を反転
35
スレッド並列化の⽅法の⼯夫
DO ICOLOR=1,NCOLOR(1)
DO IBLOCK=1,NBLOCK(IBLOCK,1) ここで並列
IES=LLOOP(IBLOCK,ICOLOR ,1)+1
IEE=LLOOP(IBLOCK,ICOLOR+1,1)
DO IE=IES,IEE
IP1=NODE(1,IE)
IP2=NODE(2,IE)
IP3=NODE(3,IE)
IP4=NODE(4,IE)
SWRK=S(IE)
FX(IP1)=FX(IP1)-SWRK*DNX(1,IE)
FX(IP2)=FX(IP2)-SWRK*DNX(2,IE)
FX(IP3)=FX(IP3)-SWRK*DNX(3,IE)
FX(IP4)=FX(IP4)-SWRK*DNX(4,IE)
FY(IP1)=FY(IP1)-SWRK*DNY(1,IE)
FY(IP2)=FY(IP2)-SWRK*DNY(2,IE)
FY(IP3)=FY(IP3)-SWRK*DNY(3,IE)
FY(IP4)=FY(IP4)-SWRK*DNY(4,IE)
FZ(IP1)=FZ(IP1)-SWRK*DNZ(1,IE)
FZ(IP2)=FZ(IP2)-SWRK*DNZ(2,IE)
FZ(IP3)=FZ(IP3)-SWRK*DNZ(3,IE)
FZ(IP4)=FZ(IP4)-SWRK*DNZ(4,IE)
ENDDO
ENDDO
ENDDO
1ノード分の
計算領域
□ はブロック1個
ブロック化
• カラー内に含まれる要素を,幾何的に
近いものにする
• ブロックとカラーの関係を反転
ブロックを
カラーリング
ブロックの
中には
複数の要素
36
スレッド並列化の⽅法の⼯夫
• 平均最内回転数/スレッド=323回転
• ピーク性能比3.78%
• L1Dミス率4%
• メモリスループット32GB/s
• 最内ループの回転数が38~44倍程度ま
で増大
• ブロックサイズ小の側で性能向上
• 最良の結果は平均最内回転数/スレッド
が323回転
1
10
100
1000
10000
100000
1000000
1000 10000 100000 1000000
平均最内回転数/スレッド
(対数表示)
平均要素数/ブロック (対数表示)
Before
After
最内ループ
平均回転数
0.00%
0.50%
1.00%
1.50%
2.00%
2.50%
3.00%
3.50%
4.00%
1000 10000 100000 1000000
ピーク性能比
%
平均要素数/ブロック (対数表示)
ピーク性能⽐
37
スレッド並列化の⽅法の⼯夫
ここまでのチューニングにより
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32
・・・
・・・
1ライン分128Byte=32個
S(32)まで1ラインで賄える
↑
オリジナル 改善後 理想値
ピーク性能⽐(%) 1.6 3.8 5.83
メモリスループット(GB/s) 10.3 32 46
L1Dキャッシュミス率(%) 21.0 3.78 3.13
もう少し改善の余地があるのでは?
4バイト変数の配列S(N)
32回に1回ミスするので1/32=3.125%が理論的なミス率
(ただし全てシーケンシャルな場合なので注意)
38
スレッド並列化の⽅法の⼯夫
配列融合によるストリーム削減 オリジナル
FX(1,IP1)=FX(1,IP1)-SWRK*DNX(1,IE)
FX(1,IP2)=FX(1,IP2)-SWRK*DNX(2,IE)
FX(1,IP3)=FX(1,IP3)-SWRK*DNX(3,IE)
FX(1,IP4)=FX(1,IP4)-SWRK*DNX(4,IE)
FY(2,IP1)=FY(2,IP1)-SWRK*DNY(1,IE)
FY(2,IP2)=FY(2,IP2)-SWRK*DNY(2,IE)
FY(2,IP3)=FY(2,IP3)-SWRK*DNY(3,IE)
FY(2,IP4)=FY(2,IP4)-SWRK*DNY(4,IE)
FZ(3,IP1)=FZ(3,IP1)-SWRK*DNZ(1,IE)
FZ(3,IP2)=FZ(3,IP2)-SWRK*DNZ(2,IE)
FZ(3,IP3)=FZ(3,IP3)-SWRK*DNZ(3,IE)
FZ(3,IP4)=FZ(3,IP4)-SWRK*DNZ(4,IE)
パターン1
FX(1,IP1)=FX(1,IP1)-SWRK*DNXYZ(1,IE)
FX(1,IP2)=FX(1,IP2)-SWRK*DNXYZ(2,IE)
FX(1,IP3)=FX(1,IP3)-SWRK*DNXYZ(3,IE)
FX(1,IP4)=FX(1,IP4)-SWRK*DNXYZ(4,IE)
FY(2,IP1)=FY(2,IP1)-SWRK*DNXYZ(1,IE)
FY(2,IP2)=FY(2,IP2)-SWRK*DNXYZ(2,IE)
FY(2,IP3)=FY(2,IP3)-SWRK*DNXYZ(3,IE)
FY(2,IP4)=FY(2,IP4)-SWRK*DNXYZ(4,IE)
FZ(3,IP1)=FZ(3,IP1)-SWRK*DNXYZ(1,IE)
FZ(3,IP2)=FZ(3,IP2)-SWRK*DNXYZ(2,IE)
FZ(3,IP3)=FZ(3,IP3)-SWRK*DNXYZ(3,IE)
FZ(3,IP4)=FZ(3,IP4)-SWRK*DNXYZ(4,IE)
パターン2
FXYZ(1,IP1)=FXYZ(1,IP1)-SWRK*DNX(1,IE)
FXYZ(1,IP2)=FXYZ(1,IP2)-SWRK*DNX(2,IE)
FXYZ(1,IP3)=FXYZ(1,IP3)-SWRK*DNX(3,IE)
FXYZ(1,IP4)=FXYZ(1,IP4)-SWRK*DNX(4,IE)
FXYZ(2,IP1)=FXYZ(2,IP1)-SWRK*DNY(1,IE)
FXYZ(2,IP2)=FXYZ(2,IP2)-SWRK*DNY(2,IE)
FXYZ(2,IP3)=FXYZ(2,IP3)-SWRK*DNY(3,IE)
FXYZ(2,IP4)=FXYZ(2,IP4)-SWRK*DNY(4,IE)
FXYZ(3,IP1)=FXYZ(3,IP1)-SWRK*DNZ(1,IE)
FXYZ(3,IP2)=FXYZ(3,IP2)-SWRK*DNZ(2,IE)
FXYZ(3,IP3)=FXYZ(3,IP3)-SWRK*DNZ(3,IE)
FXYZ(3,IP4)=FXYZ(3,IP4)-SWRK*DNZ(4,IE)
パターン3
FXYZ(1,IP1)=FXYZ(1,IP1)-SWRK*DNX(1,IE)
FXYZ(2,IP1)=FXYZ(2,IP1)-SWRK*DNY(1,IE)
FXYZ(3,IP1)=FXYZ(3,IP1)-SWRK*DNZ(1,IE)
FXYZ(1,IP2)=FXYZ(1,IP2)-SWRK*DNX(2,IE)
FXYZ(2,IP2)=FXYZ(2,IP2)-SWRK*DNY(2,IE)
FXYZ(3,IP2)=FXYZ(3,IP2)-SWRK*DNZ(2,IE)
FXYZ(1,IP3)=FXYZ(1,IP3)-SWRK*DNX(3,IE)
FXYZ(2,IP3)=FXYZ(2,IP3)-SWRK*DNY(3,IE)
FXYZ(3,IP3)=FXYZ(3,IP3)-SWRK*DNZ(3,IE)
FXYZ(1,IP4)=FXYZ(1,IP4)-SWRK*DNX(4,IE)
FXYZ(2,IP4)=FXYZ(2,IP4)-SWRK*DNY(4,IE)
FXYZ(3,IP4)=FXYZ(3,IP4)-SWRK*DNZ(4,IE)
パターン4
FXYZ(1,IP1)=FXYZ(1,IP1)-SWRK*DNXYZ(1,1,IE)
FXYZ(2,IP1)=FXYZ(2,IP1)-SWRK*DNXYZ(2,1,IE)
FXYZ(3,IP1)=FXYZ(3,IP1)-SWRK*DNXYZ(3,1,IE)
FXYZ(1,IP2)=FXYZ(1,IP2)-SWRK*DNXYZ(1,2,IE)
FXYZ(2,IP2)=FXYZ(2,IP2)-SWRK*DNXYZ(2,2,IE)
FXYZ(3,IP2)=FXYZ(3,IP2)-SWRK*DNXYZ(3,2,IE)
FXYZ(1,IP3)=FXYZ(1,IP3)-SWRK*DNXYZ(1,3,IE)
FXYZ(2,IP3)=FXYZ(2,IP3)-SWRK*DNXYZ(2,3,IE)
FXYZ(3,IP3)=FXYZ(3,IP3)-SWRK*DNXYZ(3,3,IE)
FXYZ(1,IP4)=FXYZ(1,IP4)-SWRK*DNXYZ(1,4,IE)
FXYZ(2,IP4)=FXYZ(2,IP4)-SWRK*DNXYZ(2,4,IE)
FXYZ(3,IP4)=FXYZ(3,IP4)-SWRK*DNXYZ(3,4,IE)
パターンNo
ピーク
性能比%
L1D
キャッシュ
ミス率%
メモリ
スルー
プット
GB/s
1 3.95 3.98 35.70
2 4.05 3.69 35.91
4 4.05 3.69 35.88
5 4.41 3.37 38.80
要求バイトが変わらないため、理論性能
は変化せず
パターンNo
1
2
3
4
DNX, DNY, DNZをDNXYZに融合
FX, FY, FZをFXYZに融合
パターン2+演算淳子変更
パターン3+パターン1
内容
オリジナル
FX(IP1)=FX(IP1)+SWRK*DNX(1,IE)
FY(IP1)=FY(IP1)+SWRK*DNY(1,IE)
FZ(IP1)=FZ(IP1)+SWRK*DNZ(1,IE)
パターン4
FXYZ(1,IP1)=FXYZ(1,IP1)+SWRK*DNXYZ(1,1,IE)
FXYZ(2,IP1)=FXYZ(2,IP1)+SWRK*DNXYZ(2,1,IE)
FXYZ(3,IP1)=FXYZ(3,IP1)+SWRK*DNXYZ(3,1,IE)
4
3
演算順序
39
スレッド並列化の⽅法の⼯夫
オリジナル
形状
• 矩形分割ではブロック間に要素数のイン
バランスが生ずる可能性
• 要素のブロック化にMETISを用いて様々
な形状にも対応
均等な要素
を含む複数
ブロックに
分割
各ブロックを
カラーリング
ブロック内には
たくさんの要素
!"!!#
$"!!#
%"!!#
&"!!#
'"!!#
("!!#
$!!! $!!!! $!!!!! $!!!!!!
)*+,-.
/
012345678+ 9:4;<=
ピーク性能⽐
ピーク性能⽐4.58%
L1Dミス率3.41%
メモリスループット
41.22GB/s
40
まとめ
ケース名 内容
ORG オリジナル
A
節点リナンバー,要素ブロック,
外側カラー化
B 配列融合
C ブロック化⼿法改善
0.0
1.0
2.0
3.0
4.0
5.0
ORG Sec.7 Sec.8 Sec.9
Time
[s]
命令実行
待&
'()*+,-関連待&
ORG C
B
A
0.0
1.0
2.0
3.0
4.0
5.0
1 2 3 4 5 6 7 8
Time
[s]
5
5.
L1
FX, FY, FZ
1
B/F
83%
17 3 FX, FY, FZ
IE
2/3
18 4
2
4.72 1.76 2.7
0.0
0.5
1.0
1.5
2.0
1 2 3 4 5 6 7 8
Time
[s]
(1,IP1)=FXYZ(1,IP1)-SWRK*DNXYZ(1,1,IE)
(2,IP1)=FXYZ(2,IP1)-SWRK*DNXYZ(2,1,IE)
(3,IP1)=FXYZ(3,IP1)-SWRK*DNXYZ(3,1,IE)
(1,IP2)=FXYZ(1,IP2)-SWRK*DNXYZ(1,2,IE)
(2,IP2)=FXYZ(2,IP2)-SWRK*DNXYZ(2,2,IE)
(3,IP2)=FXYZ(3,IP2)-SWRK*DNXYZ(3,2,IE)
YZ(1,IP1)=FXYZ(1,IP1)-SWRK*DNX(1,IE)
YZ(2,IP1)=FXYZ(2,IP1)-SWRK*DNY(1,IE)
YZ(3,IP1)=FXYZ(3,IP1)-SWRK*DNZ(1,IE)
YZ(1,IP2)=FXYZ(1,IP2)-SWRK*DNX(2,IE)
YZ(2,IP2)=FXYZ(2,IP2)-SWRK*DNY(2,IE)
YZ(3,IP2)=FXYZ(3,IP2)-SWRK*DNZ(2,IE)
YZ(1,IP3)=FXYZ(1,IP3)-SWRK*DNX(3,IE)
YZ(2,IP3)=FXYZ(2,IP3)-SWRK*DNY(3,IE)
YZ(3,IP3)=FXYZ(3,IP3)-SWRK*DNZ(3,IE)
YZ(1,IP4)=FXYZ(1,IP4)-SWRK*DNX(4,IE)
YZ(2,IP4)=FXYZ(2,IP4)-SWRK*DNY(4,IE)
YZ(3,IP4)=FXYZ(3,IP4)-SWRK*DNZ(4,IE)
流体解析ソルバーFrontFlow/blue
ストアのシーケンシャル化
41
42
チューニング対象ルーチン
33%
• メインループ(時間積分ループ)の内訳
• ⼊⼒データは単純な四⾓形の形状で,1プロセスあたり
100万要素
• 全体では24プロセスで,京で1ノード1プロセス,1プロ
セス8スレッド実⾏
• GRAD, DIV) 質量保存(ポアソン⽅程式)関係
• MOM, AXmult) 運動量関係
• CONV) データの変換
• COMM) 通信
• MISC) ⾊々雑多
• OTHER, 個別に扱えない細かいものの合計
⼀番重たいGRADを対象とする
43
チューニング対象カーネル
Ingredient of routine GRAD
Initialize array to zero
Element Wise Product of vector
(Hadamard Product)
i
i
i b
a
c =
Data Structure
Conversion
Main Calculation
A={a1, a2, …, an}
B={b1, b2, …, bn}
C={c1, c2, …, cn}
44
節点5 3
Elem.1
Pressure P1
Elem.2
Pressure P2
Elem3
Pressure P3
Elem.4
Pressure P4
Vertex1
1
5 4
2
Vertex 2
Vertex
3 Vertex
1
V
e
r
t
e
x
2
V
e
r
t
e
x
3
Vertex 3
Vertex 1
V
e
r
t
e
x
2
Vertex
1
V
e
r
t
e
x
3
Vertex
2
カーネル処理内容
44
DO iCOL=1,iNUM_COLOR
DO iBLK=1,iNUM_BLOCK(iCOL) Multi-Thread
iHEAD=iHEAD_ELEM(iBLK,iCOL)
iTAIL=iTAIL_ELEM(iBLK,iCOL)
DO iE=iHEAD, iTIAL
iN1=iNODE(1,iE)
iN2=iNODE(2,iE)
・・・
iN8=iNODE(8,iE)
fP=fPRES(iE)
fDP(1,iN1)+=fP*fDN(1,1,iE)
fDP(2,iN1)+=fP*fDN(2,1,iE)
fDP(3,iN1)+=fP*fDN(3,1,iE)
fDP(1,iN2)+=fP*fDN(1,2,iE)
fDP(2,iN2)+=fP*fDN(2,2,iE)
fDP(3,iN2)+=fP*fDN(3,2,iE)
・・・
fDP(1,iN8)+=fP*fDN(1,8,iE)
fDP(2,iN8)+=fP*fDN(2,8,iE)
fDP(3,iN8)+=fP*fDN(3,8,iE)
ENDDO
ENDDO
ENDDO
1
2
3
4
5
6
7
・・・
13
14
15
16
17
18
19
20
21
22
・・・
44
45
46
47
48
49
この節点は
要素1の頂点3
要素2の頂点1
要素3の頂点2
要素4の頂点1
中央の節点における圧⼒勾配は以下の計算となる
Ni,j は有限要素法の形状関数で,要素iの頂点jごと定義されてい
る,たとえば,N3,1 と N4,2 は⼀⾒同じ位置にあるが,違うもの
前ページの事例の最終状態(のすこし違うVer)
45
データ構造
Region
1 5 2 6
9 13 10 14
3 7 4 8
11 15 12 16
Colored
Elements
Elements were sorted and renumbered in data
Red
1 2 3 100
… 101 102 103 200
… 120112021203 1300
…
401 402 403 500
… 801 802 803 900
…
… … …
Green Blue Yellow
…
Blk.1 Blk.2 Blk.5 Blk.9 Blk.13
Blocked
iHEAD iTAIL
for
Blk.1
for
Blk.1
Elements
46
性能評価
前ページの事例と同じように,B/Fから理想的な性能を
求めると京では13% (16.7GFLOPS/NODE)出るとの⾒積
⾒積⽅法)
最内ループ1回転,つまり1要素当たり132Byte使う.⼀⽅演算量は48FLOPなので
B/F=132/48=2.75
実効のメモリバンド幅はストリームベンチマークから46GB.演算性能は128GFLOPS/ノー
ドなので,B/Fの上限はB/F=46/128=0.36
その⽐から 0.36/2.75=13%
Runnig Time 91.5 sec
Performance 6.6 GFLOPS
Ratio to 128GFLOPS 5.2 %
Memory throughput 26.8 GB/S
Peak value is 46GB/s by STREAM bench.
47
何がボトルネックか︖
þ
ý
ü
î
í
ì
¶
¶
¶
¶
=
+
Ñ 1
1
,
1
1
1
,
1
1 , P
y
N
P
x
N
P
þ
ý
ü
î
í
ì
¶
¶
¶
¶
=
+
Ñ 1
2
,
1
1
2
,
1
2 , P
y
N
P
x
N
P
þ
ý
ü
î
í
ì
¶
¶
¶
¶
=
+
Ñ 1
3
,
1
1
3
,
1
3 , P
y
N
P
x
N
P
Vertex 1
①For Elem.1
Vertex 2
Vertex 3
þ
ý
ü
î
í
ì
¶
¶
¶
¶
=
+
Ñ 2
2
,
2
2
2
,
2
2 , P
y
N
P
x
N
P
②For Elem.2
þ
ý
ü
î
í
ì
¶
¶
¶
¶
=
+
Ñ 2
1
,
2
2
1
,
2
3 , P
y
N
P
x
N
P
þ
ý
ü
î
í
ì
¶
¶
¶
¶
=
+
Ñ 2
3
,
2
2
3
,
2
4 , P
y
N
P
x
N
P
þ
ý
ü
î
í
ì
¶
¶
¶
¶
=
+
Ñ 4
2
,
4
4
2
,
4
5 , P
y
N
P
x
N
P
④For Elem.4
þ
ý
ü
î
í
ì
¶
¶
¶
¶
=
+
Ñ 4
1
,
4
4
1
,
4
3 , P
y
N
P
x
N
P
þ
ý
ü
î
í
ì
¶
¶
¶
¶
=
+
Ñ 4
3
,
4
4
3
,
4
1 , P
y
N
P
x
N
P
③For Elem.3
・・・略・・・
プロファイラで実⾏時間内訳をみてみると
• メモリアクセス待ち時間が多かった
• ストア命令がたくさん出ていた
ストアが多かった理由
• ひとつの節点を複数の要素で共有していて,違う
タイミングで同じ節点に何度もストアされる
節点への⾜しこみ(A=A+B)があるので
• SIMDとソフトウェアパイプラインが出来ない
節点5 3
Elem.1
Pressure P1
Elem.2
Pressure P2
Elem3
Pressure P3
Elem.4
Pressure P4
Vertex1
1
5 4
2
Vertex 2
Vertex
3 Vertex
1
V
e
r
t
e
x
2
V
e
r
t
e
x
3
Vertex 3
Vertex 1
V
e
r
t
e
x
2
Vertex
1
V
e
r
t
e
x
3
Vertex
2
48
何がボトルネックか︖
þ
ý
ü
î
í
ì
¶
¶
¶
¶
=
+
Ñ 1
1
,
1
1
1
,
1
1 , P
y
N
P
x
N
P
þ
ý
ü
î
í
ì
¶
¶
¶
¶
=
+
Ñ 1
2
,
1
1
2
,
1
2 , P
y
N
P
x
N
P
þ
ý
ü
î
í
ì
¶
¶
¶
¶
=
+
Ñ 1
3
,
1
1
3
,
1
3 , P
y
N
P
x
N
P
Vertex 1
①For Elem.1
Vertex 2
Vertex 3
þ
ý
ü
î
í
ì
¶
¶
¶
¶
=
+
Ñ 2
2
,
2
2
2
,
2
2 , P
y
N
P
x
N
P
②For Elem.2
þ
ý
ü
î
í
ì
¶
¶
¶
¶
=
+
Ñ 2
1
,
2
2
1
,
2
3 , P
y
N
P
x
N
P
þ
ý
ü
î
í
ì
¶
¶
¶
¶
=
+
Ñ 2
3
,
2
2
3
,
2
4 , P
y
N
P
x
N
P
þ
ý
ü
î
í
ì
¶
¶
¶
¶
=
+
Ñ 4
2
,
4
4
2
,
4
5 , P
y
N
P
x
N
P
④For Elem.4
þ
ý
ü
î
í
ì
¶
¶
¶
¶
=
+
Ñ 4
1
,
4
4
1
,
4
3 , P
y
N
P
x
N
P
þ
ý
ü
î
í
ì
¶
¶
¶
¶
=
+
Ñ 4
3
,
4
4
3
,
4
1 , P
y
N
P
x
N
P
③For Elem.3
・・・略・・・
節点5 3
Elem.1
Pressure P1
Elem.2
Pressure P2
Elem3
Pressure P3
Elem.4
Pressure P4
Vertex1
1
5 4
2
Vertex 2
Vertex
3 Vertex
1
V
e
r
t
e
x
2
V
e
r
t
e
x
3
Vertex 3
Vertex 1
V
e
r
t
e
x
2
Vertex
1
V
e
r
t
e
x
3
Vertex
2
プロファイラで実⾏時間内訳をみてみると
• メモリアクセス待ち時間が多かった
• ストア命令がたくさん出ていた
ストアが多かった理由
• ひとつの節点を複数の要素で共有していて,違う
タイミングで同じ節点に何度もストアされる
節点への⾜しこみ(A=A+B)があるので
• SIMDとソフトウェアパイプラインが出来ない
49
何がボトルネックか︖
þ
ý
ü
î
í
ì
¶
¶
¶
¶
=
+
Ñ 1
1
,
1
1
1
,
1
1 , P
y
N
P
x
N
P
þ
ý
ü
î
í
ì
¶
¶
¶
¶
=
+
Ñ 1
2
,
1
1
2
,
1
2 , P
y
N
P
x
N
P
þ
ý
ü
î
í
ì
¶
¶
¶
¶
=
+
Ñ 1
3
,
1
1
3
,
1
3 , P
y
N
P
x
N
P
Vertex 1
①For Elem.1
Vertex 2
Vertex 3
þ
ý
ü
î
í
ì
¶
¶
¶
¶
=
+
Ñ 2
2
,
2
2
2
,
2
2 , P
y
N
P
x
N
P
②For Elem.2
þ
ý
ü
î
í
ì
¶
¶
¶
¶
=
+
Ñ 2
1
,
2
2
1
,
2
3 , P
y
N
P
x
N
P
þ
ý
ü
î
í
ì
¶
¶
¶
¶
=
+
Ñ 2
3
,
2
2
3
,
2
4 , P
y
N
P
x
N
P
þ
ý
ü
î
í
ì
¶
¶
¶
¶
=
+
Ñ 4
2
,
4
4
2
,
4
5 , P
y
N
P
x
N
P
④For Elem.4
þ
ý
ü
î
í
ì
¶
¶
¶
¶
=
+
Ñ 4
1
,
4
4
1
,
4
3 , P
y
N
P
x
N
P
þ
ý
ü
î
í
ì
¶
¶
¶
¶
=
+
Ñ 4
3
,
4
4
3
,
4
1 , P
y
N
P
x
N
P
③For Elem.3
・・・略・・・
節点5 3
Elem.1
Pressure P1
Elem.2
Pressure P2
Elem3
Pressure P3
Elem.4
Pressure P4
Vertex1
1
5 4
2
Vertex 2
Vertex
3 Vertex
1
V
e
r
t
e
x
2
V
e
r
t
e
x
3
Vertex 3
Vertex 1
V
e
r
t
e
x
2
Vertex
1
V
e
r
t
e
x
3
Vertex
2
プロファイラで実⾏時間内訳をみてみると
• メモリアクセス待ち時間が多かった
• ストア命令がたくさん出ていた
ストアが多かった理由
• ひとつの節点を複数の要素で共有していて,違う
タイミングで同じ節点に何度もストアされる
節点への⾜しこみ(A=A+B)があるので
• SIMDとソフトウェアパイプラインが出来ない
50
何がボトルネックか︖
þ
ý
ü
î
í
ì
¶
¶
¶
¶
=
+
Ñ 1
1
,
1
1
1
,
1
1 , P
y
N
P
x
N
P
þ
ý
ü
î
í
ì
¶
¶
¶
¶
=
+
Ñ 1
2
,
1
1
2
,
1
2 , P
y
N
P
x
N
P
þ
ý
ü
î
í
ì
¶
¶
¶
¶
=
+
Ñ 1
3
,
1
1
3
,
1
3 , P
y
N
P
x
N
P
Vertex 1
①For Elem.1
Vertex 2
Vertex 3
þ
ý
ü
î
í
ì
¶
¶
¶
¶
=
+
Ñ 2
2
,
2
2
2
,
2
2 , P
y
N
P
x
N
P
②For Elem.2
þ
ý
ü
î
í
ì
¶
¶
¶
¶
=
+
Ñ 2
1
,
2
2
1
,
2
3 , P
y
N
P
x
N
P
þ
ý
ü
î
í
ì
¶
¶
¶
¶
=
+
Ñ 2
3
,
2
2
3
,
2
4 , P
y
N
P
x
N
P
þ
ý
ü
î
í
ì
¶
¶
¶
¶
=
+
Ñ 4
2
,
4
4
2
,
4
5 , P
y
N
P
x
N
P
④For Elem.4
þ
ý
ü
î
í
ì
¶
¶
¶
¶
=
+
Ñ 4
1
,
4
4
1
,
4
3 , P
y
N
P
x
N
P
þ
ý
ü
î
í
ì
¶
¶
¶
¶
=
+
Ñ 4
3
,
4
4
3
,
4
1 , P
y
N
P
x
N
P
③For Elem.3
・・・略・・・
節点5 3
Elem.1
Pressure P1
Elem.2
Pressure P2
Elem3
Pressure P3
Elem.4
Pressure P4
Vertex1
1
5 4
2
Vertex 2
Vertex
3 Vertex
1
V
e
r
t
e
x
2
V
e
r
t
e
x
3
Vertex 3
Vertex 1
V
e
r
t
e
x
2
Vertex
1
V
e
r
t
e
x
3
Vertex
2
プロファイラで実⾏時間内訳をみてみると
• メモリアクセス待ち時間が多かった
• ストア命令がたくさん出ていた
ストアが多かった理由
• ひとつの節点を複数の要素で共有していて,違う
タイミングで同じ節点に何度もストアされる
節点への⾜しこみ(A=A+B)があるので
• SIMDとソフトウェアパイプラインが出来ない
51
何がボトルネックか︖
þ
ý
ü
î
í
ì
¶
¶
¶
¶
=
+
Ñ 1
1
,
1
1
1
,
1
1 , P
y
N
P
x
N
P
þ
ý
ü
î
í
ì
¶
¶
¶
¶
=
+
Ñ 1
2
,
1
1
2
,
1
2 , P
y
N
P
x
N
P
þ
ý
ü
î
í
ì
¶
¶
¶
¶
=
+
Ñ 1
3
,
1
1
3
,
1
3 , P
y
N
P
x
N
P
Vertex 1
①For Elem.1
Vertex 2
Vertex 3
þ
ý
ü
î
í
ì
¶
¶
¶
¶
=
+
Ñ 2
2
,
2
2
2
,
2
2 , P
y
N
P
x
N
P
②For Elem.2
þ
ý
ü
î
í
ì
¶
¶
¶
¶
=
+
Ñ 2
1
,
2
2
1
,
2
3 , P
y
N
P
x
N
P
þ
ý
ü
î
í
ì
¶
¶
¶
¶
=
+
Ñ 2
3
,
2
2
3
,
2
4 , P
y
N
P
x
N
P
þ
ý
ü
î
í
ì
¶
¶
¶
¶
=
+
Ñ 4
2
,
4
4
2
,
4
5 , P
y
N
P
x
N
P
④For Elem.4
þ
ý
ü
î
í
ì
¶
¶
¶
¶
=
+
Ñ 4
1
,
4
4
1
,
4
3 , P
y
N
P
x
N
P
þ
ý
ü
î
í
ì
¶
¶
¶
¶
=
+
Ñ 4
3
,
4
4
3
,
4
1 , P
y
N
P
x
N
P
③For Elem.3
・・・略・・・
節点5 3
Elem.1
Pressure P1
Elem.2
Pressure P2
Elem3
Pressure P3
Elem.4
Pressure P4
Vertex1
1
5 4
2
Vertex 2
Vertex
3 Vertex
1
V
e
r
t
e
x
2
V
e
r
t
e
x
3
Vertex 3
Vertex 1
V
e
r
t
e
x
2
Vertex
1
V
e
r
t
e
x
3
Vertex
2
プロファイラで実⾏時間内訳をみてみると
• メモリアクセス待ち時間が多かった
• ストア命令がたくさん出ていた
ストアが多かった理由
• ひとつの節点を複数の要素で共有していて,違う
タイミングで同じ節点に何度もストアされる
節点への⾜しこみ(A=A+B)があるので
• SIMDとソフトウェアパイプラインが出来ない
52
何がボトルネックか︖
þ
ý
ü
î
í
ì
¶
¶
¶
¶
=
+
Ñ 1
1
,
1
1
1
,
1
1 , P
y
N
P
x
N
P
þ
ý
ü
î
í
ì
¶
¶
¶
¶
=
+
Ñ 1
2
,
1
1
2
,
1
2 , P
y
N
P
x
N
P
þ
ý
ü
î
í
ì
¶
¶
¶
¶
=
+
Ñ 1
3
,
1
1
3
,
1
3 , P
y
N
P
x
N
P
Vertex 1
①For Elem.1
Vertex 2
Vertex 3
þ
ý
ü
î
í
ì
¶
¶
¶
¶
=
+
Ñ 2
2
,
2
2
2
,
2
2 , P
y
N
P
x
N
P
②For Elem.2
þ
ý
ü
î
í
ì
¶
¶
¶
¶
=
+
Ñ 2
1
,
2
2
1
,
2
3 , P
y
N
P
x
N
P
þ
ý
ü
î
í
ì
¶
¶
¶
¶
=
+
Ñ 2
3
,
2
2
3
,
2
4 , P
y
N
P
x
N
P
þ
ý
ü
î
í
ì
¶
¶
¶
¶
=
+
Ñ 4
2
,
4
4
2
,
4
5 , P
y
N
P
x
N
P
④For Elem.4
þ
ý
ü
î
í
ì
¶
¶
¶
¶
=
+
Ñ 4
1
,
4
4
1
,
4
3 , P
y
N
P
x
N
P
þ
ý
ü
î
í
ì
¶
¶
¶
¶
=
+
Ñ 4
3
,
4
4
3
,
4
1 , P
y
N
P
x
N
P
③For Elem.3
・・・略・・・
プロファイラで実⾏時間内訳をみてみると
• メモリアクセス待ち時間が多かった
• ストア命令がたくさん出ていた
ストアが多かった理由
• ひとつの節点を複数の要素で共有していて,違う
タイミングで同じ節点に何度もストアされる
節点への⾜しこみ(A=A+B)があるので
• SIMDとソフトウェアパイプラインが出来ない
節点5 3
Elem.1
Pressure P1
Elem.2
Pressure P2
Elem3
Pressure P3
Elem.4
Pressure P4
Vertex1
1
5 4
2
Vertex 2
Vertex
3 Vertex
1
V
e
r
t
e
x
2
V
e
r
t
e
x
3
Vertex 3
Vertex 1
V
e
r
t
e
x
2
Vertex
1
V
e
r
t
e
x
3
Vertex
2
53
ストアを連続,かつ1回だけにする
節点5 3
Elem.1
Pressure P1
Elem.2
Pressure P2
Elem3
Pressure P3
Elem.4
Pressure P4
Vertex1
1
5 4
2
Vertex 2
Vertex
3 Vertex
1
V
e
r
t
e
x
2
V
e
r
t
e
x
3
Vertex 3
Vertex 1
V
e
r
t
e
x
2
Vertex
1
V
e
r
t
e
x
3
Vertex
2
処理の流れを変更する
要素を順番に巡って,要素からの計算結果を,
要素が使っている節点に⾜しこむ(A=A+B)
↓
節点を順番に巡って,その節点を使っている
要素からの計算結果をまとめて要素に代⼊(A=B)
54
ストアを連続,かつ1回だけにする
節点5 3
Elem.1
Pressure P1
Elem.2
Pressure P2
Elem3
Pressure P3
Elem.4
Pressure P4
Vertex1
1
5 4
2
Vertex 2
Vertex
3 Vertex
1
V
e
r
t
e
x
2
V
e
r
t
e
x
3
Vertex 3
Vertex 1
V
e
r
t
e
x
2
Vertex
1
V
e
r
t
e
x
3
Vertex
2
処理の流れを変更する
要素を順番に巡って,要素からの計算結果を,
要素が使っている節点に⾜しこむ(A=A+B)
↓
節点を順番に巡って,その節点を使っている
要素からの計算結果をまとめて要素に代⼊(A=B)
55
ストアを連続,かつ1回だけにする
節点5 3
Elem.1
Pressure P1
Elem.2
Pressure P2
Elem3
Pressure P3
Elem.4
Pressure P4
Vertex1
1
5 4
2
Vertex 2
Vertex
3 Vertex
1
V
e
r
t
e
x
2
V
e
r
t
e
x
3
Vertex 3
Vertex 1
V
e
r
t
e
x
2
Vertex
1
V
e
r
t
e
x
3
Vertex
2
処理の流れを変更する
要素を順番に巡って,要素からの計算結果を,
要素が使っている節点に⾜しこむ(A=A+B)
↓
節点を順番に巡って,その節点を使っている
要素からの計算結果をまとめて要素に代⼊(A=B)
56
ストアを連続,かつ1回だけにする
節点5 3
Elem.1
Pressure P1
Elem.2
Pressure P2
Elem3
Pressure P3
Elem.4
Pressure P4
Vertex1
1
5 4
2
Vertex 2
Vertex
3 Vertex
1
V
e
r
t
e
x
2
V
e
r
t
e
x
3
Vertex 3
Vertex 1
V
e
r
t
e
x
2
Vertex
1
V
e
r
t
e
x
3
Vertex
2
処理の流れを変更する
要素を順番に巡って,要素からの計算結果を,
要素が使っている節点に⾜しこむ(A=A+B)
↓
節点を順番に巡って,その節点を使っている
要素からの計算結果をまとめて要素に代⼊(A=B)
57
ストアを連続,かつ1回だけにする
節点5 3
Elem.1
Pressure P1
Elem.2
Pressure P2
Elem3
Pressure P3
Elem.4
Pressure P4
Vertex1
1
5 4
2
Vertex 2
Vertex
3 Vertex
1
V
e
r
t
e
x
2
V
e
r
t
e
x
3
Vertex 3
Vertex 1
V
e
r
t
e
x
2
Vertex
1
V
e
r
t
e
x
3
Vertex
2
処理の流れを変更する
要素を順番に巡って,要素からの計算結果を,
要素が使っている節点に⾜しこむ(A=A+B)
↓
節点を順番に巡って,その節点を使っている
要素からの計算結果をまとめて要素に代⼊(A=B)
58
ストアを連続,かつ1回だけにする
節点5 3
Elem.1
Pressure P1
Elem.2
Pressure P2
Elem3
Pressure P3
Elem.4
Pressure P4
Vertex1
1
5 4
2
Vertex 2
Vertex
3 Vertex
1
V
e
r
t
e
x
2
V
e
r
t
e
x
3
Vertex 3
Vertex 1
V
e
r
t
e
x
2
Vertex
1
V
e
r
t
e
x
3
Vertex
2
処理の流れを変更する
要素を順番に巡って,要素からの計算結果を,
要素が使っている節点に⾜しこむ(A=A+B)
↓
節点を順番に巡って,その節点を使っている
要素からの計算結果をまとめて要素に代⼊(A=B)
59
ソース変更
ループ構造を変更した
要素→節点と辿るのではなく節点のループを回して直接節点を参照する
1 DO iN=1,iNUM_NODE Multi-Thread
2 fTMPX=0.0
3 fTMPY=0.0
4 fTMPZ=0.0
5 DO iI=1,8 節点iNを使っている上位要素の数だけ回る
6 iE=iELEM(iI,iN)
7 iV=iERT(iI,iN)
8 fP=fPRES(iE)
9
10 fTMPX += fP * fDN(1, iV, iE)
11 fTMPY += fP * fDN(2, iV, iE)
12 fTMPZ += fP * fDN(3, iV, iE)
13 ENDDO
14 fDP(1,iN) = fTMPX
15 fDP(2,iN) = fTMPY
16 fDP(3,iN) = fTMPZ
17 ENDDO
節点5 3
Elem.1
Pressure P1
Elem.2
Pressure P2
Elem3
Pressure P3
Elem.4
Pressure P4
Vertex1
1
5 4
2
Vertex 2
Vertex
3 Vertex
1
V
e
r
t
e
x
2
V
e
r
t
e
x
3
Vertex 3
Vertex 1
V
e
r
t
e
x
2
Vertex
1
V
e
r
t
e
x
3
Vertex
2
ケース1) 処理の流れだけ変更
60
ソース変更 もう1パターン
ループ構造を変更した
要素→節点と辿るのではなく節点のループを回して直接節点を参照する
1 DO iN=1,iNUM_NODE Multi-Thread
2 fTMPX=0.0
3 fTMPY=0.0
4 fTMPZ=0.0
5 DO iI=1,8
6 iE=iELEM(iI,iN)
7 fP=fPRES(iE)
8
9 fTMPX += fP * fDN2(1, iI, iN)
10 fTMPY += fP * fDN2(2, iI, iN)
11 fTMPZ += fP * fDN2(3, iI, iN)
12 ENDDO
13 fDP(1,iN) = fTMPX
14 fDP(2,iN) = fTMPY
15 fDP(3,iN) = fTMPZ
16 ENDDO
節点5 3
Elem.1
Pressure P1
Elem.2
Pressure P2
Elem3
Pressure P3
Elem.4
Pressure P4
Vertex1
1
5 4
2
Vertex 2
Vertex
3 Vertex
1
V
e
r
t
e
x
2
V
e
r
t
e
x
3
Vertex 3
Vertex 1
V
e
r
t
e
x
2
Vertex
1
V
e
r
t
e
x
3
Vertex
2
ケース2) 配列fDNの定義も変えた
などの配列要素が持つようにした
61
改善効果
ケース
パターン A B A B
実行時間 37.4 30.2 40.9 41.7 秒
性能 18.9 23.3 17.1 16.9 GFLOPS
ピーク比 14.8 18.2 13.4 13.2 %
メモリスループット 30.9 38 48.4 47.7 GB/S
1 2
単位
⼈⼯的なリスト値(全て同じ値)での測定結果
ケース
パターン A B A B
実行時間 123 135 44.3 44.2 秒
性能 5.6 5.2 15.8 15.9 GFLOPS
ピーク比 4.4 4.1 12.4 12.4 %
メモリスループット 23.2 23.2 47.2 47.2 GB/S
1 2
単位
測定結果
2
倍
向
上
リスト値(配列iELEM,iVERT)の値を全て同⼀値にしてリストの性質の善し悪しの影響を排除し
た結果,1の低性能はリストの影響と判明.2は元々リストアクセスされる配列が少ないので,
リスト値の品質の影響は⼩さい
ケース2はほぼ理論的な性能12%に到達.⼀⽅でケース1は低い(メモリスループットも)
91秒
44秒
※K.Kumahata, K.Minami, Y.Yamade, C.Kato, “Performance improvement of the general-purpose CFD code Front/Flow/blue on the K computer”, HPC Asia 2018,
Tokyo, Japan, (2018) https://doi.org/10.1145/3149457.3149470
リスト値
iE=iELEM(iI, iN)
iV=iVERT(iI, iN)
iI, iNの値によらず同じ値とし
た
↓
キャッシュミスしなくなり,遅い
原因がキャッシュミスなのか否
かが明らかになる
62
同じ改善を別カーネルへ
アプリ中に同じ改善が適応可能なカーネルがあり,それにも適⽤し,実⾏時間半減
0.0
10.0
20.0
30.0
40.0
50.0
60.0
ASIS tune1A tune2B tune2B1 tune2C
Time
[s]
ソース概要
DO IE=1, 全ヘキサ要素
DO I=1, ヘキサ要素の8頂点
IP=頂点Iのグローバル節点番号
演算(⻑いので略)
節点IPへのストア
ENDDO
ENDDO
CASE
実行時間
[秒]
向上率
1以上なら
高速化
チューニング内容
ASIS 32.0 1.00 オリジナル(要素で回すループ)
tune1A 55.1 0.58 節点で回すループに変更(配列アクセスはランダム)
tune2B 19.1 1.67 tune1Aを配列を並び替えて配列アクセスを連続アクセス化
tune2B1 20.7 1.54 tune2Bで最内ループ回転数固定化
tune2C 14.0 2.29 tune2B1で最内ループ内処理のアンロール実装を再度ループ化
配列へのストアは連続に、かつA=A+Bの形にしない
流体解析ソルバーFrontFlow/blue
ストリーム削減・セクタキャッシュ・プリフェッチ
63
64
チューニング対象カーネル
FLD3X2ソース
DO iE=1,iNUM_ELEM Multi-Thread
fLP(iE)=fDNX(1,iE)*fDP(1,iNODE(1,iE))+
fDNX(2,iE)*fDP(1,iNODE(2,iE))+
・・・
fDNX(8,iE)*fDP(1,iNODE(8,iE))+
fDNY(1,iE)*fDP(2,iNODE(1,iE))+
fDNY(2,iE)*fDP(2,iNODE(2,iE))+
・・・
fDNY(8,iE)*fDP(2,iNODE(8,iE))+
fDNZ(1,iE)*fDP(3,iNODE(1,iE))+
fDNZ(2,iE)*fDP(3,iNODE(2,iE))+
・・・
fDNZ(8,iE)*fDP(3,iNODE(8,iE))
ENDDO
1
2
3
・・・
9
10
11
12
・・・
18
19
20
21
・・・
27
28
処理内容
要素が頂点として参照する節点がもつ(前の事
例GRAD求められた)圧⼒勾配ベクトルの発散
を求める
節点5 3
Elem.1
Pressure P1
Elem.2
Pressure P2
Elem3
Pressure P3
Elem.4
Pressure P4
Vertex1
1
5 4
2
Vertex 2
Vertex
3 Vertex
1
V
e
r
t
e
x
2
V
e
r
t
e
x
3
Vertex 3
Vertex 1
V
e
r
t
e
x
2
Vertex
1
V
e
r
t
e
x
3
Vertex
2
※) 絵では3頂点の要素だが実際は8頂点の要素
65
チューニング対象カーネル
FLD3X2ソース
DO iE=1,iNUM_ELEM Multi-Thread
fLP(iE)=fDNX(1,iE)*fDP(1,iNODE(1,iE))+
fDNX(2,iE)*fDP(1,iNODE(2,iE))+
・・・
fDNX(8,iE)*fDP(1,iNODE(8,iE))+
fDNY(1,iE)*fDP(2,iNODE(1,iE))+
fDNY(2,iE)*fDP(2,iNODE(2,iE))+
・・・
fDNY(8,iE)*fDP(2,iNODE(8,iE))+
fDNZ(1,iE)*fDP(3,iNODE(1,iE))+
fDNZ(2,iE)*fDP(3,iNODE(2,iE))+
・・・
fDNZ(8,iE)*fDP(3,iNODE(8,iE))
ENDDO
1
2
3
・・・
9
10
11
12
・・・
18
19
20
21
・・・
27
28
処理内容
要素が頂点として参照する節点がもつ(前の事
例GRAD求められた)圧⼒勾配ベクトルの発散
を求める
節点5 3
1
5 4
2
※) 絵では3頂点の要素だが実際は8頂点の要素
fLP(1)
fLP(2)
fLP(3)
fLP(4)
fDNX fDNY fDNZ
fDP fDP fDP
fLP
要素の頂点数
66
性能評価
FLD3X2ソース
DO iE=1,iNUM_ELEM Multi-Thread
fLP(iE)=fDNX(1,iE)*fDP(1,iNODE(1,iE))+
fDNX(2,iE)*fDP(1,iNODE(2,iE))+
・・・
fDNX(8,iE)*fDP(1,iNODE(8,iE))+
fDNY(1,iE)*fDP(2,iNODE(1,iE))+
fDNY(2,iE)*fDP(2,iNODE(2,iE))+
・・・
fDNY(8,iE)*fDP(2,iNODE(8,iE))+
fDNZ(1,iE)*fDP(3,iNODE(1,iE))+
fDNZ(2,iE)*fDP(3,iNODE(2,iE))+
・・・
fDNZ(8,iE)*fDP(3,iNODE(8,iE))
ENDDO
1
2
3
・・・
9
10
11
12
・・・
18
19
20
21
・・・
27
28
最適化状況
ストアの向きがGRADとは逆なのでデータ依存
性なしでSIMD化,ソフトウェアパイプライン
化は適応されている
結果
B/Fから求まる理想値は13%なので遅い
実行時間 57.4 秒
性能 10.3 GFLOPS
ピーク比 8.0 %
メモリスループット 36.8 GB/S
67
改善⼿法1
FLD3X2ソース
DO iE=1,iNUM_ELEM Multi-Thread
fLP(iE)=fDNX(1,iE)*fDP(1,iNODE(1,iE))+
fDNX(2,iE)*fDP(1,iNODE(2,iE))+
・・・
fDNX(8,iE)*fDP(1,iNODE(8,iE))+
fDNY(1,iE)*fDP(2,iNODE(1,iE))+
fDNY(2,iE)*fDP(2,iNODE(2,iE))+
・・・
fDNY(8,iE)*fDP(2,iNODE(8,iE))+
fDNZ(1,iE)*fDP(3,iNODE(1,iE))+
fDNZ(2,iE)*fDP(3,iNODE(2,iE))+
・・・
fDNZ(8,iE)*fDP(3,iNODE(8,iE))
ENDDO
1
2
3
・・・
9
10
11
12
・・・
18
19
20
21
・・・
27
28
改善⼿法
1.配列のサイズをコンパイラに教える
上位ルーチンでは
real*4 :: fDNX(8、NE)
call FLD3X2(・・・,fDNX,8,NE,・・・)
FLD3X2ルーチンでは
subroutine FLD3X2(・・・,fDNX,SZ,NE,・・・)
real*4 :: fDNX(SZ,NE)
となっており、コンパイラは配列fDNXの1次元⽬の
⼤きさが可変という前提で命令を作るが、実際には
固定なので、コンパイラに教えてみる
68
改善⼿法2
FLD3X2ソース
DO iE=1,iNUM_ELEM Multi-Thread
fLP(iE)=fDNX(1,iE)*fDP(1,iNODE(1,iE))+
fDNX(2,iE)*fDP(1,iNODE(2,iE))+
・・・
fDNX(8,iE)*fDP(1,iNODE(8,iE))+
fDNY(1,iE)*fDP(2,iNODE(1,iE))+
fDNY(2,iE)*fDP(2,iNODE(2,iE))+
・・・
fDNY(8,iE)*fDP(2,iNODE(8,iE))+
fDNZ(1,iE)*fDP(3,iNODE(1,iE))+
fDNZ(2,iE)*fDP(3,iNODE(2,iE))+
・・・
fDNZ(8,iE)*fDP(3,iNODE(8,iE))
ENDDO
1
2
3
・・・
9
10
11
12
・・・
18
19
20
21
・・・
27
28
改善⼿法
2. SIMDロードを適応するため,アンロール
実装をループに戻す
1 2 3 4 5 6 7 8 1 2
iE iE+1
fDNX
ひとつのロード命令でまとめてロードできる
のだが、fDNX(1,iE)のような書き⽅だとやっ
てくれないので、fDNX(j, iE)のように書ける
ように変更(リループ)
69
改善⼿法2
DO iE=1,iNUM_ELEM スレッド並列、SWP
DO J=1,8 SIMD, FULLUNROLL
tmp = tmp + fDNX(J,iE)* fDP(1, iNODE(J,iE))
+ fDNY(J,iE)* fDP(2, iNODE(J,iE))
+ fDNZ(J,iE)* fDP(3, iNODE(J,iE))
ENDDO
fLP(iE) = tmp
ENDDO
配列の1次元⽬がループ変数になったため、SIMDロードになるはず
70
改善⼿法3
FLD3X2ソース 改善⼿法
3. 配列fDNX, fDNY, fDNZをfDNXYZにまと
めてストリーム削減
DO iE=1,iNUM_ELEM スレッド並列、SWP
DO J=1,8 SIMD, FULLUNROLL
tmp = tmp + fDNXYZ(J,iE)* fDP(1, iNODE(J,iE))
+ fDNXYZ(J,iE)* fDP(2, iNODE(J,iE))
+ fDNXYZ(J,iE)* fDP(3, iNODE(J,iE))
ENDDO
fLP(iE) = tmp
ENDDO
do I=i, N
A(i) = A(i) + D(1,i) * D(2,i)
enddo
Memory
A
A(i) = αB(i) + C(i)
Register/演算器 Cache
cache line
演算結果 ②
①
③
ロード
B(i) C(i)
D B1 C1 B2 C2 B3 C3 B4 C4 B5 C5 B6 ・・・
Bn Cn Bm Cm
Bn Cn Bm Cm
do I=i, N
A(i) = A(i) + B(i) * C(i)
enddo
Memory
A
B
C
A(i) = αB(i) + C(i)
Register/演算器 Cache
cache line
cache line
cache line
演算結果 ③
①
②
④
ロード
Aは書き込みだけでなく
参照もされている場合
71
改善⼿法4
FLD3X2ソース 改善⼿法
4. セクタキャッシュを利⽤
配列fDPは繰り返し利⽤されると分かっている
ので優先的にキャッシュに乗っていて欲しい
L2は12ウェイあるので、3:9に分けて、9の
側はfDPを優先にする
!ocl cache_sector_size(3,9)
!ocl cache_subsector_assign(fDP)
DO iE=1,iNUM_ELEM スレッド並列、SWP
DO J=1,8 SIMD, FULLUNROLL
tmp = tmp + fDNXYZ(J,iE)* fDP(1, iNODE(J,iE))
+ fDNXYZ(J,iE)* fDP(2, iNODE(J,iE))
+ fDNXYZ(J,iE)* fDP(3, iNODE(J,iE))
ENDDO
fLP(iE) = tmp
ENDDO
節点5 3
1
5 4
2
fLP(1)
fLP(2)
fLP(3)
fLP(4)
fDP(1:3,2)
fDP(1:3,4)
fDP(1:3,5)
fDP(1:3,1)
fDP(1:3,3)
Line N
Line 1
Line 2
0 1 2 3 4 5 6 7 8 9 10 11
・・・・・・・・・・・・・・・・・・・・・・・・
fDP優先
Way
72
改善効果
オリジナル
改善⼿法
1. 配列のサイズをコンパイラに教える
2. 1+SIMDロードを適応するため,アンロール実
装をループにする
3. 2+配列fDNX,fDNY,fDNZをfDNXYZにまと
めてストリーム削減
4. 3+配列を「京」の機能であるセクタキャッ
シュに載せる
実行時間 52.6 49.9 49 47.5 秒
性能 11.3 12.4 12.6 13.0 GFLOPS
ピーク比 8.8 9.7 9.8 10.2 %
メモリスループット 40.3 42.4 43.2 42.5 GB/S
実行時間 57.4 秒
性能 10.3 GFLOPS
ピーク比 8.0 %
メモリスループット 36.8 GB/S
1 2 3 4
73
ソフトウェアプリフェッチ@富岳試作機
!ocl cache_sector_size(3,9)
!ocl cache_subsector_assign(fDP)
DO iE=1,iNUM_ELEM スレッド並列、SWP
DO J=1,8 SIMD, FULLUNROLL
tmp = tmp + fDNXYZ(J,iE)* fDP(1, iNODE(J,iE))
+ fDNXYZ(J,iE)* fDP(2, iNODE(J,iE))
+ fDNXYZ(J,iE)* fDP(3, iNODE(J,iE))
ENDDO
fLP(iE) = tmp
ENDDO
富岳試作機で測定
演算量は全てのスレッドで⼀定のはずが、バリア同期が発⽣
している
↓
⼊⼒メッシュデータに依存して、スレッドごとのキャッシュミス率が
異なってしまっている
74
ソフトウェアプリフェッチ@A64FX
!ocl cache_sector_size(3,9)
!ocl cache_subsector_assign(fDP)
DO iE=1,iNUM_ELEM スレッド並列、SWP
!ocl prefetch_read(fDP(1,NODE(1,iE+32)),level=1)
!ocl prefetch_read(fDP(2,NODE(1,iE+32)),level=1)
!ocl prefetch_read(fDP(3,NODE(1,iE+32)),level=1)
!ocl prefetch_read(fDP(4,NODE(1,iE+32)),level=1)
!ocl prefetch_read(fDP(5,NODE(1,iE+32)),level=1)
!ocl prefetch_read(fDP(6,NODE(1,iE+32)),level=1)
!ocl prefetch_read(fDP(7,NODE(1,iE+32)),level=1)
!ocl prefetch_read(fDP(8,NODE(1,iE+32)),level=1)
DO J=1,8 SIMD, FULLUNROLL
tmp = tmp + fDNXYZ(J,iE)* fDP(1, iNODE(J,iE))
+ fDNXYZ(J,iE)* fDP(2, iNODE(J,iE))
+ fDNXYZ(J,iE)* fDP(3, iNODE(J,iE))
ENDDO
fLP(iE) = tmp
ENDDO
オリジナル
配列fDPのプリフェッチをパラメータスタディ
スレッドごとの打ち分けが均等になり、1秒縮んだ
75
ソフトウェアプリフェッチ@A64FX
!ocl cache_sector_size(3,9)
!ocl cache_subsector_assign(fDP)
DO iE=1,iNUM_ELEM スレッド並列、SWP
DO J=1,8 SIMD, FULLUNROLL
!ocl prefetch_read(fDP(1,NODE(J,IE+64), level=1)
tmp = tmp + fDNXYZ(J,iE)* fDP(1, iNODE(J,iE))
+ fDNXYZ(J,iE)* fDP(2, iNODE(J,iE))
+ fDNXYZ(J,iE)* fDP(3, iNODE(J,iE))
ENDDO
fLP(iE) = tmp
ENDDO
プリフェッチの指⽰⾏をSIMDが有効になっている
ループ内へと変更し、プリフェッチもSIMD化
10.1秒 → 9.2秒 → 6.7秒
命令 SIMD化 命令数 削
4命令 少
オリジナル
乱流燃焼解析コード LS-FLOW-HO
76
77
LS-FLOW-HO
• JAXA 研究開発部⾨ 第三研究ユニットで開発している⾼次精度の流体・燃焼解析ソルバー[1,2]
• 有限体積法に基づき,⾼次精度を達成するため Flux-Reconstruction 法[3]を採⽤
ロケット発射台の空⼒⾳響解析 エンジン燃焼器の乱流燃焼解析
[1] T. Haga, S. Kawai,"On a robust and accurate localized artificial diffusivity scheme for the high-order flux-reconstruction method.," J. Comput. Phys. 376 (2019), pp. 534-563.
[2] Y. Abe, I. Morinaka, T. Haga, T. Nonomura, H. Shibata, K. Miyaji, "Stable, non-dissipative, and conservative flux- reconstruction schemes in split forms." J. Comput. Phys. 353 (2018), pp. 193-227.
[3] H. T. Huynh,"A Flux Reconstruction Approach to High-Order SchemesIncluding Discontinuous Galerkin Methods.," 18th AIAA Computational Fluid Dynamics Conference Miami, Florida
78
Flux Reconstruction (FR) 法
U
U
U
F F
F F
i i+1
i-1
i-1/2 i+1/2 i+3/2
i-3/2
FluxPoint SolutionPoint
共通Fluxの修正
セル界⾯のFPでの値が不連続となる
値が連続となるようセル内SPの値を修正
Cell N-1 Cell N Cell N+1
Cell N-1 Cell N Cell N+1
Actual Cell
Shape
Theoretical Cell Shape
Cell (p=1)
In 3D
Cell (p=2)
In 2D
79
JAXA スーパーコンピュータ JSS3 TOKI-SORA
https://www.jss.jaxa.jp/jss3_configuration/ より抜粋
1977年の⽇本初のスパコンから8世代⽬
Fujitsu	FX1000
1コア当たりの演算性能
2.2GHz x 2FMA x 8SIMD × 2Pipe = 70.4GFLOPS
• SIMDありきの性能なのに注意
• レジスタ数が減っているのに注意
Core
Clock Freq. 2.2 GHz
GFLOPS 70 GFLOPS
L1D Cache 64 KiB (256GB /s)
CMG
# of Core 12
GFLOPS 884 GFLOPS
Memory 8 GiB (256 GB/s)
L2 Cache 8 Mib (1024 GB/s)
CPU
# of CMG 4
GFLOPS 3379 GFLOPS
Memory 32 GiB
Node # of CPU 1
Syste
m
# of Node 5760
GFLOPS 19.4 PFLOPS
Memory 180 TiB
リングバスには他にPCIeやインターコネクトのコントローラが接続
Machine 京 FX100 FX1000
SIMD width 2 (128 bit) 4 (256 bit) 8 (512 bit)
# of register 256 256 32
80
ベンチマーク問題
A Update T and P H Correct Residual
B Compute E I Compute Residual F.G.
C Compute Cp J Compute Self Resiaual(A)
D Compute Trans Prop K Compute Self Residual(B)
E Compute Cv L Compute Gradient
F Compute Thermal Prop M Sum of under 1%
G Ref. flamelet tab.
Cost distribution
on SORA by
profiler
FIPP
Procedures for Combustion Calculations
10MPa
H2 150K
O2 100K
7100 Cells (1cell for thickness)
p=2 (# of SPs in Cell 27)
Use 1CMG (12threads)
on FX1000
100step
液体酸素と⽔素の同軸噴流⽕炎 反応機構で素反応を含む8化学種
実在気体の状態⽅程式 SRK⽅程式
輸送係数
Chung
CHEMKIN
Wilke混合則
燃焼モデル Flamelet Progress Variable (FPV)
81
インライン展開のやりすぎに注意
D) Compute Trans Propのコールツリー
通らない(実⾏時
パラメータ依存)
インライン展開
⾮インライン展開
do icell=1, セル数 スレッド並列化
do isp=1, 27
Call_Subroutines
enddo
enddo
これ以外のループの回転数はごく少ない
(例:コンパイル時に明らかになっている数8)
最も回転数が多いループicell
2番⽬に回転数が多いループisp
FX100向けにインライン展開を多⽤.使⽤するレジスタ数
が増えるが,FX1000ではレジスタ数が減っているので,レ
ジスタに乗せるデータの⼀時退避・復帰が頻発し性能劣化
チューニング)
⼀般的には演算区間であるような下位のループの実⾏時間
を短縮し,GFLOPSやGB/sを向上させること.
本コードでは,上位ループから回転数・演算数がごく⼩さい
下位ループを多数呼んでおり,⼿続き呼び出しのオーバー
ヘッドや,レジスタ不⾜に伴う演算待ちがボトルネックであり,
現状,それらの低減が主眼.
⼿法ごとに整理して述べる
ComputeMwBar
ComputeTransProp_LowPress
ComputeTransProp_Chung_Single
ComputeRconst
Mixing_Wilke
0ならインライン展開する,1ならインライン展開しない
デフォルト
最良
原点が0でないので注意
82
⼩回転ループはさけたい
• コンパイル時にはすでに決まっている,⼩回転数のループ
• ソフトウェアパイプライン化されるが,回転数が少ないため効果なし
• ループ制御のオーバーヘッドを避けるためループで無くした⽅がよい
do icell=1, セル数 スレッド並列化
do isp=1, 27
・・・
do ichem=1, pr%nchem
y(ichem) = value(ie + ichem, icell)
enddo
・・・
enddo
enddo
SIMD化(VL: 8)
SOFTWARE PIPELINING化
IPC: 3.00, ITR: 144,
MVE: 5, POL: S)
do icell=1, セル数 スレッド並列化
do isp=1, 27
・・・
do ichem=1, _NSCL
y(ichem) = value(ie + ichem, icell)
enddo
・・・
enddo
enddo
FULL UNROLLING
コンパイル時には数が分かっているが
可変回転数のループとして扱われている
プリ処理部でpr%nchem=_NSCLと設定
このようなループがある
F) Compute Thermal Propの内の下位のループ
原点が0でないので注意
今のケースでは実際は2
83
⼩回転ループはさけたい
52.0
52.1
52.2
52.3
52.4
52.5
52.6
0 1 0 1 0 1 0 1
0 0 1 1 0 0 1 1
0 0 0 0 1 1 1 1
Time
[s]
Loop C
Loop B
Loop A
0) Original (Implemented as Loop)
1) Modified (Unrolled)
別のルーチンにも同様の⼿法を当てはめてみた
Loop A)
前ページと同じく,コンパイル時には
回転数が確定しているが,コンパイ
ラにはわからない
今のケースでは8回転
Loop B,C)
ソース上で直接回転数をハードコー
ドしている
do i=1,10など
原点が0でないので注意
84
OpenMPのスケジュール調整
0.0
2.0
4.0
6.0
8.0
10.0
12.0
0 1 2 3 4 5 6 7 8 9 10 11
Time
[s]
Thread
Inctruction Commit
Barrier Wait
Instruction Wait
Memory/Cache
AccessWait
0.0E+00
5.0E+09
1.0E+10
1.5E+10
2.0E+10
0.0E+00
2.0E+10
4.0E+10
6.0E+10
8.0E+10
1.0E+11
0 1 2 3 4 5 6 7 8 9 10 11
■Number
of
Instructions
■Number
of
FLOP
Thread
0.0
2.0
4.0
6.0
8.0
10.0
12.0
0 1 2 3 4 5 6 7 8 9 10 11
Time
[s]
Thread
Inctruction Commit
Barrier Wait
Instruction Wait
Memory/Cache
AccessWait
A) Update T and P ルーチンの実⾏時間内訳
• FX1000のCPU性能解析レポートの出⼒,バリア同期待ちが多い
• セルを巡るループでスレッド並列化しており,各スレッドへのセルの割当量
は均⼀だが演算数に違いが出ている
• 当該ループのOpenMPのディレクティブに schedule(dynamic, 1)
を指定し !$omp parallel do schedule(dynamic, 1)
とした
do itr=1, max
res = ・・・
if(res < EPS) exit
enddo
収束判定に合格して
ループを抜けるタイミングが
まちまちだった
85
重複した処理の回避
A) Update T and Pルーチン中の温度更新反復のコールツリー
• 同じサブルーチンが複数の上位から呼ばれていることが多い
• 例えば⾚枠ConvertMass2Moleは質量分率からモル分率に変
換するルーチン.反復ループ外から1回,反復ループ中からは他
のルーチンを介して1反復当たり3回呼ばれるが,全ての呼び出し
が同じ計算
• 他にもループ中に温度に依存しない計算があったり,依存するが
同じ温度から同じ結果得る計算を何度も読んでいる個所があり,
除去を⾏った
do itr=1, iter_max
call subroutine
T = ...
enddo
温度を更新する
反復ループがある
Update T and P
このとき浮動⼩数点演算数は
1.09×1012 から
8.10x1011 に25%ほど削
減
86
配列初期化時の性能劣化
※前ページまでの事例とは,ソースの版数と⼊⼒データが異なる
1ルーチン単体(下位のルーチン含まず)
でコストの18%弱を占める
C ase N o. A Total range1 range2 range3 range4 other
31 12.
80 0.
12 1.
08 11.
60
32 2.
81 0.
11 0.
12 0.
11 2.
48
33 2.
99 0.
11 0.
11 0.
10 0.
11 2.
56
34 2.
81 0.
11 0.
11 0.
11 2.
49
単位 [s]
ルーチン内に細かくタイマールーチンを挿⼊.
特定部分を計るためのタイマーが有効な
時だけ速い
range2,3でおかしなことが起きている
01 subroutine sample(n1, n2, input_arrayA, input_arrayB)
02 implicit none
03
04 ! argument
05 integer, intent(in) :: n1, n2
06 real(8), intent(in) :: input_arrayA(n1), input_arrayB(n2)
07
08 ! local
09 real(8) :: work_arrayA(n1), work_arrayB(n2)
10 ・
11 ・
12 ! call timer_start(range2)
13 work_arrayA(:) = input_arrayA(:)
14 ! call timer_stop(range2)
15
16 ! call timer_start(range3)
17 work_arrayB(:) = input_arrayB(:)
20 ! call timer_stop(range3)
21 ・
22 ・
23 end subroutine sample
当該ルーチン概要
range3
• range2,3は引数の値をワーク配列へコピーする配列式
• コンパイラは配列式をループとして扱いループ最適化
(実⾏時回転数889以上でスレッド並列,SIMD,ソフトウェアパイプライン
など適応)
• コメントアウトしてあるタイマールーチン呼び出しを有効にすると速くなる
87
配列初期化時の性能劣化
コンパイル時及び実⾏時の以下の条件が重なり遅くなっていた
1. コンパイラは配列式をループとして扱うため,range2とrange3は
それぞれループとなる
2. ⾃動スレッド並列化が有効である(-Kparallel)場合,同じ
ループのスレッド並列版と,逐次版を⽣成し,実⾏時のループ回
転数で切り替える
3. スレッド⽣成のオーバーヘッドを避けるため,並列リージョン拡張と
いう,可能なら複数のループを合成してからスレッド並列化の処
理を⾏う機能がある
この機能が動作したときは,逐次版のループを作らない
range2と3の間にタイマールーチン呼び出しがある場合は並列
リージョン拡張は働かない
do i=1, n1
work_arrayA(i) = input_arrayA(i)
enddo
do i=1, n2
work_arrayB(i) = input_arrayB(i)
enddo
range2
range3
if(n1 > 889) then
!$omp parallel
range2のスレッド並列版ループ
!$omp end parallel
else
range2の逐次版ループ
endif
if(n2 > 889) then
!$omp parallel
range3のスレッド並列版ループ
!$omp end parallel
else
range3の逐次版ループ
endif
!$omp parallel
range2のスレッド並列版ループ
range3のスレッド並列版ループ
!$omp end parallel
イメージ
イメージ
イメージ 実⾏時の回転数は
range2は72, range3は9.
並列リージョン拡張されなかった場合は,逐
次版ループを実⾏する
拡張された場合は低回転ループにも関わら
ず,スレッド並列版ループを実⾏する
そのためオーバーヘッドで性能劣化
range2 range3
このような現象が出るときの解決策
• -Knoregion_extensionを指定
• 配列式に!OCL SERIALを指定
• 今回のように無害なルーチンを配列式の間に挿⼊
88
まとめ
0.0
20.0
40.0
60.0
80.0
100.0
As-Is Current
Time
[s]
Thread
Inctruction Commit
Barrier Wait
Instruction Wait
Memory/Cache
AccessWait
With Array Init Problem
チューニング)
⼀般的には演算区間であるような下位のループの実⾏時
間を短縮し,GFLOPSやGB/sを向上させること.
本コードでは,上位ループから回転数・演算数がごく⼩さい
下位ループを多数呼んでおり,⼿続き呼び出しのオーバー
ヘッドや,レジスタ不⾜に伴う演算待ちがボトルネックであり,
今回はそれらボトルネックの低減が主眼でした
他にも,コンパイルオプションの再考として,元々FX100向け
だったので⾊々指定されていた
-Kfast,parallel,noalias=s,array_private,
preex,ocl,nounroll,autoobjstack を再整理し
て -Kfast,parallel,ocl として56.0秒から53.8秒
With Array Init. Problem
プロファイラ(CPU性能解析レポート)を使うとバーヘッドが出る
ため,ここではプロファイラを⽤いて求めた実⾏時間の内訳を,
プロファイラなしで実⾏した際の全体実⾏時間で補正
今回ご紹介した紹介したチューニング事例を全て適応
アプリ全体の実⾏時間は,81秒程度から51秒程度に
改善
配列初期化時の性能劣化は,統⼀して測定できな
かったので,その分10秒を個別に加えると90秒程度か
ら51秒程度に改善
その他のTips
89
90
なるべく⻑いループでSIMDに
0.46秒,2.35E+10FLOP,SIMD率90.4%
1.03秒,3.33E+10 FLOP, SIMD率40.0%
(1,2) do idx=1, max(=191700) SWP
(3-1) do ichem=1, spc_num(=8) 8SIMD
(3-2) do j=1,3 FULL UNROLL
(3-3) do j=1, spc_num(=8) 8SIMD
(1,2) do idx=1, max(=191700) 8SIMD
(3-1) do ichem=1, spc_num(=8) FULL UNROLL
(3-2) do j=1,3 FULL UNROLL
(3-3) do j=1, spc_num(=8) FULL UNROLL
SIMD化は最内ループに適応される
91
Z-Fillの効果
Z-Fillあり -Kzfill
Memory
A
B
C
A(i) = αB(i) + C(i)
Register/演算器 Cache
cache line
cache line
cache line
演算結果
4stream
Z-Fillなし
Memory
A
B
C
A(i) = αB(i) + C(i)
Register/演算器 Cache
cache line
cache line
cache line
演算結果
3stream
キャッシュライン確保命令
①
②
③
④
①
②
③
暗黙のロード
92
Z-Fillの効果
疑似コード
integer*8 :: I, SZ, ITR, NITR
parameter(SZ=104857600)
parameter(NITR=100)
real*8 :: A(SZ), B(SZ), C(SZ), alpha
start = gettime()
call FAPP_START()
do ITR=1, NITR
do I=1, SZ
A(I)=alpha * B(I) + C(I)
enddo
enddo
call FAPP_STOP()
dt = start – gettime()
本体部分
配列ひと
つのサイ
ズ MB
case GB dt [s] GB/s
withoutzfill 335.544 1.616 207.657
withoutzfill_numactl 335.544 1.618 207.343
withzfill 251.658 1.236 203.634
withzfill_numactl 251.658 1.237 203.382
withoutzfill 335.544 1.601 209.577
withoutzfill_numactl 335.544 1.623 206.767
withzfill 251.658 1.242 202.633
withzfill_numactl 251.658 1.241 202.788
withoutzfill 335.544 1.463 229.422
withoutzfill_numactl 335.544 1.674 200.500
withzfill 251.658 1.279 196.833
withzfill_numactl 251.658 1.284 195.948
800
80
8
Z-Fillにより暗黙のAのロードがなくなり
ストリームが削減し性能改善
93
その他
ifを含むループはリストベクトル化
93
REAL A(N1, N2, NE)
DO IE=1, NE マルチスレッド
DO I=1, N2
DO J=1, N1 SIMD
A(J,I,IE)=Const
ENDDO
ENDDO
ENDDO
REAL A(N1, N2, NE)
SZ=(N1*N2*NE) / 8
DO I=8 マルチスレッド
ST=1+SZ*(I-1)
call memset_wrap(A(P),Const,SZ)
ENDDO
上位要素数8までの節点
上位要素数8以上の節点
節点リスト
1 2 3 4 5 6 7 8
IF(NEP(8)>8) THEN
DO I=9,NEP(8)
・・・
ENDDO
ENDIF
IF(NEP(8)>8) THEN
DO I=9,NEP(8)
・・・
ENDDO
ENDIF
IF(NEP(8)>8) THEN
DO I=9,NEP(8)
・・・
ENDDO
ENDIF
IF(NEP(8)>8) THEN
DO I=9,NEP(8)
・・・
ENDDO
ENDIF
IF(NEP(8)>8) THEN
DO I=9,NEP(8)
・・・
ENDDO
ENDIF
IF(NEP(8)>8) THEN
DO I=9,NEP(8)
・・・
ENDDO
ENDIF
IF(NEP(8)>8) THEN
DO I=9,NEP(8)
・・・
ENDDO
ENDIF
IF(NEP(8)>8) THEN
DO I=9,NEP(8)
・・・
ENDDO
ENDIF
オリジナルは,全ての節点で
判定とループを実⾏
上位要素数が8以上の節点リスト
3 4 6 8
IP=LST(4)
DO I=9,NEP(IP)
・・・
ENDDO
ENDIF
IP=LST(4)
DO I=9,NEP(IP)
・・・
ENDDO
ENDIF
IP=LST(4)
DO I=9,NEP(IP)
・・・
ENDDO
ENDIF
IP=LST(4)
DO I=9,NEP(IP)
・・・
ENDDO
ENDIF
リストベクトル化
リストベクトル化後は
IFなしで,実⾏可能
↓
最内ループは必ず実⾏
され,SIMD化・SWP
化されている
7.8秒
0.0?秒
ifに合格するものだけの集合
C⾔語のmemsetを呼ぶラッパー関数
を⽤意
配列を8等分し,8スレッドから呼ぶ
2.2秒
0.6秒
配列、特に多次元配列の初期化を、配列の
形に合わせたようなループでやらない

第5回 配信講義 計算科学技術特論B(2022)