f()

スケーラブルでないモジュールを含む
並列プログラムにおける高性能の達成
Achieving High Performance in Parallel
Programs Containing Unscalable Modules
東京大学 大学院
理学系研究科 情報科学専攻
大山恵弘
満足のいく性能モデル
• プロセッサ増加 ⇒ 実行時間減少 or
実行時間そのまま
すべてのプログラムで成立してほしい
はたして現実は?
Motivating Example
• 各スレッドが独立にfib(10)と共有カウンタの増加
を交互に繰り返し実行するプログラム
– C + Pthreads, Sun Enterprise 10000
– 仕事量の総和はプロセッサ数に非依存
time (msec)
2000
fib
実行のほんの一部が逐次化
fib + counter
↓
(spin)
fib + counter
満足のいく性能モデルが破綻
1500
1000
500
(mutex)
0
0
10
20
30
40
number of processors
50
60
実行を逐次化するモジュール
(ボトルネックモジュール)
広範囲に存在!
• Thread-unsafeライブラリ
– MPICH、GTK+
• 共有資源の操作
– I/O、GUI、大域変数、共有バッファ
– 並列ループの誘導変数
• 暗黙に排他処理するライブラリ
– 多くのmallocの実装
現状
多くの並列プログラムで不満足な性能モデル!
並列プログラム
逐次モジュールが
ほとんどないプログラム
行列積
GUI
Fib
暗号破り
自然言語処理
webサーバ
並列分野の既存研究の多く
本研究の目的
• 満足のいく性能モデルを、すべての並列
プログラムで実現する言語
– 共有メモリ計算機が対象
ボトルネックの最大性能ギリギリ
Q: 満足のいく性能モデルを
得ることに意味あるの?
A: ある!
time
このへんで実行したら悲劇
(最高性能の半分)
number of processors
U字の底のプロセッサ数で
実行すればいいのでは?
• 最適なプロセッサ数は予測困難
– 動的な挙動の予測はときに困難
– 最適な数は入力やプログラムの場面に依存
色々なプロセッサ数で何回も同じ計算をするのは
処理系実装者やベンチマーク屋だけ!
我々の怒り
多くの並列プログラマが
唯々諾々と従っている啓示
「並列化の恩恵受けたければ、
ボトルネックを皆無にすべし」
こんな高飛車で、
万人に並列処理が普及するか?
「最高性能を出すプロセッサ数は
プログラマが自分で見つけるべし」
そんな苦労をプログラマに
負わせておいていいのか?
並列処理を大きく
discourage!
我々が取り組んだ問題
• ボトルネック存在下でも高性能を出すには
– 排他処理
– スレッドスケジューリング
– 言語設計
はどうあるべきか?
3つの本質的な部分問題
•
ボトルネック部分の実行コストの削減
– ボトルネック担当プロセッサの動的導入で達成
•
ボトルネック部分の実行回数の削減
– 複数の呼び出しの「融合」で達成
•
ボトルネック部分での過大なメモリ消費の抑制
– プロセッサ数の動的制御で達成
3つのポイントがもたらすもの
time
1
2
number of processors
3つのポイントがもたらすもの
メ
モ
リ
消
費
量
limit
3
number of processors
Part 0
我々の言語
我々の言語Amdahl
• C++
+ 軽量スレッド
+ 排他メソッド
単純なプログラミングモデルを提供
スレッド
• API:
athread_create(f, arg, thr_id);
• Lazy Task Creation [Mohr et al. 91]に
もとづくスレッド管理
– 低コストで多数のスレッドを生成可
• 「並列単位1つ ⇔ スレッド1つ」のプログラミング
– ランタイムが自動的に動的負荷分散
• Task stealing
排他機構
• 排他メソッド
– ≒ synchronized methods in Java
– 1つのオブジェクト上で排他的に実行されるメソッド
class Counter {
int value;
…
sync inc(int n) {
value += n;
}
}
Part 1
ボトルネック部分の実行における
メモリ通信コストの最小化
情報処理学会論文誌に掲載
その拡張版を国際学会PDSIA ’99で発表
既存の逐次化モジュールの実装法
• ロックを付加し呼び出しを逐次化
CPU1
CPU2
ボ
CPU3
既存の方法の問題 (1)
• ロック操作で大きなメモリアクセス遅延
– 同じアドレスへのアクセスの衝突
→アクセスコストの飛躍的増加
CPU2
CPU1
CPU3
既存の方法の問題 (2)
• 更新された情報の読出でキャッシュミス
– 異なるプロセッサが交代で実行するため
CPU1
CPU2
ボ
a, b
CPU3
Amdahlのランタイム技術
• アクセス衝突
→ 呼び出しデータ(タスク)のリスト作成
• 複数の呼び出しを1プロセッサが連続実行
CPU2
f(5)
担当するぞ!
CPU1
ボ
a, b
f(3)
CPU3
f(7)
Amdahlのランタイム技術
• アクセス衝突
→ 呼び出しデータ(タスク)のリスト作成
• 複数の呼び出しを1プロセッサが連続実行
f(5)
f(3)
CPU1
CPU2
f(7)
ボ
a, b
CPU3
この方法がもたらす利益
• ロック操作の大幅減少
– 例: 1回ロック操作して、30個メソッド実行
– 全部消えはしない
• 連続実行中:
オブジェクトの読出と更新
⇔ キャッシュの読出と更新
• ボトルネックに常にプロセッサ
Amdahlのコンパイル時最適化
• メモリ読出コストをさらに削減
– Prefetch 命令の挿入
– 手続き間 register promotion
これの実行中
この情報をprefetch
f(5)
CPU1
f(3)
ボ
f(7)
a, b
連続実行中はa,b
をレジスタに置く
実験
• アプリケーション
– N body, RNA
• 比較したもの
– C + Solaris threads + task queue
• Spin locks, mutex locks
– Amdahl
• Spin locks, mutex locks, 我々の提案する方法
• Sun Enterprise 10000 (64 CPU)
RNA
20000
C + Solaris threads
(spin)
C + Solaris threads
(mutex)
Amdahl (spin)
time (msec)
15000
10000
Amdahl (mutex)
5000
Amdahl (detach)
0
0
10
20
30
40
number of processors
50
60
N body, 木作成フェーズ
8000
C + Solaris threads
(spin)
C + Solaris threads
(mutex)
Amdahl (spin)
time (msec)
6000
4000
Amdahl (mutex)
2000
Amdahl (detach)
0
0
10
20
30
40
number of processors
50
60
N body, 全フェーズ合計
15000
time (msec)
C + Solaris threads
(spin)
C + Solaris threads
(mutex)
Amdahl (spin)
Amdahl (mutex)
Amdahl (detach)
0
0
10
20
30
40
number of processors
50
60
非衝突時の性能
Cで書いたマイクロベンチマーク
no lock
roundrobin
spin
ticket
MCS
Solaris mutex
block
Amdahl
1200
time (msec)
1000
800
600
400
200
0
•Amdahlの方法の実行時間:
•単純なblocking lockの0.92倍
•単純なspin lockの1.32倍
Part 2
複数の排他的な操作を
融合する機構
情報処理学会論文誌に掲載
既存の枠組みの問題
• プログラムの動的挙動に適応する効率化支援
機構が少ない
– 我々の観測: アクセス衝突時に生じる効率化の機会を
有効利用できていない
重複して呼び出し
CPU1
window
repaint
CPU2
repaint
CPU3
repaint
Amdahlのアプローチ
• 排他メソッドの複数の呼び出しの融合
– 動的に逐次化された2つの呼び出しを融合
– プログラマが融合規則を記述
プログラム例 (1/2)
class Window {
…
sync repaint() {
…
}
融合規則
fusion repaint() & repaint() {
repaint();
}
}
repaintを「まびき」
プログラム例 (2/2)
class Buffer {
int len;
double elements[...];
...
sync void put(double v) { elements[len++] = v; }
sync double get() { return elements[--len]; }
fusion put(v) & get() {
return v;
}
}
融合規則
putとgetを「バイパス処理」
融合処理の実装
タスクリストの操作で実現
専念!
CPU2
♪
repaint
CPU1
window
repaint
CPU3
repaint
この融合の研究の広い見方
• 並列言語ならではの効率化の機会を指摘した
– 逐次言語:
x = y-2;
x += 3;
x = y+1;
– 並列言語: 文面に現れない制御フロー
• 既存研究の盲点
val
+=1;
val
+=2;
val
+=3;
実験
• ImageViewer
– repaint & repaint → repaint
• FileWriter
– write & write → strcat + write
• RNA
– inc & inc → inc
ImageViewer
no fusion
fusion
time (msec)
20000
15000
10000
5000
0
0
2
4
6
8
number of processors
10
12
FileWriter
no fusion
fusion
time (msec)
5000
2500
0
0
10
20
30
40
number of processors
50
60
RNA
no fusion
fusion
time (msec)
6000
4000
2000
0
0
10
20
30
40
number of processors
50
60
Part 3
プロセッサ数の動的調節による
メモリ消費量の制御
単純な実装における問題
• ボトルネックにおける大きなメモリ消費量
CPU2
f()
f()
CPU3
...
f()
…..
CPU1
ボ
生産者消費者アプリケーション一般が共有
CPUn
メモリ消費量拡大による悪影響
• Cache miss, page faultの増加
– Working setの増加による
• 他ジョブで使えるメモリが減少
– 1つの邪悪なプログラムが、その計算機上の
全プログラムを凍らせうる
Motivating Example
ボトルネックに付加されるタスク数: 数百のオーダ
←
タ
ス
ク
数
我々の目標
• 1つのオブジェクト(モジュール)に付加
されるタスク数の最大値を小さく抑える
– 例:各オブジェクトに最大64個
– 「メモリ消費量の制限⇔タスク数の制限」
と問題を限定
目標達成のための単純な方法
• タスク数 = 閾値
→タスクを入れようとするCPUはスピンして待つ
64
…..
f()
CPU1
ボ
f()
CPU3
デッドロック発生!
(詳細は論文を参照)
f()
我々はより緩い目標をめざす
• Soft limitをほとんどの場合に越えない
soft limit
タ
ス
ク
数
時間
我々のアプローチの概要
• プロセッサ数の動的調節でタスク数を制御
– タスク数がsoft limitを越えそう
→プロセッサ減らす
タスク生成ペースを遅らせる
– タスク数がsoft limitを越える気配なし
→減らしたプロセッサを復活させる
Amdahlの実装
生存可能プロセッサ数カウンタ
現プロセッサ数カウンタ
28
50
定期的に更新
f()
CPU1
ボ
脱退!
CPU3
...
f() …..
CPU2
CPU50
プロセッサの脱退
thread
thread
thread
thread
thread
thread
thread
CPU15
CPU37
プロセッサの増加
生存可能プロセッサ数カウンタ
48
現プロセッサ数カウンタ
31
CPU1
CPU33
CPU2
定期的にチェック
...
CPU32
CPU31
生存可能プロセッサ数の決定法
• 次のカウンタ更新時のタスク数を予測
– 過去の履歴からタスクが入るペース、出るペースを予測
• その数がsoft limitを越えないよう、入るペースを調節
– 仮定: 入るペース∝プロセッサ数
soft limit = 64
...
...
20
プロセッサ数を 20/60=1/3 に
...
ボ
44
60
実験結果
• ほとんどの時間でsoft limit以下
• タスク数小 → プロセッサ数増
•最大タスク数 < 2×soft limit
実行時間 (60プロセッサ上)
numprocessors fixed
numprocessors varied
normalized execution time
2
1.5
1
0.5
0
Fib&Memwrite
RNA
N body
(Part 4)
クリティカルパスの実行時計算
国際学会 HIPS 2000 で発表
(LNCS vol. 1800)
クリティカルパスの実行時計算
• プログラムにコードを挿入
• クリティカルパスを求めつつプログラムを実行
• Cilk [Blumofe et al. 95],
Paradyn [Hollingsworth 98]
• クリティカルパスの利益
– 性能モデルの調査と検証を
助ける
– チューニングすべき場所の
発見に役立つ
我々がやったこと
• 既存の方法を改良
– メモリ通信コストを考慮
– 第一級通信データ構造の導入
• 改良した方法を並列言語Schematicに実装
– 実験で有効性を確認
関連研究 (1/3)
• 互いに干渉しない排他処理間の並行性抽出
– ICC++ [Chien et al. 96], OPA [Yasugi et al. 98],
Schematic [Taura et al. 96], Reader-writer locks
• Associativeな操作の並行実行
– CA [Chien 91], Reduction [Fisher et al. 94],
Adaptive object replication [Rinard et al. 99]
衝突した複数の排他操作
干渉しない
Associative
関連研究 (2/3)
• Locality-Enhanced Staged Server [Larus 00]
– 似た操作を固めて実行して局所性向上
– まだアイデア段階。実験結果なし
• Network combining [Gottlieb et al. 83]
– ネットワークスイッチによる複数の命令の融合
• プログラム変換による複数の処理の融合
– Bird-Meertens Formalism [Bird 89], Loop fusion,
Deforestation [Wadler 90], Parallel scans,
プログラム融合変換 [Onoue et al. 97]
– 静的に検出できる連続した操作を静的に融合
関連研究 (3/3)
• プロセッサ数の動的調節
– [Hall et al. 97], [Thitikamol et al. 99], [Yue et al. 96], [WernerKytölä et al. 00], [Nguyen et al. 96], [Severance 96]
– 過去の性能を基にイテレーションの切れ目や
並列ループの直前のみで調節
• Congestion avoidance for TCP
– [Jacobson 88], [Jain et al. 97], [Brakmo et al 95]
– データ生成ペースの動的調節という点で共通
• Ninja [Welsh et al. 2000]
– サーバの要求キューの長さの制限
– まだアイデア段階。実験結果なし
今後の課題
• 各排他処理実装の性能のよりよい理解
– 「なぜ我々の方式が速いか」を形式的に議論
• 正しい融合規則の記述の支援
– 明らかに誤った融合規則を静的に検出
• 性能向上を強く志向したプロセッサ数制御
まとめ
• 満足のいく性能モデルの実現に大きく
近づける並列言語実装技術を提案
極限まで近づけた!
全体性能
最低性能のモジュールの性能
(GUI, I/O, mem. allocator, counter…)
• プロセッサを投入しすぎたときの悲劇を最小化
• 「軽いスレッド + 排他メソッド」による
快適な並列プログラミングモデルを維持
Amdahlがもたらすもの
単純でないプログラム
資産
Amdahlによる
並列実行
値下がりしない
株
低
高 リスク
高リターン
逐次実行維持
タンス預金
低リスク
低リターン
並列処理がより広く普及!
並列プログラマは待望のエル・ドラドを獲得!
おわり
• Visit
http://www.yl.is.s.u-tokyo.ac.jp/~oyama/publications/