Diese Präsentation wurde erfolgreich gemeldet.
Wir verwenden Ihre LinkedIn Profilangaben und Informationen zu Ihren Aktivitäten, um Anzeigen zu personalisieren und Ihnen relevantere Inhalte anzuzeigen. Sie können Ihre Anzeigeneinstellungen jederzeit ändern.
キャッシュコヒーレントに囚われ 
ない並列カウンタ達 
#DSIRLNP 
@kumagi
この発表について 
Data Structure!
キャッシュ? 
• CPUが高速化のためにメモリの一部を切り出 
して複製している物
キャッシュ 
CPUコア 
L1キャッシュ 
L2キャッシュ 
L3キャッシュ 
メモリ
All programmer should know 
• L1 キャッシュ参照......................... 0.5 ns 
• 分岐予測ミス............................ 5 ns 
• L2 ...
キャッシュ 
メモリ
キャッシュコヒーレント? 
• 複数のCPUコアから見えるメモリは同一でな 
いと困る 
• つまり複数のCPUコアのキャッシュは常に最 
新の情報を保持してないと困る 
• だが常に最新の情報を全部のキャッシュに全 
て書き続けるのは速度が出...
キャッシュ 
メモリ 
2つのコアで 
L2キャッシュを共有
キャッシュコヒーレント 
• 複数のL1キャッシュ間で一貫したデータを扱うため 
のキャッシュ間のプロトコル 
• Intel系CPUはMESIFプロトコル 
• AMD系CPUはMOESIプロトコル 
Core1 Core2 
L1キャッシュ...
キャッシュコヒーレントプロトコル 
• キャッシュラインが取る状態名の頭文字が由来 
– Modified: メモリよりもキャッシュの方が新しい(書き換えた) 
– Exclusive: メモリとキャッシュが同一であり、他のコアはこの 
キャッ...
L1キャッシュの状態 
• 1ライン64byteで、アドレスの下位バイトが同 
じ物ごとに8wayずつ32KBまで持っている 
• 1ラインごとにMESIFのどれかのステートを 
持っている 
invalid 
shared 
exclusiv...
キャッシュコヒーレントプロトコル 
• MESI(F)プロトコルはModifiedなデータを他のコアが読み出す際 
にメモリに書き戻す 
• Sharedなデータを書き換える時にはInvalidation要求をブロード 
キャストするためトラフ...
キャッシュを汚す事はギルティ 
• 他のスレッドから繰り返し読む値を書き換え続けると、キャッ 
シュラインのステートはModifiedとSharedの間を行ったりき 
たりすることになる。これは激しいトラフィックを起こす。 
• 更にはModi...
キャッシュを汚す事はギルティ 
共有/localデータから 
Readした場合の速度 
localデータにWrite 
した場合の速度 
共有データにWrite 
した場合の速度 
http://www.1024cores.net/home/l...
まったくスケール 
しない!!!! 
http://www.1024cores.net/home/lock-free-algorithms/first-things-first から
NUMAでのキャッシュコヒーレント 
• 最近のサーバはマルチソケットCPUがよく使 
われる
cc-NUMA 
• 複数のCPUソケットから同一のメモリ空間が 
見えて欲しい(まるでマルチコアCPUのように) 
• キャッシュ衝突するとQPIアクセスの刑 
– かつては拷問にも使われていたQPI経由のキャッ 
シュコヒーレント
All programmer should know 
• L1 キャッシュ参照......................... 0.5 ns 
• 分岐予測ミス............................ 5 ns 
• L2 ...
キャッシュ 
隣のCPUのキャッシュは 
自分のメインメモリよりも遠い!!! 
メモリメモリ
cc-NUMAの時代 
• キャッシュ衝突をとにかく減らすアルゴリズム 
が望まれている
Combining Tree 
• 以下のインタフェースを備えるカウンタ 
– add(int a):数値aを足す 
– read():現在の数値を読む 
• ただしスケーラブル! 
擬似コード 
class counter { 
public...
Combining Tree 
• 1つのキャッシュラインを取り合うのが2スレッ 
ドまでになるようトーナメントを構成する 
• トーナメントでぶつかったスレッドは、先に来 
たスレッドに後に来たスレッドが値を託して待 
つ 
• キャッシュコ...
Combining Tree 
• トーナメントのてっぺんを読めば値が読める 
root
Combining Treeアルゴリズム 
+1 +1 +2 +3 +2 +1
Combining Treeアルゴリズム 
+1 +1 +2 +3 +2 +1
Combining Treeアルゴリズム 
+1 
待 
+3 
+3 
+3 
待
Combining Treeアルゴリズム 
+4 
待 
待 
+6 
待 
待
Combining Treeアルゴリズム 
+10 
待 
待 
待 
待 
待
Combining Treeアルゴリズム 
• 結合法則を用いて計算の合成を行う 
• x + 1 + 1 + 2 + 3 + 2 + 1 
• x + 1 + (1 + 2) + 3 + (2 + 1) 
• x + (1 + 3) + (3...
詳細なアルゴリズム 
• 各ノードはIdle, First, Second, Rootのどれかの 
状態を持つ 
– Idle: どのスレッドも触ってない 
– First: 最初のスレッドが既に触った 
– Second: 二つ目のスレッドが...
Combining Tree 
• 初めに木を登りながらステートの変更を行う 
– Idleな物をFirstにしていく 
– ロックを取ってステートを変えて即アンロック 
Root 
First 
First
Combining Tree 
• 初めに木を登りながらステートの決定を行う 
– Firstを見たらSecondにして第二ロックを獲得 
• こっちのロックはすぐには手放さない 
Root 
First 
Second 
First Firs...
Combining Tree 
• 初めに木を登りながらステートの決定を行う 
– Secondにしたらそこで木を登るの停止 
Root 
First 
Second 
First 
Second
Combining Tree 
• 木を登るのをやめた所で、自分の過去の経 
路の第二ロックを獲得し直しながら値を清算 
Root 
First 
Second 
First 
Second
Combining Tree 
• 木を登るのをやめた所で、自分の過去の経 
路の第二ロックを獲得し直しながら値を清算 
Root 
First 
Second 
+1 +2 
First 
Second
Combining Tree 
• 清算しきった値を最初に自分が登った一番高 
い所に書き込んでアンロックするのが基本戦 
略 
Root 
First 
Second 
First 
+3 
Second
Combining Tree 
• 清算しきった値を最初に自分が登った一番高 
い所に書き込んでアンロック 
Root 
+3 
SFeicrosntd 
Second 
Second 
First
Combining Tree 
• Secondのステートを見たら他のスレッドが清 
算中なのでそれを待つ(第二ロック獲得待ち) 
Root 
Lock! 
SFeicrosntd 
Second 
Second 
Lock! 
First
Combining Tree 
• 清算し終わった値を持って再帰的に自分の 
値として生産する 
Root 
SFeicrosntd 
Second 
Second 
First 
+4
Combining Tree 
• 平均して木の深さnに対して2*n回のロックと 
アンロックを使うことになる 
– 大丈夫なの・・・? 
• Mutex lock/unlock ........................... 25 n...
Combining Tree 
• 衝突がない場合でも2*n回のロック・アンロッ 
ク 
• レイテンシという点において非常に悪い 
– 改良として1ノードに3スレッド以上ぶら下げて木 
の深さを減らすパターンもあるが、複雑さがマッ 
ハでレイ...
Combining Funnel 
• Funnel = 上戸 
• 乱数ベースで負荷を低減 
– アルゴリズムはEliminationに近い 
– Eliminationと組み合わせることも可能 
Counter
Combining Funnel 
• 配列の中のランダムな箇所にCAS命令で自分 
のタスクを置く 
• ランダム時間の待機後、CASでタスクを引き上 
げて次のレイヤーに進む(ここが上戸っぽい) 
+2 +1
Combining Funnel 
• 置こうと思った場所に先客が居たらそいつと 
操作を結合して次のレイヤーに進む 
+3したい 
+2 +1
Combining Funnel 
• 置こうと思った場所に先客が居たらそいつと 
操作を結合して次のレイヤーに進む 
+5せざるを得ない! 
待+1
Combining Funnel 
• 置こうと思った場所に先客が居たらそいつと 
操作を結合して次のレイヤーに進む 
あっ待てって言われてる 
待+1 
+5 
Counter
Combining Funnel 
• カウンタのレイヤーまで到達したらそいつに 
Compare And Swap 
• 感動的に簡単しかも速い
Combining Funnel 
Combining Funnels A Dynamic Approach To Software Combining より
SNZI 
• 数を数えようとするから残念なことになるん 
や!諦めろ! 
– ゼロかどうか分かればええ! 
• Scalable-Non-Zero-Indicatorの略でSNZI 
– pronounced "snazzy" : (和訳)粋...
SNZIのセマンティクス 
• 数字が読めないカウンタ 
• これをスケーラブルにする 
擬似コード 
class snzi { 
public: 
counter() : cnt_(0) {} 
void inc() { cnt_ += 1;...
SNZIの実装 
• キャッシュラインで木構造を作る 
0 
0 0 
ここが0かどうかを 
見れば良い 
0 0 0 0
SNZIの実装 
• 木の各ノードが1CPU 
– 上から数えてi番目のノードはi番目のCPUに割当 
0 
1 
0 1 
0 
01 0 0 0 
root以外を0から1に増やすときには1個上のノード 
の値をインクリメントする 
root...
SNZIの実装 
• 木の各ノードが1CPU 
– 上から数えてi番目のノードはi番目のCPUに割当 
0 
1 
0 1 
0 
01 0 0 0 
root以外を1から0に減らすときには1個上のノード 
の値をデクリメントする 
rootは...
SNZIの実装 
• 木の各ノードが1CPU 
– 上から数えてi番目のノードはi番目のCPUに割当 
0 
1 
0 2 
1 
0 
01 0 0 0 
それ以外のときは普通にインクリメントするだけ 
=上のノードのキャッシュラインに触れず...
SNZI 
• すごくスケールする!!! 
SNZI: Scalable NonZero Indicatorsより
しかもロックフリー!!
SNZIの実装 
• 厳密には複数のスレッドが同一のノードにア 
クセスしに来た際に0⇔1周りで細かい調停が 
必要 
0から1のときは、先に自分の箇所の値を1/2という値にしてから上のノードをインクリメン 
トしにいき、そのあとで1/2を1に...
SkySTMへの適用 
What kinds of applications can benefit from Transactional Memory? より
時間が無くて書けなかったこと 
• STMの高速化のためにSNZIが必要とかいっと 
きながら実際にSNZIをRead-Write-Lockに用い 
たSkySTMは割とあっさりTLRWに負けている 
– TLRWはByteLockっていうまた...
HTM+SNZI 
HTM 
の力 
What kinds of applications can benefit from Transactional Memory? より
Nächste SlideShare
Wird geladen in …5
×

キャッシュコヒーレントに囚われない並列カウンタ達

5.044 Aufrufe

Veröffentlicht am

第6回DSIRNLPで発表した資料。

Veröffentlicht in: Technologie
  • Login to see the comments

キャッシュコヒーレントに囚われない並列カウンタ達

  1. 1. キャッシュコヒーレントに囚われ ない並列カウンタ達 #DSIRLNP @kumagi
  2. 2. この発表について Data Structure!
  3. 3. キャッシュ? • CPUが高速化のためにメモリの一部を切り出 して複製している物
  4. 4. キャッシュ CPUコア L1キャッシュ L2キャッシュ L3キャッシュ メモリ
  5. 5. All programmer should know • L1 キャッシュ参照......................... 0.5 ns • 分岐予測ミス............................ 5 ns • L2 キャッシュ参照........................... 7 ns • Mutex lock/unlock ........................... 25 ns • Main memory 参照...................... 100 ns
  6. 6. キャッシュ メモリ
  7. 7. キャッシュコヒーレント? • 複数のCPUコアから見えるメモリは同一でな いと困る • つまり複数のCPUコアのキャッシュは常に最 新の情報を保持してないと困る • だが常に最新の情報を全部のキャッシュに全 て書き続けるのは速度が出ないので、まるで 本当に全部のキャッシュにすべて書いてるか のように見せかけながらパフォーマンスを出 す必要がある
  8. 8. キャッシュ メモリ 2つのコアで L2キャッシュを共有
  9. 9. キャッシュコヒーレント • 複数のL1キャッシュ間で一貫したデータを扱うため のキャッシュ間のプロトコル • Intel系CPUはMESIFプロトコル • AMD系CPUはMOESIプロトコル Core1 Core2 L1キャッシュコヒーレント L1キャッシュ L2キャッシュ
  10. 10. キャッシュコヒーレントプロトコル • キャッシュラインが取る状態名の頭文字が由来 – Modified: メモリよりもキャッシュの方が新しい(書き換えた) – Exclusive: メモリとキャッシュが同一であり、他のコアはこの キャッシュラインを持っていない – Shared: メモリとキャッシュが同一であり、他のコアもこの キャッシュラインを複製している – Invalid: 正しいキャッシュを持っていないので読むな – Owned: 俺がメモリだ(Shared可能なModified) – Forward: Sharedのボス。アクセスする際にはこいつに伺え
  11. 11. L1キャッシュの状態 • 1ライン64byteで、アドレスの下位バイトが同 じ物ごとに8wayずつ32KBまで持っている • 1ラインごとにMESIFのどれかのステートを 持っている invalid shared exclusive modified 64Byte 全部のラインが独立して それぞれステートが遷移する 32KB forward
  12. 12. キャッシュコヒーレントプロトコル • MESI(F)プロトコルはModifiedなデータを他のコアが読み出す際 にメモリに書き戻す • Sharedなデータを書き換える時にはInvalidation要求をブロード キャストするためトラフィックが混む Modified Exclusive 共有を要求 書き換えた (1個下のメモリへアクセス) 新規に読み出した Shared Invalid Invalidation要求が来た 他のコアから貰った
  13. 13. キャッシュを汚す事はギルティ • 他のスレッドから繰り返し読む値を書き換え続けると、キャッ シュラインのステートはModifiedとSharedの間を行ったりき たりすることになる。これは激しいトラフィックを起こす。 • 更にはModifiedからSharedになる度に下層のメモリに書き 込まなくてはならない うぉー! うぉー! Core1 Core2 L1キャッシュL1キャッシュ L2キャッシュ write read ぎゃー!! write Invalidate
  14. 14. キャッシュを汚す事はギルティ 共有/localデータから Readした場合の速度 localデータにWrite した場合の速度 共有データにWrite した場合の速度 http://www.1024cores.net/home/lock-free-algorithms/first-things-first から
  15. 15. まったくスケール しない!!!! http://www.1024cores.net/home/lock-free-algorithms/first-things-first から
  16. 16. NUMAでのキャッシュコヒーレント • 最近のサーバはマルチソケットCPUがよく使 われる
  17. 17. cc-NUMA • 複数のCPUソケットから同一のメモリ空間が 見えて欲しい(まるでマルチコアCPUのように) • キャッシュ衝突するとQPIアクセスの刑 – かつては拷問にも使われていたQPI経由のキャッ シュコヒーレント
  18. 18. All programmer should know • L1 キャッシュ参照......................... 0.5 ns • 分岐予測ミス............................ 5 ns • L2 キャッシュ参照........................... 7 ns • Mutex lock/unlock ........................... 25 ns • Main memory 参照...................... 100 ns • QPI経由で隣のメモリ参照.............. 200 ns~
  19. 19. キャッシュ 隣のCPUのキャッシュは 自分のメインメモリよりも遠い!!! メモリメモリ
  20. 20. cc-NUMAの時代 • キャッシュ衝突をとにかく減らすアルゴリズム が望まれている
  21. 21. Combining Tree • 以下のインタフェースを備えるカウンタ – add(int a):数値aを足す – read():現在の数値を読む • ただしスケーラブル! 擬似コード class counter { public: counter() : cnt_(0) {} void add(int a) { cnt_ += a; } int read() const { return cnt_; } private: int cnt_; };
  22. 22. Combining Tree • 1つのキャッシュラインを取り合うのが2スレッ ドまでになるようトーナメントを構成する • トーナメントでぶつかったスレッドは、先に来 たスレッドに後に来たスレッドが値を託して待 つ • キャッシュコヒーレントトラフィックを劇的に削 減!
  23. 23. Combining Tree • トーナメントのてっぺんを読めば値が読める root
  24. 24. Combining Treeアルゴリズム +1 +1 +2 +3 +2 +1
  25. 25. Combining Treeアルゴリズム +1 +1 +2 +3 +2 +1
  26. 26. Combining Treeアルゴリズム +1 待 +3 +3 +3 待
  27. 27. Combining Treeアルゴリズム +4 待 待 +6 待 待
  28. 28. Combining Treeアルゴリズム +10 待 待 待 待 待
  29. 29. Combining Treeアルゴリズム • 結合法則を用いて計算の合成を行う • x + 1 + 1 + 2 + 3 + 2 + 1 • x + 1 + (1 + 2) + 3 + (2 + 1) • x + (1 + 3) + (3 + 3) • x + (4 + 6) • x + 10
  30. 30. 詳細なアルゴリズム • 各ノードはIdle, First, Second, Rootのどれかの 状態を持つ – Idle: どのスレッドも触ってない – First: 最初のスレッドが既に触った – Second: 二つ目のスレッドが触った – Root: てっぺん(遷移しない) • 更にノードはロックを2つ持っている
  31. 31. Combining Tree • 初めに木を登りながらステートの変更を行う – Idleな物をFirstにしていく – ロックを取ってステートを変えて即アンロック Root First First
  32. 32. Combining Tree • 初めに木を登りながらステートの決定を行う – Firstを見たらSecondにして第二ロックを獲得 • こっちのロックはすぐには手放さない Root First Second First First Second
  33. 33. Combining Tree • 初めに木を登りながらステートの決定を行う – Secondにしたらそこで木を登るの停止 Root First Second First Second
  34. 34. Combining Tree • 木を登るのをやめた所で、自分の過去の経 路の第二ロックを獲得し直しながら値を清算 Root First Second First Second
  35. 35. Combining Tree • 木を登るのをやめた所で、自分の過去の経 路の第二ロックを獲得し直しながら値を清算 Root First Second +1 +2 First Second
  36. 36. Combining Tree • 清算しきった値を最初に自分が登った一番高 い所に書き込んでアンロックするのが基本戦 略 Root First Second First +3 Second
  37. 37. Combining Tree • 清算しきった値を最初に自分が登った一番高 い所に書き込んでアンロック Root +3 SFeicrosntd Second Second First
  38. 38. Combining Tree • Secondのステートを見たら他のスレッドが清 算中なのでそれを待つ(第二ロック獲得待ち) Root Lock! SFeicrosntd Second Second Lock! First
  39. 39. Combining Tree • 清算し終わった値を持って再帰的に自分の 値として生産する Root SFeicrosntd Second Second First +4
  40. 40. Combining Tree • 平均して木の深さnに対して2*n回のロックと アンロックを使うことになる – 大丈夫なの・・・? • Mutex lock/unlock ........................... 25 ns • QPI経由で隣のメモリ参照.............. 200 ns~ キャッシュ衝突のペナルティを 考えると余裕でペイする
  41. 41. Combining Tree • 衝突がない場合でも2*n回のロック・アンロッ ク • レイテンシという点において非常に悪い – 改良として1ノードに3スレッド以上ぶら下げて木 の深さを減らすパターンもあるが、複雑さがマッ ハでレイテンシはむしろ悪化
  42. 42. Combining Funnel • Funnel = 上戸 • 乱数ベースで負荷を低減 – アルゴリズムはEliminationに近い – Eliminationと組み合わせることも可能 Counter
  43. 43. Combining Funnel • 配列の中のランダムな箇所にCAS命令で自分 のタスクを置く • ランダム時間の待機後、CASでタスクを引き上 げて次のレイヤーに進む(ここが上戸っぽい) +2 +1
  44. 44. Combining Funnel • 置こうと思った場所に先客が居たらそいつと 操作を結合して次のレイヤーに進む +3したい +2 +1
  45. 45. Combining Funnel • 置こうと思った場所に先客が居たらそいつと 操作を結合して次のレイヤーに進む +5せざるを得ない! 待+1
  46. 46. Combining Funnel • 置こうと思った場所に先客が居たらそいつと 操作を結合して次のレイヤーに進む あっ待てって言われてる 待+1 +5 Counter
  47. 47. Combining Funnel • カウンタのレイヤーまで到達したらそいつに Compare And Swap • 感動的に簡単しかも速い
  48. 48. Combining Funnel Combining Funnels A Dynamic Approach To Software Combining より
  49. 49. SNZI • 数を数えようとするから残念なことになるん や!諦めろ! – ゼロかどうか分かればええ! • Scalable-Non-Zero-Indicatorの略でSNZI – pronounced "snazzy" : (和訳)粋な、おしゃれな、 優雅な、エレガントな、格好いい
  50. 50. SNZIのセマンティクス • 数字が読めないカウンタ • これをスケーラブルにする 擬似コード class snzi { public: counter() : cnt_(0) {} void inc() { cnt_ += 1; } void dec() { cnt_ -= 1; } bool is_zero() const { return cnt_ == 0; } private: int cnt_; };
  51. 51. SNZIの実装 • キャッシュラインで木構造を作る 0 0 0 ここが0かどうかを 見れば良い 0 0 0 0
  52. 52. SNZIの実装 • 木の各ノードが1CPU – 上から数えてi番目のノードはi番目のCPUに割当 0 1 0 1 0 01 0 0 0 root以外を0から1に増やすときには1個上のノード の値をインクリメントする rootは常に普通にインクリメントするだけ
  53. 53. SNZIの実装 • 木の各ノードが1CPU – 上から数えてi番目のノードはi番目のCPUに割当 0 1 0 1 0 01 0 0 0 root以外を1から0に減らすときには1個上のノード の値をデクリメントする rootは常に普通にデクリメントするだけ
  54. 54. SNZIの実装 • 木の各ノードが1CPU – 上から数えてi番目のノードはi番目のCPUに割当 0 1 0 2 1 0 01 0 0 0 それ以外のときは普通にインクリメントするだけ =上のノードのキャッシュラインに触れずに済む
  55. 55. SNZI • すごくスケールする!!! SNZI: Scalable NonZero Indicatorsより
  56. 56. しかもロックフリー!!
  57. 57. SNZIの実装 • 厳密には複数のスレッドが同一のノードにア クセスしに来た際に0⇔1周りで細かい調停が 必要 0から1のときは、先に自分の箇所の値を1/2という値にしてから上のノードをインクリメン トしにいき、そのあとで1/2を1にCASを試みる。もし上のノードのインクリメントに成功した 後に1/2→1のCASに失敗したら上のノードをデクリメントしておく • デクリメントの数はその前に行われたインクリ メントの数を越えては行けない(Read-Write ロックなどに用いるには充分)
  58. 58. SkySTMへの適用 What kinds of applications can benefit from Transactional Memory? より
  59. 59. 時間が無くて書けなかったこと • STMの高速化のためにSNZIが必要とかいっと きながら実際にSNZIをRead-Write-Lockに用い たSkySTMは割とあっさりTLRWに負けている – TLRWはByteLockっていうまた別のロックプロトコ ルを用いてる(こっちの話はまた今度) • SNZIのためにHTMを用いたやつがあって凄い 速い – HTMの使い方についてもまた今度
  60. 60. HTM+SNZI HTM の力 What kinds of applications can benefit from Transactional Memory? より

×