4月版 Linus(と筆者)を嘆かせたanon_vma騒ぎ
小崎資広
2010/5/18
rmapスケーラビリティパッチとその混乱
LinuxにおけるVMの役割の1つに、仮想アドレスと物理アドレスの変換があります。仮想→物理変換は主にページフォルト時の処理のために必要であり、物理→仮想は主にページ回収処理(キャッシュ破棄やスワップアウト)で使われます(ページをfreeにする前に参照しているプロセスのページテーブルエントリを削除しておかないと、カーネルがクラッシュしてしまいます)。
Larry Woodmanはanonymous memory(注1)用の物理→仮想変換処理がAIM7ベンチマークに大幅な性能劣化を与えていることを報告しました。
anonymous memoryの物理→仮想変換処理(注2)は、図1のような構造になっています。vm_area_struct、略してVMAが、プロセスの仮想アドレス空間のあるリージョン(オフセットと長さのペア、例えば番地0x10000から1MB)とその属性(アクセス権やさまざまなmmapで与えられたフラグ、mbindで設定されたNUMAバインディングなど)を表しており、その逆マッピングのVMAのリストを保持する管理用構造体がanon_vmaです。
図1 anonymous memoryの物理→仮想変換処理 |
一見きれいな構造をしているように見えますが、この構造はfork時にちょっと奇妙な動作をします。図2、図3のように、VMAはコピーするがanon_vmaはコピーせず、anon_vmaの持つVMAリストに親子両方のVMAをつなげるのです。
図2 通常時の挙動 |
図3 fork時のanon_vmaの挙動 |
これはCopy-On-Write(以下COW)の仕様が原因です。Linuxはfork時は実際のデータはコピーせず、fork後に最初にメモリにアクセスした時点でデータコピーを行います。これにより、fork後すぐにexecするようなケースを高速化しているのです。
COWによりコピーされたデータが親子どちらに割り当てられるかは、どちらのプロセスが先にメモリにアクセスするかに依存します。よってfork時には何も決められないので、仕方なく両方をリストにつないでおくのです。
この方式の欠点は、COWが終わった後明らかになります(図4)。親と子はもはや何もデータを共有していないにもかかわらず同じanon_vmaを共有してしまっているため、ページ回収時のVMAチェックが2倍に増えてしまうのです。そして前述のAIM7は、Larryのconfigでは1万プロセスほどforkするので、メモリ回収時のVMAチェックのコストが普通のシステムの約1万倍になっていたというわけです。
図4 COW終了後の問題点 |
そのためRik van Rielによりanon_vma_chainという補助構造体を導入し、図5のようにCOW時に新しいanon_vmaを生成し、もともとのページ群は親子両方のVMAがリンクされている構造を踏襲しつつ、新しいページは必要なVMAだけを参照するよう改良が行われました。
図5 anon_vma_chainによる改良 |
この変更は導入当初から、「AIM7は現実のワークロードを全然反映していないから測定方法が不適切ではないか」と指摘され続けていました。さらにマージ後、大量のバグが残っていることが明らかになり、Linus自ら陣頭指揮を執って解決に乗り出すほどの大騒ぎとなりました。
Linusは当初「このエリアの最近の変更は追えていなかったんだよね、Andrew Mortonに任せっ切りで。ちょうどいい機会だよ」なんて余裕なことをいっていたのですが、VM開発者が現在の動きをいろいろと説明していくにつれ、どんどん楽天的なセリフは減っていきました。
「は? write lockが取れないからread lock+pte lockで代用してる……だと」
「は? kfree後のメモリにアクセスする可能性があるけど意図的……だと」
「は? rmap dereferenceはraceにより全然違うanon_vmaをlookupするかもしれないが仕様……だと」等々……。
Linusは「このコードは本当に僕を混乱させているよ。ただの人間(mere mortals)にも分かるようにドキュメント化してくれよ」と嘆きました。
注1:プロセスのメモリのうち、ファイルと関連付けられていないメモリ。malloc()で確保したメモリやスタックなど。 注2:仮想→物理の方がよく使われるし素直な変換なので、物理→仮想の変換をreverse mapping(rmap)、つまり逆マッピングということもあります。 |
2/2 |
|
|
||||
|
連載 Linux Kernel Watch |
Linux Squareフォーラム Linuxカーネル関連記事 |
連載:Linux Kernel Watch(連載中) Linuxカーネル開発の現場ではさまざまな提案や議論が交わされています。その中からいくつかのトピックをピックアップしてお伝えします |
|
連載:Linuxファイルシステム技術解説 ファイルシステムにはそれぞれ特性がある。本連載では、基礎技術から各ファイルシステムの特徴、パフォーマンスを検証する |
|
特集:全貌を現したLinuxカーネル2.6[第1章] エンタープライズ向けに刷新されたカーネル・コア ついに全貌が明らかになったカーネル2.6。6月に正式リリースされる予定の次期安定版カーネルの改良点や新機能を詳しく解説する |
|
特集:/procによるLinuxチューニング[前編] /procで理解するOSの状態 Linuxの状態確認や挙動の変更で重要なのが/procファイルシステムである。/procの概念や/procを利用したOSの状態確認方法を解説する |
|
特集:仮想OS「User
Mode Linux」活用法 Linux上で仮想的なLinuxを動かすUMLの仕組みからインストール/管理方法やIPv6などに対応させるカーネル構築までを徹底解説 |
|
Linuxのカーネルメンテナは柔軟なシステム カーネルメンテナが語るコミュニティとIA-64 Linux IA-64 LinuxのカーネルメンテナであるBjorn Helgaas氏。同氏にLinuxカーネルの開発体制などについて伺った |
|
|
- 【 pidof 】コマンド――コマンド名からプロセスIDを探す (2017/7/27)
本連載は、Linuxのコマンドについて、基本書式からオプション、具体的な実行例までを紹介していきます。今回は、コマンド名からプロセスIDを探す「pidof」コマンドです。 - Linuxの「ジョブコントロール」をマスターしよう (2017/7/21)
今回は、コマンドライン環境でのジョブコントロールを試してみましょう。X環境を持たないサーバ管理やリモート接続時に役立つ操作です - 【 pidstat 】コマンド――プロセスのリソース使用量を表示する (2017/7/21)
本連載は、Linuxのコマンドについて、基本書式からオプション、具体的な実行例までを紹介していきます。今回は、プロセスごとのCPUの使用率やI/Oデバイスの使用状況を表示する「pidstat」コマンドです。 - 【 iostat 】コマンド――I/Oデバイスの使用状況を表示する (2017/7/20)
本連載は、Linuxのコマンドについて、基本書式からオプション、具体的な実行例までを紹介していきます。今回は、I/Oデバイスの使用状況を表示する「iostat」コマンドです。
|
|