x86‑TSO の ARM 上でのエミュレーションがパフォーマンスボトルネックとなる理由とベンダーの対応策
TL;DR
ARM の弱いメモリモデル上で x86‑TSO をエミュレートすることは高コストであり、すべてのロード/ストアが acquire/release 指令に変換され、アラインメントの不一致アクセスは高コストなアラインメントフォールト処理を引き起こし、スプリットロックの原子的操作には重いカーネル介在が必要となる。最近の ARM 拡張(LRCPC、FEAT_LSE2)および Apple のハードウェア TSO モードにより、これらのペナルティの大部分が軽減され、現代の ARM CPU ではネイティブに近いパフォーマンスが実現可能となった。
x86‑TSO とは何か? なぜ重要なのか?
- x86‑TSO(Total Store Ordering) は、ストアがすべてのコアに可視になる前に、その後のロードがその値を観測できないことを保証する。これによりプログラマにはシンプルで直感的なモデルが提供される:書き込みは即座に一貫性を持つ。
- ARM の弱い(緩い)モデル では、ストアがプライベートキャッシュラインに留まり、明示的な acquire/release 指令が使われない限り、ロードは古くなったデータを見ることになる。
- x86 エミュレータ(例:FEX)が ARM 上で実行される場合、すべての x86 ロードを ARM の load‑acquire、すべての x86 ストアを ARM の store‑release に変換する必要がある。これは TSO の整合性を保つためである。
- この変換は ARM のネイティブモデルよりもはるかに制限的であり、実行時のパフォーマンスを支配する要因となることがある。
acquire/release モデルのベースラインパフォーマンス
- FEX の初期実装では、ARMv8.0‑a の acquire/load および release/store を すべてのメモリ操作 に使用していた。
- マイクロベンチマークでは、ほとんどの CPU で 2〜5倍の遅延 が発生した。acquire/release 指令は自由に再順序化できず、パフォーマンスのホットパスとなるからである。
- AmpereOne サーバー CPU では最も深刻な遅延が発生:release‑store ユニットが特に弱く、acquire‑load の大量発生がパイプラインを制限する。
- 高性能モバイルコア(Cortex‑X4、X925)も、アラインメントの不一致アクセスで約 50 % の損失を被る。アラインメントフォールト発生時に必要な追加の DMB(データメモリバリア)が原因である。
アラインメントの不一致アクセスとスプリットロック
ARM 上のアラインメントフォールト
- ARMv8.0 では 自然アラインメント(アドレス ≡ サイズ)が必須。これを違反すると アラインメントフォールト が発生し、通常はクラッシュする。
- FEX は各ロード/ストアの前に パッチポイント(NOP)を挿入する。フォールトが発生すると、この命令を DMB でラップされた通常のロード/ストアに置き換え、実行を再開する。
- このフォールバックは動作するが、すべてのアラインメント不一致アクセスに対してカーネルからユーザー空間へのラウンドトリップが発生し、高コストである。
x86 上のスプリットロック
- x86 では スプリットロック 操作が許可されている:キャッシュライン境界をまたぐ原子的読み書き。これらは原子的かつ一貫性を持ち、決して破損しない。
- ARM の原子命令は自然アラインメントアクセスに対してのみ シングルコピー原子的 である。FEAT_LSE2 拡張により 16 バイト単位まで緩和されるが、64 バイトのキャッシュライン境界をまたぐ場合に失敗する。
- その結果、FEX は 2 回の 64 ビット compare‑exchange(CAS)操作とカーネル介在のフォールトハンドラを用いてスプリットロックをエミュレートする必要がある。これにより 1 回あたり数百ナノ秒 のオーバーヘッドが発生し、ネイティブ x86(約 1.4 ns)よりもはるかに遅くなる。
効果的なアーキテクチャ拡張
LRCPC(Release Consistency processor‑consistent) – ARMv8.3+
- x86‑TSO の要件に一致するメモリモデルを実装する LRCPC‑load および LRCPC‑store 指令を導入。
- ベンチマークでは、LRCPC‑load がすべてのテスト CPU(AmpereOne、Cortex‑X4/X925、Oryon‑3、Apple M1)で ベースラインロードパフォーマンス を達成した。
- FEX は FEAT_LRCPC 機能を検出すると、acquire‑load から LRCPC‑load に切り替えることで、アラインメントされたアクセスに対する高コストな DMB パスを排除する。
FEAT_LSE2(Large System Extensions 2)
- acquire/LRCPC/Release 指令および read‑modify‑write 原子操作のアラインメント要件を 16 バイト単位の範囲内 の任意のアドレスまで緩和。
- x86 エミュレーションでは わずかな利点 しかもたらさない。なぜなら、ほとんどの x86 コードは 64 バイトのキャッシュライン全体をまたぐアクセスを行うため(真のスプリットロック)である。
Apple のハードウェア TSO モード
- Apple Silicon は スレッド単位の TSO トグル(FEAT_TSO)を実装。有効化すると、通常の ARM ロード/ストアが x86‑TSO と同様に振る舞う。
- M1 では、LRCPC‑load は単なる通常のロードのエイリアスであるため、アラインメントされたアクセスも不整合されたアクセスも 5 % 未満のオーバーヘッド で済む。
- デメリットは、ネイティブ ARM コードで約 24 %(ストア)の遅延が発生するが、FEX のネイティブ ARM 実行比率が極めて小さいため、影響は無視できる。
ベンダー別パフォーマンススナップショット
| CPU | アラインメントされたロード (GB/s) | アラインメントされていないロードのペナルティ | アラインメントされたストア (GB/s) | アラインメントされていないストアのペナルティ |
|---|---|---|---|---|
| AmpereOne | ~28 (ベースライン) | ≈0 % (アラインメント処理済み) | ~28 | ~8.5 % の低下 |
| Cortex‑X4 | 11.5 | ~50 % の低下 (DMB) | 6.7 | ~50 % の低下 |
| Cortex‑X925 | 14.2 | ~50 % の低下 | 9.1 | ~50 % の低下 |
| Oryon‑3 | 18.0 (LRCPC‑load ≈ ベースライン) | ~30 % の低下 | 12.2 (ベースラインの約68 %) | ~57 % の低下 |
| Apple M1 (TSO) | ≈ベースライン | ≤5 % | ベースラインの約76 %(依然として高速) | 顕著でない |
- 数値は記事のマイクロベンチマークグラフから導出。正確な値は簡潔さのため省略。
キャッシュなし(write‑combine)メモリの課題
- ゲームはしばしば VK_MEMORY_HOST_CACHED_BIT = 0(キャッシュなし、write‑combine)メモリを介して GPU バッファに直接書き込む。
- ARM 上では、キャッシュなしのストアも still store‑release を使用するが、write‑combine バッファの恩恵を受けず、キャッシュありストアと比べて最大 816 倍の帯域幅低下 が発生する。
- ロード帯域幅はさらに悪化する。すべてのロードがキャッシュをバイパスし、システムメモリにアクセスしなければならないためである。
- 結果として、PCIe‑GPU システムではエミュレートされた x86 ゲームが 1 FPS 未満 にまで落ち込む(例:Hollow Knight: Silksong, Subnautica 2)。
- 対策:
- UMA システム(統合 GPU)では、ドライバにキャッシュバッファを使用させるように強制。NVIDIA Tegra、Snapdragon Adreno、多くの Mali GPU はすでにこれを行っている。
- Apple の TSO モードは自動的にこの問題を回避する。ハードウェアがキャッシュなしストアを一貫性のあるものとして扱うためである。
- 現在の ARM 拡張では write‑combine ストアの問題を解決できない。将来の FEAT_LRCPC4 が必要となるだろう。
スプリットロックエミュレーションの正しさ
- FEX の現在のスプリットロックエミュレーションは ベストエフォート:非スプリットロック原子操作が 128 ビット領域の片方だけを変更した場合、データが破損する可能性がある。
- 単純なグローバルミューテックスの解決策は、すべてのスプリットロックをシリアライズするが、同時にアラインメントされた原子操作による破損は許容する。
- カーネル全体の「世界停止」アプローチは、ゲームでのスプリットロックの頻度が高いため、実現不可能である。
- 著者らは、キャッシュライン境界をまたぐがアラインメントフォールトを発生させない 128 ビット CASP を提案。この操作は失敗する可能性があり、再試行可能であり、原子性を保つ。
- ARM のトランザクショナルメモリ拡張(TME)は理論的には役立つが、廃止され、実際には出荷されていない。
コミュニティの洞察
"Apple は 6 年前から、x86 エミュレーションが重要になった時点で、チップに x86 互換のメモリ順序モードを単純に追加することでこの問題を解決していた。Apple のチップが業界をリードする別の方法だ。" – modeless
"FEX は Apple の Rosetta2 や Microsoft の Prism と同様に、x86 から ARM への翻訳フレームワークである。Valve が開発をスポンサーしている。なぜなら、新しい Steam Frame も x86 ゲームをサポートする方法だからだ。" – dagmx
"この記事は、ARM が最も緩く、x86 が最も厳格であるという一般的な主張を繰り返しているが、緩いモデルが必ずしも大きな利点を持つわけではない。" – pdw
これらのコメントは、記事の核心的な主張を裏付けている:ハードウェアレベルのサポート(Apple の TSO、ARM の LRCPC)が、ARM 上での高パフォーマンス x86 エミュレーションの唯一の実用的な道筋である。
今後の展望
- ARM ベンダーは LRCPC および LSE2 拡張を段階的に追加しており、x86‑TSO とのギャップを縮めている。
- Apple のハードウェア TSO モードは、専用の TSO トグルが最も洗練された解決策であることを示している。
- 将来の提案として、スプリットロックに対応した 128 ビット CASP や、再び復活したトランザクショナルメモリ拡張が、残りの正しさとパフォーマンスのギャップを完全に解消する可能性がある。
- こうした拡張が主流になるまでは、ARM 上の x86 エミュレータは UMA プラットフォームを優先し、ドライバパッチ(例:Valve の Steam Frame カーネルパッチ)に頼ってキャッシュなしメモリのペナルティを軽減し続けるだろう。
結論:ARM 上で x86‑TSO をエミュレートすることは、両者のメモリモデルが一貫性のスケールの反対側にあるため、根本的に高コストである。しかし、最近の ARM ISA 拡張および Apple のハードウェア TSO モードにより、オーバーヘッドは劇的に削減され、ARM 上での高パフォーマンス x86 ゲーミングがますます現実味を帯びつつある。
Sources
関連
- Dispatch
- Dispatch
- Dispatch
- Dispatch
- Dispatch