Linux 7.3、メモリ管理に2つの高速化。ロック保持500ms超が2ms未満に
Linux 7.3のマージウィンドウで、メモリ管理サブシステムに2つのパフォーマンス改善が入った。圧縮メモリの解放処理で最大1.83倍、KSMの逆引きマップ走査でロック保持時間を100〜500分の1に短縮する。
Linux 7.3のマージウィンドウで、メモリ管理サブシステムに2つのパフォーマンス改善が入った。圧縮メモリの解放処理で最大1.83倍、KSMの逆引きマップ走査でロック保持時間を100〜500分の1に短縮する。
501本のパッチ、概要の下書きにGemini
Linux 7.2が現地時間8月17日にリリースされ、7.3のマージウィンドウが開いた。翌18日、メモリ管理(MM)サブシステムのメンテナであるアンドリュー・モートン(Andrew Morton)氏がリーナス・トーバルズ(Linus Torvalds)氏に向けて、最初のプルリクエストを送った。
今サイクルは活発だった。モートン氏がパッチ採用時に発行する"added-to-MM"(MM追加通知)メールは1,250通。前サイクルの920通から35%増えた。今回の第1弾だけで501本のパッチが含まれ、さらに約200本が翌週に控える。
モートン氏はプルリクエストの中で、パッチシリーズの概要文をGoogleのGeminiに下書きさせ、自分でレビュー・編集したと明かしている。カーネル開発にAIが浸透し始めているが、メジャーサブシステムのメンテナが「AIに書かせた」と公の場で書くのは、まだ珍しい光景だ。
レビュー状況も数字で示されている。501パッチ全体のレビュー率は70%、1パッチあたり平均1.66件。ただしDAMON(Data Access MONitor)関連のパッチを除くとレビュー率は90%に上がり、さらにセルフテストも除けば92%に達する。DAMONだけで145本ものパッチが入っており、レビューの手が追いついていない。
zsmalloc:圧縮メモリの解放が最大1.83倍に
501本の中で特に注目すべき改善が2つある。
1つ目はzsmalloc(圧縮RAMページ用のメモリアロケータ)におけるzs_free()のロック競合の削減だ。zsmallocはZswapやzRAMが圧縮したRAMページを格納するために使う。メモリが逼迫した状況でページを解放する際、zs_free()の内部でロックの競合が発生し、特にAndroid端末のLMK(Low Memory Killer)発動時や、サーバーでZswapを多用するワークロードで顕著だった。
Xiaomiのウェンチャオ・ハオ(Wenchao Hao)氏によるパッチシリーズは、64ビット環境においてzs_free()がプールレベルのロック(pool->lock)を取得せずにクラスインデックスを引けるよう設計を変更した。
ベンチマークでは、各プロセスが256MBのメモリ領域を個別にマッピング→書き込み→zRAMへのスワップアウト→並行アンマップ、という手順で測定されている。Raspberry Pi 4B(4コアARM Cortex-A72)では最大1.83倍、20コアIntel i7-12700(16並行プロセス)では最大1.4倍の高速化が確認された。
メモリ価格の高騰でサーバーのZswap/zRAM利用が広がっている現状を考えると、このロック競合の解消は地味ながら実利が大きい。
KSM:ロック保持705msが1.67msに
2つ目はKSM(Kernel Samepage Merging、同一内容のメモリページを統合して物理メモリを節約する仕組み)の逆引きマップ走査、rmap_walk_ksm()の最適化だ。
ZTEのシュ・シン(Xu Xin)氏とワン・ヤーシン(Wang Yaxin)氏が発見し、修正した。
KSMが管理するページの逆引きマップを走査する際、従来の実装はそのページに紐づくanon_vma(匿名メモリ領域を管理する構造体)配下のVMA(Virtual Memory Area、仮想メモリ領域)を全件走査していた。VMAの数が少なければ問題にならないが、数千〜数万のVMAが1つのanon_vmaにぶら下がると、走査はO(N)の計算量になる。
この走査中に取得されるanon_vmaのロックは、ページフォールト、メモリ回収、ページマイグレーション、コンパクション、mlock、exit_mmap、cgroupの会計処理など、メモリ管理の広範な操作で共有されている。rmap_walk_ksm()がロックを数百ミリ秒保持すると、これらすべての操作がブロックされる。
シュ・シン氏はパッチシリーズの中で、ZTEのベンチマーク結果をこう報告している。
ロック保持時間が500ms超から2ms未満に短縮された。最悪ケースでは705msから1.67ms(最大)/1.44ms(平均)になった
修正内容は、anon_vma_interval_tree_foreachの走査にページオフセット範囲のフィルタリングを追加し、対象ページと無関係なVMAをスキップするというものだった。
誰が困っていたのか
この問題はVMAが大量に分割される環境で発生する。VMAの分割はfork()がなくても起きる。mprotectやmadviseを繰り返し呼ぶだけで、1つのVMAが数千〜数万に分裂し、すべてが元のanon_vmaに紐づいたまま残る。
シュ・シン氏はパッチシリーズの中で具体例を挙げている。JVMやGoランタイムはヒープ領域にmmapを使い、後からガベージコレクションのバリアやガードページのためにmprotect(PROT_NONE)を呼ぶ。MySQLやPostgreSQLも、共有メモリバッファや匿名マッピングに対してmadvise(MADV_DONTNEED)で特定ページを解放する。いずれの操作もVMAを細かく分割する。
ZTEの本番環境では、KSMを有効にしたJavaアプリケーションで約20,000のVMAが1つのanon_vmaを共有していた。パッチ適用前のロック保持時間は、メモリコンパクションとページマイグレーション中のrmap walkで最大228msだった。
パッチの影響を受けないワークロード(VMAが大量分割されていない環境)では、追加されるのはページオフセットの比較1回分で、オーバーヘッドは無視できる。影響を受けるワークロードでは100〜500倍のロック保持時間の短縮になり、テールレイテンシの改善、メモリ圧迫時のスループット向上、コンテナのタイムアウト解消につながるとシュ・シン氏は述べている。
| zsmalloc | KSM | |
|---|---|---|
| 対象 | 圧縮RAM解放 | 逆引きマップ走査 |
| 問題 | ロック競合 | ロック長期保持 |
| 改善幅 | 最大1.83倍 | 705→1.67ms |
| 仕組み | クラス検索を ロック外に移動 | VMAフィルタリング を追加 |
| 影響先 | Android/サーバー | JVM・MySQL等 |
| 貢献 | Xiaomi | ZTE |
501本の中の2本
今回のMMプルリクエストには、このほかにもdefrag_modeでのリクレイムストーム修正(Meta本番環境で発生した深刻なパフォーマンス退行への対処)、userfaultfdによるVMゲストメモリのワーキングセット追跡、HugeTLB割り当ての汎用化、VMAページオフセット処理の大規模リファクタリングなど、カーネルのメモリ管理を支える改善が並ぶ。
zsmallocのロック競合削減とKSMの逆引きマップ最適化は、どちらもカーネル内部の、ほとんどのユーザーが意識しない層の改善だ。だが、Androidのアプリ切り替え速度や、KSMを使う仮想化ホストのレイテンシ、zRAMを頼るサーバーのスワップ性能に直接影響する。
見えない層が少しずつ速くなり、その結果がユーザーのもとに届く。
501本のパッチはその一断面にすぎない。
関連記事
- Btrfsがhuge folios対応、Linux 7.2で投入へ
- io_uringがコアあたり60%高速化、PoC公開
- Linux 7.0でPostgreSQL性能半減、修正困難か
- Linux 7.3、cgroupスケジューリングを根本から作り替え。ゲームもサーバーも恩恵
- Linux 7.3、VRAM管理パッチがカーネル本流入り。次はオーバーコミット改善
- 古参Slackware系ディストロ、CPUスケジューラを換えて復活
- Linux 7.2、GPUスケジューラの新方式をリリース直前に撤回
- Linux 7.3、M3 Pro/Max/Ultraのデバイスツリーを初めてマージへ
- KVMエスケープ脆弱性「Zapscape」公開 6年前から存在した問題を解説
- Intel Starfire、Linux 7.3で最初のパッチが着地