2 ポイント 投稿者 GN⁺ 2024-10-03 | 1件のコメント | WhatsAppで共有
  • 高い競合 状況では Mutex 実装の差が大きく現れ、Cosmopolitan Libc の pthread_mutex_t は Windows と Linux の主要実装よりも短い実行時間と低い CPU 使用量を示した
  • Windows の 24-core Threadripper 29070WX テストでは、Cosmopolitan は Microsoft SRWLOCK より 2.75 倍高速で、CPU リソースの使用量は 18 倍少なかった
  • Linux の 96-core Threadripper Pro 7995WX では、glibc より 3 倍、musl libc より 11 倍高速で、CPU 時間の差はさらに大きく広がった
  • MacOS M2 Ultra では Apple Libc がわずかに上回り、Cosmopolitan は ARM 環境で XNU の ulock システムコール に依存する単純なアルゴリズムを使っている
  • 性能の基盤は Google の nsync 統合であり、CAS の高速パス、待機キュー、futex/ulock/WaitOnAddress()、飢餓防止と designated waker 設計が中核となっている

競合 Mutex ベンチマークの方法

  • テストでは 30 個のスレッド を作成し、各スレッドが同じグローバル整数 g_chores100,000 回 増加させる
  • 各インクリメント処理は pthread_mutex_lock()pthread_mutex_unlock() の間にある非常に小さなクリティカルセクションで実行される
  • 測定値はマイクロ秒単位で、3 種類の時間を区別している
    • wall time: プログラム実行にかかった実時間で、スレッド生成と join のオーバーヘッドを含む
    • user time: ユーザー空間で消費した CPU 時間
    • system time: カーネルで消費した CPU 時間
  • 複数スレッドが並列実行されるため、user time と system time の合計は wall time より大きくなることがある
  • 非競合の状況では実装間の性能差は概して小さいが、競合状況 では Mutex 設計の差が大きく現れる

Windows: SRWLOCK より高速な Cosmopolitan

  • Windows テストは 24-core Threadripper 29070WX で実施された
  • Mark Waterman の MutexShootout は、高競合シナリオにおいて Windows の SRWLOCK を最も強力な実装と評価していた
  • 同じ条件で Cosmopolitan pthread_mutex_t は、SRWLOCK より短い wall time と低い CPU 使用量を記録した
実装 wall time user time system time
Cosmopolitan pthread_mutex_t 148,940µs 328,125µs 62,500µs
Microsoft SRWLOCK 410,416µs 5,515,625µs 1,640,625µs
Microsoft CRITICAL_SECTION 949,187µs 7,937,500µs 5,078,125µs
MSVC 2022 std::mutex 991,750µs 12,156,250µs 4,031,250µs
spin lock 1,165,435µs 24,515,000µs 15,000µs
Cygwin pthread_mutex_t 9,780,803µs 1,937,000µs 6,156,000µs
  • Cosmopolitan Mutex は Microsoft SRWLOCK より 2.75 倍高速 で、CPU リソースの使用量は 18 倍少ない
  • POSIX 実装を Windows に提供する Cygwin Mutex と比べると 65 倍高速
  • Cygwin Mutex はこのユースケースでは spin lock よりも遅い結果になった

Linux: wall time よりさらに大きい CPU 時間の差

  • Linux テストは 96-core Threadripper Pro 7995WX で実施された
実装 wall time user time system time
Cosmopolitan pthread_mutex_t 36,905µs 44,511µs 23,492µs
glibc pthread_mutex_t 101,353µs 150,706µs 2,724,851µs
spin lock 202,423µs 4,694,749µs 2,000µs
Musl libc pthread_mutex_t 411,013µs 2,167,898µs 9,926,850µs
  • Cosmopolitan Mutex は glibc より 3 倍musl libc より 11 倍 高速
  • CPU 時間ベースでは glibc より 42 倍、musl libc より 178 倍 少なく使う
  • すべてのスレッドが直列化された処理を行う必要があるワークロードでは、Cosmopolitan は htop 上で 1 コアしか動いていないように見えることがある
  • 同じ状況で glibc や musl libc は CPU 使用量を大きく埋めることがあり、同じサーバー上で複数の処理を走らせる際の負担が大きくなる

