64GB超RAMサポート

Linuxカーネルのバージョン2.6では、大容量RAMサポート強化が一つの目標とされています。バージョン2.4においても、理論的には64GBまでのRAMがサポートされていましたが、現実的には16-32GB程度が限界でした。先日、Ingo Molnar氏から64GB超のRAMサポートの公開リリースがLinux Kernel MLにアナウンスされました。

Linuxカーネルバージョン2.4のRAMサポート

Linuxカーネルバージョン2.4では、カーネルコンパイル時のオプションとして、 RAM容量を選べ、1GB未満、1GB以上4GB未満、4GB以上64GB未満を選べます。 しかし、実際には16-32GB程度が限界でした。なぜそうだったのか、今後どうなるのか、Ingo Molnarは明らかにしています。

Linux 2.6での大容量RAMサポート

Linuxカーネルバージョン2.6では、64GB以上のRAMをサポートできる VMモードを選択できるようになります。これは、4G/4G split modeと よばれることになるでしょう。

以下は、Ingo Molnar氏によるLinux Kernel MLへのアナウンスの翻訳です。

メール本文

Subject: [announce, patch] 4G/4G split on x86, 64 GB RAM (and more) support
From: Ingo Molnar <mingo@elte.hu>
Date: Wed, 9 Jul 2003 00:45:52 +0200 (CEST)

Linux カーネル 2.5.74 向けの “4GB/4GB VM分割”パッチの最初の公開リリースを アナウンスします。パッチは、 http://redhat.com/~mingo/4g-patches/4g-2.5.74-F8 になります。

4G/4G分割機能とは、主として、システムコールごとのTLBフラッシュオーバーヘッドの 費用を払っても、よりカーネルユーザVMを欲しい(または必要とする)ような、 より多くのRAMを搭載したx86システムを対象としています。

x86 では、仮想メモリの総量は、公知のとおり、4GBに制限されています。 この全4GBのVMにおいて、ユーザ空間は3GB(0x00000000-0xbfffffff)使っており、 カーネルは1GB(0xc0000000-0xffffffff)使っています。このVMの仕組みは、 3/1分割と呼ばれています。この分割方法は、RAMが1GB以下の領域では完璧に うまく稼動します。そして、’highmem’ 機能によって、たくさんの大きなキャッシュ (とオブジェクト)を上位メモリエリアへ移動するものの、まあまあ 十分にうまく稼動します。

しかし搭載RAMの総量が増加してくると、3/1分割は、実際のところボトルネックに なってきます。highmemを、かなりの数の大きなサイズのキャッシュで使っているにも かかわらず、最も重要なデータ構造体の一つである mem_map[] は、カーネルVMの1GBの中から 割り当てられます。32GBのRAMを使っている場合、残る0.5GBの低位メモリ領域と いうのは大変な制限で、全てのRAMの1.5%しか表せないことになります。 様々な共通の負担が低位メモリ領域を使いはたし、人為的なボトルネックをつくり出す ことになります。64GBのRAMを使っている場合、mem_map[]だけでほとんど1GB近く使ってしまい カーネルがブートできなくなります。mem_map[]を高位メモリへ再割り当てすることは、 VM、低レベル機種依存コード、ドライバ、ファイルシステムなどの全カーネルと、 この中心的データ構造体との緊密な結合から考えて、まったくもって非現実的です。

4G/4Gパッチによって、カーネルは4G/4Gモードでコンパイルできるようになります。 このモードは、分離された全て4GBのVMをカーネルへ割り当て、それとは別の全(しかも プロセスごとに)4GBのVMをユーザ空間へ割り当てます。

4G/4Gカーネルで動作している典型的なプロセスの /proc/PID/maps ファイルは、 以下のように全4GB分のアドレス空間で動いているのが見て取れます。

 00e80000-00faf000 r-xp 00000000 03:01 175909     /lib/tls/libc-2.3.2.so
 00faf000-00fb2000 rw-p 0012f000 03:01 175909     /lib/tls/libc-2.3.2.so
 [...]
 feffe000-ff000000 rwxp fffff000 00:00 0

スタックは 0xff000000 (4GB引く16MB) までに配置されます。カーネルは4GBの低位メモリ 領域を持つため、64GBのRAMを搭載したとしても、3.1GBがまだ利用可能になっています。

 MemTotal:     66052020 kB
 MemFree:      65958260 kB
 HighTotal:    62914556 kB
 HighFree:     62853140 kB
 LowTotal:      3137464 kB
 LowFree:       3105120 kB
低位メモリ(lowmem)の総量は、それでも4GBメモリ搭載システムの3倍以上あり、 32GBのシステムでも3/1分割の場合の6倍以上あります。

