キャッシュコヒーレントに囚われない並列カウンタ達
Upcoming SlideShare
Loading in...5
×
 

Like this? Share it with your network

Share

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

on

  • 75 views

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

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

Statistics

Views

Total Views
75
Views on SlideShare
68
Embed Views
7

Actions

Likes
0
Downloads
2
Comments
0

1 Embed 7

https://twitter.com 7

Accessibility

Categories

Upload Details

Uploaded via as Microsoft PowerPoint

Usage Rights

© All Rights Reserved

Report content

Flagged as inappropriate Flag as inappropriate
Flag as inappropriate

Select your reason for flagging this presentation as inappropriate.

Cancel
  • Full Name Full Name Comment goes here.
    Are you sure you want to
    Your message goes here
    Processing…
Post Comment
Edit your comment

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

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