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

Lock Algorithm 色々

Lock Algorithm 色々

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

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