Slide 1

Slide 1 text

Lock Algorithm 色々 星野 喬 1 rev.20230303a 公開版

Slide 2

Slide 2 text

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

Slide 3

Slide 3 text

Lock の基本おさらい • Lock 取得 → クリティカルセクション実行 → Lock 解放 • クリティカルセクション: • 複数スレッドで共有している対象データの操作を行う処理 • Reader-writer lock は Exclusive lock の他 Shared lock が取れる • Exclusive (write) lock: • 他の誰もクリティカルセクションに入れない • 対象データを読み書きするために使う • Shared (read) lock: • Exclusive lock を取ろうとするスレッドクリティカルセクションに入れない • 対象データを読むために使う • 複数スレッドが対象データを同時に読めるため性能を上げられる 3

Slide 4

Slide 4 text

データ構造 • Mutex (object) • Lock する対象データ毎に必要なデータ構造 (カウンタその他) • Lock (object) • Lock を取っている間管理するデータ構造 (mutex pointer その他) 4 C++ STL の std::mutex と std::unique_lock が対応する

Slide 5

Slide 5 text

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

Slide 6

Slide 6 text

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

Slide 7

Slide 7 text

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

Slide 8

Slide 8 text

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

Slide 9

Slide 9 text

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

Slide 10

Slide 10 text

高速化のための原則 • (1) 皆がアクセスする Cacheline はほぼ読み込み専用にする • SHARED state に保つということ • たまに書くくらいなら外からやっても問題ない • (2) 変更する Cachline は他スレッドがほぼ触らないようにする • MODIFIED/EXCLUSIVE state を保つということ • たまに読むくらいなら外からやっても問題ない • Spinwait はダメ、絶対 10

Slide 11

Slide 11 text

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

Slide 12

Slide 12 text

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

Slide 13

Slide 13 text

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