Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Lock Algorithm 色々

Lock Algorithm 色々

Lock の基本おさらい
Lock アルゴリズムの戦略
高速化

Avatar for Takashi HOSHINO

Takashi HOSHINO

March 03, 2023
Tweet

More Decks by Takashi HOSHINO

Other Decks in Technology

Transcript

  1. Lock の基本おさらい • Lock 取得 → クリティカルセクション実行 → Lock 解放

    • クリティカルセクション: • 複数スレッドで共有している対象データの操作を行う処理 • Reader-writer lock は Exclusive lock の他 Shared lock が取れる • Exclusive (write) lock: • 他の誰もクリティカルセクションに入れない • 対象データを読み書きするために使う • Shared (read) lock: • Exclusive lock を取ろうとするスレッドクリティカルセクションに入れない • 対象データを読むために使う • 複数スレッドが対象データを同時に読めるため性能を上げられる 3
  2. データ構造 • Mutex (object) • Lock する対象データ毎に必要なデータ構造 (カウンタその他) • Lock

    (object) • Lock を取っている間管理するデータ構造 (mutex pointer その他) 4 C++ STL の std::mutex と std::unique_lock が対応する
  3. Fairness (公平性) • Task-fair: • Request 発行順に Lock が取れる (Strict

    FIFO fashion) • Task-fair-RR (オレオレ定義) • Write lock 間、Write lock と Read lock 間の順番は入れ替わらない • Bounded-bypass • どんな Request も高々定数回しか抜かされない • Starvation-free • どんな Request も無限に抜かされることはない • Request 発行順は Queue に並んだ順番で考えることが多いが、手法によっては順番が判然としな いこともあるので、Bounded-bypass や Starvation-free については Lock を試み始める実時刻順 だと解釈するのが妥当 5
  4. Lock アルゴリズムの主な戦略 3 つ • Spin lock • 単に Mutex

    上で条件が満たされるまで Spinwait する • Read と Write の公平性が担保できない • Ticket lock • Ticket の仕組み: 取得と返却は別の Cacheline (in, out) にする • Mutex(out) 上で Spinwait する • Task-fair にできる • Queue lock • Request queue に並ぶという仕組み • 各 Request (node) 上で Spinwait する • Task-fair にできる 6
  5. Spin lock • Mutex • Integer 1 つのみ保持 • 0

    は Unlocked、-1 は Write locked、正の整 数であれば Read locked しているスレッド の数を表す • 操作 • 状態遷移に CAS or LL/SC が必要 • もっとカッコイイ命令があれば……(後述) • 公平性の欠如 • 一旦 Read locked になって Reader が多 い状態が続くと、いつまでたっても Unlocked にならず、Writer が Starve する 7
  6. Ticket lock • Mutex • 整数を 2 つ使う: in, out

    (オーバーフローOK) • 操作 • (1) in を FETCH_ADD し、返り値を自分の Ticket とする • (2) out を Spinwait して自分の Ticket の 値になるまで待つ • (3) out を FETCH_ADD し、待ってる人に 通知する • Reader-writer lock では in, out を 2 つ用意 • rin, win (ふたつでひとつ) • rout, wout (ふたつでひとつ) 8
  7. Queue lock • Mutex • Tail pointer を保持 • 操作

    • tail と Request node (self) pointer を Atomic SWAP • 前の値が Request node pointer (prev) なら prev から self にリンクを貼る • Unlock するときに次 Node に通知 • Queue を空にするときだけ CAS を使用 • Reader-writer lock にするには追加操作 が必要 • Counter 操作 vs Queue 操作や、隣合う Read lock request 同士の同期が複雑 9
  8. 高速化のための原則 • (1) 皆がアクセスする Cacheline はほぼ読み込み専用にする • SHARED state に保つということ

    • たまに書くくらいなら外からやっても問題ない • (2) 変更する Cachline は他スレッドがほぼ触らないようにする • MODIFIED/EXCLUSIVE state を保つということ • たまに読むくらいなら外からやっても問題ない • Spinwait はダメ、絶対 10
  9. NUMA aware/oblivious • 最近の共有メモリマシンは NUMA architecture を採用 • Non-Uniform Memory

    Access • アクセスはできるけど、遅延や帯域が異なる構成 • NUMA node: CPU core とメモリがそれぞれ属す単位 • 各 CPU コアにとって、同一 NUMA node 内のメモリは「近い」 • NUMA-aware • NUMA 構造を理解していて、メモリアクセスを最適化できること • 具体的には L3 miss (NUMA node 間の Cache coherence control) を減らす • NUMA-oblivious • NUMA 構造について知らないこと (大概は性能が出ない) • NUMA 構造について知らないが NUMA でもうまく動くという意味で使われる こともある 11
  10. NUMA 環境で高速化する方法 (RW lock) • 方法(1): NUMA node 毎のデータを持つ •

    Reader counter を分割 (0 まで待つ Writer の負担増) • Local queue を用意 (Local → Global の順番で並ぶ) • 例: Cohorting lock(2012,2013), CST lock(2017) • 方法(2): Queue 並べ替え • NUMA node 毎にまとめる • 例: Shfl lock(2019) • 方法(3): Hash table を使う • 登録したら Read lock 扱い (Writer は Table 全チェック) • 例: BRAVO (2019) 12
  11. CPU の進化に期待 • Hardware Transactional Memory (HTM) • Intel TSX

    (サーバ向けでなんとか生きてる?) • Power8, Power9 (Power10 で削除されたらしいorz) • フォーラムスレッド: Hardware Transactional Memory, the end? https://www.realworldtech.com/forum/?threadid=208244&curpostid=208244 Linus Torvalds(たぶん本人) が複数コメントしている • Atomic 命令の進化 • CMPccXADD by Intel たぶん Spin reader-writer lock が今よりも高速になる • フォーラムスレッド: Remote atomics, not relaxed https://www.realworldtech.com/forum/?threadid=209117&curpostid=209138 Linus は ( ´∀`)人(´∀` )ナカーマ だったのかw 13