4G/4G機能の性能への影響:

4G/4Gパッチを適用したときの動作時のコスト:カーネルとユーザ空間VMで 分離したアドレス空間を実装するため、entry/exit コードはカーネルページテーブルと ユーザページテーブルを切替える必要があります。これは、TLBミスでいうところの 非常にコストのかかる操作であるTLBフラッシュ(これは、キャッシュからとってこれるならば インテルCPUでは非常に高速です)ではなく、直接的なTLBフラッシュコスト(%cr3操作)が システムエントリー時に発生します。

RAMの制限:

理論的には4G/4Gパッチは、1GBの低位メモリを残しながら、x86で200GB(!)の 物理RAM分のmem_map[]を提供できます。つまり座席には足を伸ばせるだけの広さが 十分あると言うわけです。大量のRAMを搭載する正しいソリューションというのは、 正式な64-bitシステムを使うことだけれど、現状でも多くのx86ハードがあり、 今後数年に渡ってx86売られ続けるだろうことから、我々は最大限のサポートを 行うべきでしょう。

パッチは、wliのpgclパッチ(訳注:mem_map[]用の空間をNUMA-Q MPのノード0以外はbootmemから掃きだして64GB RAMをサポートする)と直交しています。両パッチは、同じことを違った 方法でやろうとしています。私は、いずれ二つのパッチを結合したいと思っており、作業量の見積もりもできています。

実装の詳細:

パッチは、たくさんの低レベル x86 コードインフラを実装/変更します。

  • GDT, IDT, TSS, LDT, vsyscallページとカーネルスタックを高位仮想メモリウインドウ 4GBアドレス空間のトップ16MBの(トランポリン)へ移動します。
  • atomic kmaps の高位メモリ依存性を解除します。
  • LDTを atomic kmap化します。
  • (そして、初期マップサイズの増加やカーネルVMの全4GBをマップするPAEコードの修正 など、その他のより小さな細かい部分がたくさん)

我々が、ユーザモードからsyscall(や他の全てのトラップ)を行うときは必ず、 高位アドレス esp0 における、高位アドレスのトランポリンコードが動作を開始 します。このコードはカーネルページテーブルへと切替えて、その後「仮想カーネル スタック」から、通常の(本当の)カーネルスタックへと切替えます。システム コールexit時は、逆方向のことを行います。

いくつか一般的なカーネルの変更を同様に行います:

  • ‘indirect uaccess’ プリミティブを実装し、全ての get_user/put_user/copy_to_user/… などの関数が、直接のユーザ空間へのアクセスを避けて実装されます。
  • PAGE_OFFSET が PAGE_OFFSET_USER と PAGE_OFFSET (kernel)へと分割されます。
  • PAGE_OFFSET が PMD_SIZE へアライメントされると言う前提を数個修正します。
しかしパッチがカーネル全般へ及ぼす影響は極めて小さい物です。

パッチは、kernel <-> kernel コンテキストスイッチを最適化し、IRQエントリー 同様、TLBをフラッシュさせません。唯一の例外は、ユーザ空間のページテーブルを ロードした時に限られます。

よくあるx86 サーバにおける4G/4Gの典型的なコストは、システムコールの遅延で 3 マイクロ秒増える程度です(これには1マイクロ秒以下のnullシステムコールの 遅延が加算されます)。典型的なアプリケーションの負荷(DBの負荷やネット ワーキングなど)では、負荷によっては、無視できない程度の0%から30%の オーバーヘッドとなって表われます。マイクロベンチマークとは別に、同様に システムコールの遅延が増えることで、大きな速度低下が見られることがあります。

私は、4G/4G パッチは16GBのRAM容量以下では、システムのオーバーヘッドに見合うだけの 利点は無いと思います。(しかし例外はあって、特にlowmemに強烈に負荷が反応 する場合です)。32GBのRAM容量では、lowmemの制限に引っかかるため、4G/4Gパッチが とても推奨されます。そして、64GBやそれ以上のシステムでは、必須だと思います。

現状と将来計画:

パッチは作業中のスナップショットです。まだ、いくつかTODO(作業予定)とFIXME(修正項目)がありますが、 コンパイルも動作も私のところではうまくいっています。でも、 注意深く取り扱ってください。これは、かなり濃い変更が低レベルのx86コードに 加わるような、実験的なパッチです。

数個の性能向上がこのパッチの開発先端に含まれており、数日中にはこのパッチへ 統合するつもりです。しかしまずベースパッチをリリースしたいと考えました。

とにかくまあ、このパッチを試してみて。いつものように、コメントや提案は歓迎です。

	Ingo