Upload
teague
View
38
Download
0
Embed Size (px)
DESCRIPTION
Survey: Portable High-Performance Programs の一部. 2000.4.12 遠藤 敏夫. 今回の内容. Portable High-Performance Programs [Frigo 99(PhD)] テーマは portability Cache-oblivious algorithms([Frigo et al. 99], PhD Chap 3) メモリ階層に対して portable 逐次の話 Portable parallel memory (PhD Chap 4) - PowerPoint PPT Presentation
Citation preview
Survey: Portable High-Performance
Programs の一部
2000.4.12 遠藤 敏夫
今回の内容
Portable High-Performance Programs [Frigo 99(PhD)]テーマは portability Cache-oblivious algorithms
([Frigo et al. 99], PhD Chap 3) メモリ階層に対して portable 逐次の話
Portable parallel memory (PhD Chap 4) Cilk: 並列性に対して portable Cilk の性能モデルにメモリ階層の影響を追加
Frigo
Cilk グループ (MIT) の一員 FFTW で 1999 年 Wilkinson 賞を受賞
FFTW: FFT に特化したコンパイラによって高速化
Cilk の性能モデルにメモリ階層の影響を追加 遠藤の行く手に立ちふさがる人物
Cache-oblivious algorithms
Oblivious … a. 忘れっぽい、気づかない対義語 : aware, conscious
プログラムのメモリアクセスパターンの工夫により、キャッシュミスの少ない (= 速い ) プログラムを作ることができる
でも、プログラマに各計算機固有 ( アーキテクチャにaware) の最適化をやらせたくない
いくつかの問題に対して、 cache-oblivious かつ性能のよいアルゴリズムを提案 行列積、転置行列、ソート、 FFT キーワードは divide and conquer
準備 : 理想キャッシュモデル(1)
キャッシュは 1 階層のみ ラインサイズ L(word), ライン数 H キャッシュサイズ Z = LH (word) プログラムを走らせたときのキャッシュミス
数 Q
CPU Cache Main memory
LH
QZ
Full associative ライン置換え規則 : 将来のアクセスが最後で
あるようなラインを追い出す 局所性を完全に利用できる
Z = Ω(L2) (L2 オーダー以上 ) を仮定
この理想的キャッシュでのミス数 Q が小さいアルゴリズムを提案
準備 : 理想キャッシュモデル(2)
行列積 (1): 単純方式
A, B, C: n×n 行列単純なアルゴリズム (iterative アルゴリズム ):
for (i = 0; i < n; i++)
for (j = 0; j < n; j++)
for (k = 0; k < n; k++)
C[i,j] += A[i,k] * B[k,j]
計算量は O(n3)
C = A B
行列積 (2) : 単純方式の評価
単純アルゴリズムでのキャッシュミス数 Q は?ここでは、だいたい n < Z/3 < n2 として考える( 一行ならキャッシュに収まるが、行列全体はムリ ) C: 全体 write を 1 回… QC = O(n2/L)
A: 各行 n 回 read してから次へ… QA = O(n2/L)
B: 全体 read を n 回… QB = O(n3/L)
結局、 Q = O(n3/L) アルゴリズム変更で減らせる !
A B
×n
C
行列積 (3) :Blocked 方式
Blocked アルゴリズム 各行列を s×s 小行列に分割 s=O(√Z)
小行列がキャッシュに収まるような s
for (i = 0; i < n/s; i++)
for (j = 0; j < n/s; j++)
for (k = 0; k < n/s; k++)
mul(s, A, B, C, i, j, k)
ns
この中は普通に iterative
行列積 (4): Blocked 方式の評価
一回の mul では 計算量は O(s3) で普通 キャッシュミス Q=O(s2/L) ですむ
Blocked アルゴリズム全体では 計算量は O(n3) で普通 キャッシュミス Q=O(n3/Ls)=O(n3/L√Z)
(n がいくつでも成立する式は Q=O(n+n2/L+n3/L√Z) )
Q は単純アルゴリズムより√ Z 倍減った! しかし、 s を z に依存させる必要 (cache-aware)
行列積 (5): Recursive 方式 Recursive アルゴリズム
行列 A, B, C を 4 等分しながら再帰呼び出し
if (n == 1)
C += A B
else
A→A11, A12, A21, A22 (B, C も同様 )
C11 += A11 B11; C11 += A12 B21
C12 += A11 B12; C12 += A12 B22
C21 += A21 B11; C21 += A22 B21
C22 += A21 B12; C22 += A22 B22
サイズを n/2 にして再帰呼び出し(divide&conquer!)
再帰の終点
行列積 (6): Recursive 方式の評価
枝別れしていったいつかは、全行列がキャッシュに収まるサイズになる その時のサイズは s=O(√Z) のはず 計算量、ミス数の議論は Blocked と同じ Q=O(n+n2/L+n3/L√Z)
プログラム中に Z, L に依存する変数は現れない (cache-oblivious)
Blocked アルゴリズムと同等 ( 違ったとしても定数倍 ) の Q
行列積 (7): recursive は速いか?
横軸… n, 縦軸… ( 実行時間 / n3)
venus(Ultra SPARC 360MHz) Iterative(iter) と recursive(rec-X) を比較 考察 :
iter は n>256 くらいで遅くなる rec-X は n にほぼ依存しないが、 rec-1 は遅すぎる 再帰を 4 や 32 で止めると iter に勝つ
0
0.05
0.1
0.15
0.2
0.25
0.3
0.35
0 200 400 600
iterrec-1rec-4rec-32
( 調査 : 遠藤 )
Funnel sort (1)
マージソートの一種 多数の k-merger( 図中三角 ) の組み合わせ
一番右は n1/3-merger
計算量 =O(n log n), Q=O((n/L)(1+log Z n))
結果列 ( 長さn)
入力n 個
Funnel sort (2): k-merger k-merger の外部仕様
長さ k2×k 本の入力列 →長さ k3 の出力列 k-merger の内部構造
√k 個の√ k-merger L1…L√k
√k 本の FIFO キュー ( 長さ 2k3/2) 1 個の√ k-merger R
R
L1
L2
√k 本
k 本
Funnel sort (3): k-merger の詳細
以下を、入力データがなくなるまで繰り返す Li のうち、バッファが半分以下しか埋まっていない
merger たちを動作させる → 全バッファが少なくとも半分埋まる
R を動作させる 最終的に、各 Li は k 回づつ、 R は k3/2 回動作する
内部 merger に小出しにさせることにより、バッファサイズを小さく押さえるというのがツボらしい
k-merger のデータサイズは O(k2) (自分の出力バッファ除く )
Funnel sort (4): Q の概略
外 / 内方向の再帰についてk-merger を 1 回動かしたときのミス数 QM(k)
k が O(√Z) より大きい… QM(k) 2≦ k3/2 QM(√k) + k2
k が O(√Z) 以下… QM(k) = O(k3/L)
帰納法により、 QM(k)=O(k3/L+k3 log Z k/L)
左右方向の再帰について funnel sort 全体のミス数 Q(n) n が O(Z) より大きい… Q(n) = n1/3 Q(n2/3) + QM(n1/3) n が O(Z) 以下… Q(n)=O(n/L) 帰納法により、 Q(n) = O((n/L)(1+log Z n))
Funnel sort(5): 他ソートとの比較
N が Z よりも大きいとき、 Funnel sort では Q(n) = O((n/L) log Z n) 2way merge sort では Q(n) = O((n/L) log2(n/Z)) 多分
たとえば Z=216, n=224 のとき、 log Z n : log2(n/Z) = 24/16 : 24-16 = 1.5 : 8
n が十分大きければ、 log Z 倍 funnel sort が有利
Cache-oblivious algorithm まとめ
いくつかの問題に対し、 Cache-oblivious かつミス数の少ないアルゴリズムを提案・議論 基本方針は divide&conquer
少なくとも sort では、ミス数は漸近的最適 行列積・ FFT では lower bound が知られてないらしい
future work: cache-oblivious アルゴリズムが cache-aware アルゴリズムに勝てない場合はあるのか?
Portable parallel memory
ここから後半です。
ここでの結論は、TP(Z,L) = O((T1+μQ)/P + μHT∞)
背景 : Cilk(1)
文脈 : 並列言語 Cilk は、 細粒度マルチスレッド機能を提供
プログラマは CPU 数などを気にせず並列プログラミング
並列プログラムの性能モデルを提供 1CPU での実行時間 T1 と、クリティカルパス長
さ T∞ から、並列実行時間を求めることができる しかし、モデルにメモリ階層の影響が入ってい
なかった → 本研究により追加
背景 : Cilk(2)
行列積 のプログラム例 (文法はいい加減 )if (n == 1) C = A B
else
A→A11, A12, A21, A22 (B, C も同様 )
spawn(C11 = A11 B11); spawn(T11 = A12 B21)
spawn(C12 = A11 B12); spawn(T12 = A12 B22)
spawn(C21 = A21 B11); spawn(T21 = A22 B21)
spawn(C22 = A21 B12); spawn(T22 = A22 B22)
sync;
matrix_add(n, T, C) /* C += T を並列実行 */
任意の場所での fork /親によって join lock/unlock なし
背景 : Cilk(3)
T1: 全タスク量 (1 プロセッサでの実行時間 )
T∞: クリティカルパス長 のとき、P プロセッサでの平均実行時間 O(T1/P + T∞)
タスク
クリティカルパス中のタスク
依存関係
メモリ階層を考慮した性能モデル
分散共有メモリを仮定 Location-consistency ( 後述 ) プログラムのメモリアクセスは各メモリに対
して均等に起こると仮定 遠藤の研究では、ばらつきがある場合に対応
メモリモデル (1)
各プロセッサは以下を持つ : サイズ Z=H×L の LRU キャッシュ 十分なサイズのメモリ
キャッシュミス時は、自分または他プロセッサのメモリからキャッシュへコピー
平均ミス (fetch) コスト μCPU
cache
CPU
cache
CPU
cache
memory memory memory
CPU
cache
memory
メモリモデル (2):location-consistency
Relaxed consistency model の一種 Cilk のスレッドスケジューラと連携 location-consistency の定義 :
C をスレッド依存グラフとしたとき、任意のlocation(cache line) l について C の topological sort Tl が存在し、 l への read の結果は Tl における直前の write の結果である
直観 : タスク u→v という依存関係があるなら u での write 結果は必ず v に見える
メモリモデル (3)
Location consistency を実現するために プロセッサ p 上のタスク u と、 q 上の v に、
u→v という依存関係があるとき、 p は u 後に全 cache line を reconcile(write back) q は v前に全 cache line を reconcile, flush
メモリモデルへの意見
ハードウェア DSM で実装するなら、 CPU が全reconcile命令などを備えている必要
ソフトウェア DSM だとすると、よその memory から直接 cache へ通信できるという前提が不自然
relaxed モデルを採用した理由は、不定期に起こるinvalidation を避けるためと考えられる 別プロセッサ間タスク依存のあるときのみ、余
分に reconcile&flush 遠藤の研究では ( ほぼ )sequential consistency であ
るマシンを対象。その変わりプログラムがほとんど invalidation を起こさないことを仮定
記号・用語説明 (1)
T1: 全仕事量 ( ミスコストなし )
T1(Z,L): 全仕事量 ( ミスコスト込み ) μ: 一回の transfer (fetch/reconcile)平均時間 Q: 逐次でのミス数
T1(Z,L) = T1 +μ Q
T∞: クリティカルパス長 ( ミスコストなし ) T∞(Z,L) というのは使わない
TP(Z,L): P プロセッサでの実行時間
記号・用語説明 (2)
Subcomputation : 仕事グラフを以下の時点で区切ったもの プロセッサが仕事を得た時点 /ひまになった時点 同期待ちを起こした時点 / 起こされた時点
並列実行時の transfer の分類 intrinsic transfer: 逐次に実行したときでも起こる
もの (総数 Q) extrinsic transfer: 並列実行のときのみ起こるもの
用法 : ある subcomputation が N 個の extrinsic transfer を引き起こした
transfer 数の議論
各 subcomputation に、最大 3H の extrinsic transfer が対応 (H は cache line 数、 H=Z/L)
subcomputation開始時に最大 H の reconcile subcomputation 実行中に、逐次の時より最大 H余
計にミス (fetch) subcomputation 終了時に最大 H の reconcile
並列時の平均キャッシュミス数は Q(Z,L) + O(HPT∞)
並列化オーバヘッドの議論
event=task steal試行 +extrinsic transfer 各プロセッサが以下の仮定を満たすとき、
task steal 成功の間には H 回以上の transfer task steal試行の間には 1 回以上の transfer
event 回数の、全プロセッサでの合計は平均でO(HPT∞) 27HP 回の event のうち、少なくとも 4P 回が steal 試行 4P 回 steal試行があれば、 1/2 以上の確率で critical path
にそって仕事が進む event 回数 ×μ が並列化オーバヘッド
並列実行時間の議論
P プロセッサでの Cilk プログラム平均実行時間は TP(Z,L) = O((T1(Z,L)/P + μHT∞)
= O((T1+μQ)/P + μHT∞) 各プロセッサの消費する時間の合計は、
計算 +intrinsic transfer に T1(Z,L)
event に O(μHPT∞)
補足 : アクセス衝突
これまでの議論は transfer 時に衝突がないことを仮定。衝突があると、 transfer コストは μ 以上になるかも → transfer 対象がランダムで平均しているという仮定
なので、衝突コストを入れてもせいぜい定数倍、ということを証明
意見 : 確かにこの仮定が成り立つなら、定数倍という結果は感覚的に納得できる。しかし Origin2000 のようなマシンではその仮定が崩れうる。遠藤の研究はそこに注目。
Portable parallel memory まとめ
Cilk の実行時間モデルにキャッシュの影響を追加 Cilk のスレッドスケジューラ、 location-
consistency 、アクセスが balanced 、という仮定のもとで TP(Z,L) = O((T1+μQ)/P + μHT∞)
divide&conquer プログラムにおいて、使用メモリ量の上限を解析 (未 survey)
自分の研究について
並列時キャッシュミス = 逐次時キャッシュミス + O(H × steal 回数 ) というのを先にやられてしまった
Frigo はオーダー解析をメインに行っているので、定数部にも注目し、実験を通して予測と実測の比較をメインにやっていきたい プログラムを並列 GC に限定 (invalidation がおそ
らくあまり起こらない、タスクグラフが簡単 )