MacOS: Apple Libc がわずかに優勢

  • MacOS テストは M2 Ultra で実施された
実装 wall time user time system time
Apple Libc 52,263µs 43,202µs 911,009µs
Cosmopolitan pthread_mutex_t 54,700µs 63,055µs 1,003,674µs
  • MacOS M2 ARM64 では Apple Libc が Cosmopolitan Mutex よりわずかに高速
  • Cosmopolitan の一般的な Mutex 実装はこのプラットフォームではうまく動作しない
  • MacOS ARM では、Cosmopolitan は Ulrich Drepper の Futexes Are Tricky に基づく、より単純なアルゴリズムを使用している
  • この方式では重い処理の大半を XNU の ulock システムコール に任せており、その結果 Apple 実装とほぼ同等の性能を出している

性能の基盤: nsync 統合

  • Cosmopolitan Mutex の性能の鍵は、Google の nsync ライブラリ統合にある
  • nsync は GitHub スター 371 件のライブラリで、Google の Mike Burrows によって書かれた
  • Cosmopolitan への統合過程では、次の作業が行われた
    • nsync の Mutex unlock 関数で長らく見つかっていなかったバグを発見して修正した
    • AARCH64 で C11 アトミック演算へ移植し、競合時の nsync Mutex を upstream nsync より 30% 高速 にした
    • futex のようなシステム統合を新たに書き直し、ランタイム移植性を実現した
    • POSIX スレッドキャンセルと滑らかに動作するようにした

nsync の動作方式

  • nsync はロックを素早く取得するため、最初に 楽観的 CAS(compare and swap) を即座に試みる
  • ロックを取得できなければ、呼び出しスレッドを待機者の 双方向リンクリスト に追加する
    • 各待機者は、独立した別キャッシュライン上に自分専用のセマフォを持つ
    • 待機状態に入ったスレッドは、もはや主ロックに触れない
    • これは複数コアが同じキャッシュラインに触れることで生じる通信オーバーヘッドを減らすうえで重要である
    • 関連する背景として Ulrich Drepper の What Every Programmer Should Know About Memory が挙げられている
  • nsync は OS の futex を使ってスレッドをスリープさせる
    • MacOS では futex は ulock と呼ばれる
    • Windows では WaitOnAddress() が futex の役割を果たす
    • Cosmo がサポートする OS の中で NetBSD だけは futex がなく、POSIX セマフォをカーネル空間で実装しており、各セマフォごとに新しいファイルディスクリプタが必要になる
  • nsync は “long wait” の概念で 飢餓(starvation) を避ける
    • 待機者が 30 回起こされたにもかかわらず毎回内部的にロック取得に失敗した場合、まだ待っていないスレッドがロックを取得できないよう、ロックにビットを追加する
    • このビットがあると、待機キューがある程度空くまで新規に入ってきたスレッドの初回 CAS は失敗する
  • 小さなクリティカルセクションで競合するユースケースは、designated waker の概念によって高速化される
    • あるスレッドが起床してロックを取得しようとする時、主ロックにビットがセットされる
    • nsync では unlock 関数が次の待機スレッドを起こす責任を持つ
    • このビットのおかげで、unlock 中のスレッドはすでに起きているスレッドがいる場合に 2 番目の待機者を起こす必要がない
  • 関連するソースコードは cosmopolitan/third_party/nsync/mu.ccosmopolitan/libc/intrin/pthread_mutex_lock.c にある

実サービスと検証コード

  • Cosmo Mutex を使ったライブデモとして http://ipv4.games/ サーバーを見ることができる
  • このサービスは 2 コア GCE VM で動作しており、これまで最大 49,131,669 IP 規模のボットネット DDoS に耐えてきた
  • nsync によって SQL クエリをバックグラウンドスレッドへ移し、スレッド同士がメッセージを送り合う構造を使えるようになった
  • 状態指標は /statusz で確認できる
  • ベンチマークコードは gettimeofday() で wall time を測り、getrusage() で user time と system time を測定する
  • 最後に g_chores == THREADS * ITERATIONS を確認して、すべてのインクリメント処理が実行されたことを検証する

Spin lock を見るときの注意点

  • 非競合の状況では Mutex 実装間の差は小さく、数行の spin lock のほうが良い場合もある
  • しかし spin lock は、本当に他に選択肢がない時だけ使うべきである
  • カーネルのように極端に低レベルの制約があり、より複雑な方式を使いにくい場所では有用である
  • nsync lock の内部実装詳細として spin lock が使われることもある
  • lock 性能を wall time だけで見ると spin lock が良く見えることがあるため、getrusage()CPU 時間 まであわせて確認する必要がある

1件のコメント

 
GN⁺ 2024-10-03
Hacker News のコメント
  • 新しいミューテックス実装との比較はいつも興味深いが、このベンチマーク手法は気に入らない。ほとんどマイクロベンチマークのように見える。
    高速なロックを実際にデプロイしている人たちは、たいてい非常に大きなマルチスレッドプログラムを主な性能テスト手段にしている。クリティカルセクションの長さ、競合するスレッド数、競合の度合いがさまざまに変わる複雑なワークロードでは、ミューテックスを速くしたり遅くしたりする要因が変わるようだ。
    参考までに、私は WebKit の高速ロックを書き、ロック実装用の ParkingLot 抽象化を発明し(Rust と Unreal Engine でも使われている)、以前には Java 用の高速ロックに関する研究と論文も行った。

    • デスクトップアプリを作ってきた立場から補足すると、数十個のスレッドが頻繁に回るアプリでは、競合が激しくない場合の性能数値が見たい。
      リアルタイムオーディオのプログラマーとしては、まだロックされていないミューテックスを取得するコストのほうが重要だ。私たちのアプリではこの状況が圧倒的に多い。同様に、N 個のスレッドが競合するときではなく、失敗する try-lock 操作のコストも知りたい。
      Cosmopolitan はオープンソースなので自分で測定することもできるが、それでも物足りない。
    • 同じことを思った。ミューテックスには複数の種類があり、特定のワークロードではどれかがより適している。DistributedMutexSharedMutex が思い浮かぶ(https://github.com/facebook/folly/blob/main/folly/synchroniz...https://github.com/facebook/folly/blob/main/folly/SharedMute...)。
      ハッシュマップと同じで、単一のハッシュマップがあり得るすべてのワークロードで優れていることはまれだ。
    • このスタイルのミューテックスは Python 3.13 の PyMutex にも使われる予定だ。3.13 以前の PyThread_type_lock より PyMutex がどれほど速いかを示す実際のベンチマークがある。
    • 確かにマイクロベンチマークであり、一般的な性能を代表していない可能性が高い。このページは OS ベンチマーキングの慣行について良い基準を示している。ただし、やや学術寄りだ: https://gernot-heiser.org/benchmarking-crimes.html
    • その特定のベンチマークは、むしろ望ましくない挙動、たとえば病的な不公平性を好む可能性が高い。最適なスケジューリングは、1 つ目のスレッドのインクリメント操作をすべて実行し、その次に 2 つ目のスレッドのものをすべて実行する、という形になる。そうすればプロセッサ間トラフィックが最小化されるからだ。
      ロック取得失敗時に固定時間(例: 100µs)スリープするミューテックスは、ほぼ常に処理をひとかたまりにし、この挙動に近づけてベンチマークで「勝つ」ことができる。しかし実際のアプリケーションで少しでも競合があると、そのようなミューテックスはひどいものになる。
      このミューテックスが悪いとか pthread ミューテックスが良いという意味ではなく、そのマイクロベンチマークが実際のアプリケーション性能を予測できるようなものを測っていないという意味だ。
  • 「Cosmopolitan Mutex が優れている理由は nsync というライブラリを使っているから」という部分について、nsync は初めて聞いたが、Mike Burrows は Google の本番用ミューテックス実装も書いている: https://github.com/abseil/abseil-cpp/blob/master/absl/synchr...
    なので、なぜこのミューテックス実装がベンチマークから外れているのか気になる。そして macOS で __ulock に委譲するなら、libc++ の atomic ライブラリにある wait()notify_one() メンバー関数だけを使って、もっと単純に実現できそうだ。
    以前、Rust のミューテックス実装改善に関する大きなスレッドもあった: https://github.com/rust-lang/rust/issues/93740#issuecomment-... 興味深いのは、人気のあるほぼすべてのミューテックス実装の内部動作が詳しく議論されていることだ。

    • 私が AV に入ったとき、Mike はすでに伝説的存在だった。検索エンジンをもっと速くしなければならないたびに、彼がやって来て中核関数をいくつか書き直し、元の仕事に戻っていったという伝説があった。
      本当かもしれないが、直接確認することはできない。効率を重視する、極めて頭の切れるエンジニアだった。ただし、私たちは 1 台のサーバーを長く運用していたわけではない。
    • Burrows は Burrows-Wheeler 変換、Bigtable、Dapper、Chubby などにも関わっていた。
    • その Rust のスレッドは最終的にはそこにたどり着くが、基本的には Mara の作業に関するもので、だから 2023 年 1 月に出た彼女の本にも言及されている。
      現在の Rust のミューテックス実装は今年初めに入ったもので、Linux では大きく違わないかもしれないが、Windows と Mac では新しい作業だと理解している。
      それでも Mara が他の実装の内部を説明した内容は依然として興味深いが、自分の状況では古い情報ではないか確認したほうがよい。
    • Abseil のミューテックス実装がベンチマークから外れた理由は、C ではなく C++ 実装だからかもしれない。推測だ。
    • Mike Burrows は ACM の賞も受けているようで、そこに写真も掲載されている。
      https://awards.acm.org/award-recipients/burrows_9434147
  • 「まだ新しいCライブラリなので粗い部分はあるが、あまりにも急速に良くなっているため、プロダクションで使わないことが職業上の責任放棄のように見え始めた」という文はかなり変だ。Cosmopolitanプロジェクトは高く評価しているが、こうした大げさな優越性の主張は、たいていかなり悪い危険信号だ

    • Justineの主張はおおむね正しいと思う。ただし、大げさで自己顕示的な表現を使うのが彼のスタイル、あるいは性格なのだろう
      一部の人にはきつく見えるかもしれないのも理解できる。以前にもllamacppでそういう形の騒動が起きたことがある
    • Justineはかなり優秀で創造的な人物に見えるが、プロダクションで「新しく」「粗い部分がある」libcを使いたくはない
      プロダクションで最優先されるのは「ものすごい速さで良くなっていること」ではなく、安定性、予測可能性、信頼性だ。もちろん性能も重要だ。より速いコードはインフラを減らし、コストや環境面で良い可能性がある。しかし速さは最後の優先事項だ
    • 一人で長い間コンピュータの前でコーディングしていると、もしかすると社会的接触が不足して、ある程度の傲慢さが伴うように思う。本人やその仕事の重要性を牽制してくれる仕組みがないと、成果が印象的であっても、広く認められている以上に壮大なものに見えてしまうことがある
      例えばAPEは非常に印象的なハックだと感じるが、「今や1つのプラットフォームだけで不安定なのではなく、複数のプラットフォームで同時に不安定になれるということか?」という批判も可能だ
      技術分野に長くいるほど、完全な相互利益は極めてまれで、ほとんどは得るものと失うものが同時にあるトレードオフなのだと気づく
    • 少なくとも私には冗談のように見えた
    • あなたとJustineのユーモアの感覚が違うかもしれない、とは考えてみたのか気になる。これをここに投稿して誰の役に立つと思っているのかも分からない
  • 完全に横道だが、ゲーム開発者としては、すべての開発者ビルドでデバッグ作業をたくさんする遅いミューテックスが好きになった。デバッグ名/IDを持ち、所有者を追跡し、競合に費やした時間をプロファイラに報告し、所有権の変更もプロファイラに報告する、といったものだ
    ゲームは並行性を別の形で構成する傾向があり、ロックを避けるパターンも発展してきた。しかしそうしたパターンは使うのが難しく、プログラマが構造を変える必要がある。ほとんどのコードは「とりあえずここにロックを付けて、マイルストーンを越えよう」から始まる
    高速なロックも予測不能に遅くなることがあり、リアルタイム保証があったならそれを壊してしまう。平均的には速いかもしれないが、テールレイテンシは消えない。「うちのゲームがカクつく」を追跡するために戻ってくる人間にはなりたくないが、たいてい自分がその人間になる
    だから遅いロックを使う方がいい。プロファイラで大きく赤く見えるロックのことだ。問題になっているのが見えたら、リファクタリングして取り除けばいい
    難しい要求だというのは分かっている。AAAプロダクションでプロファイラを使える人は、指で数えられる程度だ。複数のプロダクションを見ても、いつもそうだった
    愚痴で申し訳ないが、高速な並行性プリミティブとアルゴリズムの研究は続いてほしい

    • さらに横道だが、Rustでゲームを開発するのが楽しい理由の1つがこれだ
      ゲームでは、可能ならロック競合は絶対に避けたいし、多くの場合、ロックを取る必要がないことを証明できる。例えば各フレームは段階に分かれており、ある共有リソースへの可変アクセスは特定の段階でだけ必要になる。render()前のupdate()や、アセットのホットリロードのような場合だ
      スコープ付きスレッドとRustの借用規則を使えば、そもそもミューテックスが不要になるように構造化でき、後でコードが変わって必要になった瞬間にコンパイラが厳格にエラーを出してくれると確信できる
      可能なら、プロファイラのスパイクよりもコンパイルエラーを受け取る方が常に良い
    • 完全に同意する。デッドロック検出や内部状態確認のようなデバッグ機能は、簡単に元が取れる。性能に影響するほど頻繁にロックを取得しているなら、設計を見直すべきだ。スレッド間で可変状態を共有するのは避けるべきだ
  • 一方で Cosmo/APE/redbean 系は本当にすごそうに見えるし、関連記事のコメントもおおむね好意的で、概念そのものに反論する内容もあまりありません。ところが別の面では、他の人がこれを使っているという話をほとんど聞きません
    誰もが自分の作業を大きく共有するわけではありませんが、何年も経っているならプロジェクトの振り返り記事をいくつか見かけていてもよさそうです。私が見た Cosmo/APE/redbean への言及は、すべて Justine のサイト由来のものでした
    なので気になります。隠れた落とし穴があるのでしょうか?成果を得るために何か悪いことをしているツールなのでしょうか?コンパイラやランタイムに詳しくないせいで私が理解できない、tom7 風のジョークやトローリングなのでしょうか?それとも本当に、まだ広く普及していない独創的なツール群なのでしょうか?

    • APE はいつ塞がれてもおかしくない巧妙なトリックで動作しており、OpenBSD では実際に塞がれました
      クロスプラットフォームソフトウェアを作る多くの人が欲しいのは、すべてのプラットフォームで動く単一の実行ファイルではなく、サポートする各プラットフォームで正しく動作する単一のコードベースです
      その観点では、Go のように CGO を避ければすべてのターゲットへクロスコンパイルできる言語は快適です。しかし、APE の「3通りに実行可能」という魔法は本当に賢いとはいえ、永遠に動き続けるという信頼感はなく、多くの場合は実質的な利点もあまりありません
      各プラットフォームにはそれぞれのパッケージングや署名の要件があるので、プラットフォーム別のターゲットとして個別にコンパイルするほうがよいです
    • 個人的には、cosmo と ape は非常に賢く見えますが、普通のツールがすでにうまく動いているなら、仕事でこの種の賢さは必要ありません
      たとえば、すでにプロジェクトを別の OS やプラットフォーム向けにクロスコンパイルできている、あるいはそのためのビルドインフラがあるなら、どこでも動く単一バイナリを作る解決策を探す理由はありません
      また APE は複数の OS で実行するために巧妙なハックを使っています。実行ファイル形式が進化して、そのハックがいつか壊れたら?その変更に合わせて APE を直す時間が誰にもなかったら?
      一方で gcc、clang、go、rust のような退屈なツールは、更新され進化し続ける OS 上でも動き続けるでしょう。だから結局、退屈なほうに留まることになります。賢いものを気にしない理由は、退屈なものが私には普通にうまく動くからです
    • Mozilla の llamafile がこれを使っています。モデルの重みと実行ファイルを一つにまとめ、cosmo/ape プラットフォームならどこでも実行できるようにし、対話用の redbean HTTP サーバーも立ち上げてくれます
      統合された重みなしで実行し、ファイルシステムから重みを読み込ませることもできます。ローカル LLM を最も簡単に「入手してすぐ実行」できる方式かもしれません
    • Cosmopolitan は、いつも面白いブログ記事のネタになる技術的な抜け穴のように感じていました。奇抜さと設定へのこだわりだけで、HN のような場所のトップページ入りがほぼ保証される種類のものです
      しかし libc のような基盤技術として使うには、主に面白いおもちゃや小さな個人プロジェクトに役立つものに見えます
      その文脈で glibcmuslmsvcrt のようなものの真面目な代替として提示されると、少し奇妙に感じます。とてもかわいいハックですが、自分が本気で依存しているものの中で見つけたら、かなり戸惑うと思います
    • Mozilla には Cosmopolitan libc ベースの Llamafile プロジェクトがあります: https://github.com/Mozilla-Ocho/llamafile
      Hugging Face にも、その形式で再パッケージした人気モデルを定期的にアップロードしています: https://huggingface.co/models?search=llamafile
      ただし、それが小さなモデルを素早く試すこと以上の実用性を持つかどうかは別問題です
  • それほど良いなら、なぜすべての C ライブラリが同じトリックを採用していないのか気になる
    私の推測では、そのトリックは特定のアーキテクチャ、特定の CPU モデル、特定のワークロードやアクセスパターンでだけ常に速い可能性が高い。サポートするすべてのハードウェアでさまざまなワークロードをきちんとベンチマークすると、同じ利点は出ないかもしれない
    あるいは、Cosmopolitan が実装しようとしている pthread API のセマンティクスが微妙に異なり、この実装が仕様に厳密には準拠していない可能性もある
    複数の libc 作者たちが、OS の基本要素に関する最新研究についていけていないとは想像しにくい

    • そういうプロジェクトには、特定の API 一つ以外にも優先事項が何十もある。個別の API にこだわるのは、限られた時間の使い方として良いやり方ではない。そして反例として、Linux の一般的な libc における malloc と文字列ルーチンを見ればよい
      glibc の malloc はそれなりに使えるが、全体的な速度とスケーラビリティでは、より現代的な代替に簡単に負ける。断片化がひどく、時間とともに悪化し、実ワークロードに大きな影響を与える MALLOC_ARENA_MAX のような調整値も多い。musl malloc は性能面ではあらゆるレベルでひどい。マルチスレッドプログラムで musl のアロケータを使うと性能をひどく台無しにし、ほとんど過失と言ってよいほどだった
      musl には SIMD 最適化された文字列比較ルーチンのようなものもない。非自明なプログラムでこの種の処理にどれほど多くの CPU サイクルが使われているかを知れば驚くだろうし、実際のプロファイルにもはっきり表れ、これを改善するとほぼすべてのプログラムが普遍的に良くなる。glibc の最適化ルーチンは良いが、それでもまだ速くできそうに見える
      こうしたものは「一つのアーキテクチャにだけ特化して一般化できない最適化」ではない。特にこの二つの領域は、ほぼすべてのワークロードで実時間を 2〜5 倍短縮し、長時間のワーキングセット利用率も大きく改善する、よく研究され理解された領域だ。ではなぜ採用されなかったのか。いつものように、他にやることがあったか、musl のように最高性能より単純さを優先する相反する優先事項があったからである可能性が高い
      こうしたプロジェクトを責めているわけではない。誰も「私のプログラムはひどく遅く、何もまともにできないように設計しており、私はそれを誇りに思っている」とは言わない。ただ、そのプロジェクトの作業者たちが完璧なパレート境界だけを選んで設計したという考えはまったく現実的ではなく、多くのプロジェクトが実際に動いている姿を捉えていない
    • 政治、NIH 症候群、古参メンテナのせいかもしれない
      glibc や C++ 側の同等物で何かを変えるには永遠に時間がかかる
      同期プリミティブにはいくつもの種類があるが、pthreads はその一部しかサポートしていない。それに自分を縛ると、たいてい性能を手放す代わりに移植性を得ることになる
    • 「複数の libc 作者たちが、OS の基本要素に関する最新研究についていけていないとは想像しにくい」というのが皮肉なのか気になる
      libc のメンテナについては知らないが、いくつかを保守している立場としては、最新研究を実装しようとは思わない。安定性を保ち、性能が許容範囲かを確認しようとする。研究実装は私の「保守」予算の外にある
    • pthread ミューテックス実装を変えるのに ABI 上の考慮事項があるのか気になる
    • 「それほど良いなら、なぜすべての C ライブラリが同じトリックを採用していないのか?」という問いからは、こんなジョークを思い出す
      ある男と統計学者が道を歩いていて、50ユーロ札を見つける。統計学者は歩き続け、男は立ち止まって「見てください、地面にお金があります」と言う。すると統計学者は「偽物でしょう。本物なら誰かがもう拾っているはずですから」と言って歩き続ける。もう一人の男がそのお金を拾っていく
  • スレッドとミューテックスは、計算機科学で最も複雑さを生む要素だ。新しい実装は、何年も大規模に使われるまでは常に懐疑的に見る
    こうしたスレッディング機構のバグは、最も厳しいレビューすらすり抜けることが多い。90年代半ばに Java が登場したとき、Solaris のあらゆるスレッドやミューテックスのバグが露呈した
    必要なのは最速のミューテックス実装ではなく、信頼できる実装

    • ミューテックスは最も「複雑」なものからはほど遠い。効率的に実装する方法もそれほど多くない。ほとんどの場合、特に読み取りパスでは、避けるのが一番よい
  • このコードはミューテックスロック性能ではなく、ミューテックス競合をベンチマークしている。こういう形でロックを使っているなら、コードを見直すべきだ
    各スレッドは g_chores をインクリメントするたびにミューテックスをロックして解除する。そのため、ミューテックスを頻繁に取得・解放するオーバーヘッドが生じ、スレッドごとに 100,000 回繰り返される
    このオーバーヘッドが、ロック機構間の実際の性能差を覆い隠す。ベンチマークが実作業ではなくロック競合に支配されているからだ。こういうベンチマークは役に立たない

  • Justine とその仕事のファンだが、これはおそらくミューテックスのベンチマークテストケースとしては最も面白くない部類だ。複数のスレッドが同じミューテックスを叩き続ける状況は、そもそも避けるべきだ
    なので、どのミューテックス実装がこのケースを最もうまく処理するかは、あまり面白くないと思う

    • ミューテックスの良いベンチマークテストケースとしては何を考えているのか気になる
    • 私がロックやセマフォを使う大半のケースは、非常に高価なリソースの周辺だ。そのリソースの使用量がロックの性能オーバーヘッドを圧倒する
    • では何を測るべきなのか。競合がない場合は重要で基準線になるが、それ以外ではミューテックスの弱点がまさにこの点にある。競合をうまく処理できないと、ハードウェアが遊んだり、スケジューラの仕事が増えたり、カーネルへの進入が多くなったりする
      重要な点を一つ見落としていたが、競合状況で性能の悪いロックは、メモリネットワークにホットスポットを作るなど、非常に悪いシステム的影響を及ぼし得るし、それもここで現れるはずだ
    • 「複数のスレッドが同じミューテックスを叩き続けるべきではない」という評価には、完全には同意しにくい
      同じミューテックスに複数のスレッドが集中するケースはいくつか思い浮かぶ。簡単な例として、リストや辞書のようなデータ構造を同時に埋める作業がある
      メッセージパッシングでもできるが、メモリをより多く使い、共有位置に書き込むために待つより遅くなることもある
  • 本番環境は、速度、効率、あるいは明らかに「賢いハック」に関するものではない
    日曜の午前3時に壊れたシステムを直すために呼び出されない保証のために効率の 50% を犠牲にする必要があるなら、毎回その選択をする
    本番環境は信頼性に関するものであり、信頼できるコードを書くことは「速い」コードを書くことより 10 倍難しい