LinuxCon Japan 2012を3倍楽しむための基礎知識

第5回Linux Kernelメモリ管理最新動向その1]

2012年6月6日~8日にLinuxCon Japan 2012が開催されます。ここではLinux Kernelの最新技術の発表や議論がいろいろ行われるのですが、カンファレンスを楽しむ手助けとなる記事を…ということで、最近のLinux Kernelのメモリ管理の以下のトピックについて、2回に分けて紹介したいと思います。

今回は、

  • NUMA対応
  • 組込みシステム向けの新機能

次回は

  • ファイルシステム、デバイスと連携したエンハンス
  • メモリ資源管理機能(cgroup)
  • CleanCache

を取り上げます。

それぞれ、LKMLでどのような提案があって、提案の理由は何か? 現在はどうなっているのか? ということを簡単に紹介したいと思います。

NUMA対応

性能エンハンス機能として現在議論されているのが、NUMAマシン上のアプリケーションのチューニング機能です。現在、全く別の方式が有名ハッカー2人から提案されていることもあり、この議論は注目されています。

まず、NUMA(Non Uniformed Memory Architecture)とは何かをおさらいします。

NUMAとは、CPUがメモリアクセスをする際に、アクセス対象メモリの物理的な位置に依存してアクセスコストが変わるアーキテクチャです。たとえば、最近のx86 系CPUではCPU内にMMU(Memory Management Unit)が内蔵されており、CPUから直接DIMMに接続する形になっています。複数CPUがある場合、あるCPUに繋がったDIMMに別のCPUからもアクセスはできますが、この場合は自分に直接繋がっているDIMMへのアクセスよりもアクセスのコストが高くなります。つまり、CPUとDIMMの距離でアクセスコストが変わることになります。図1にその概要を示します。

図1 NUMAにおける Threadの動作するCPUとメモリの距離の違いによる性能差
図1 NUMAにおける Threadの動作するCPUとメモリの距離の違いによる性能差

NUMAの場合、ファームウェアからカーネルに、CPUとメモリの距離を教えてくれる仕組みがありますので、それを参照しつつ、カーネルは 近い距離にあるCPUとメモリをまとめ、Nodeと呼ばれるCPUとメモリの組を作ります。threadが走行しているCPUと同じNodeのメモリを使っている場合、メモリアクセスコストが抑えられ、効率の良い動作になります。

【備考】
NIC等のデバイスとCPU、メモリの間にも距離の概念はあって、同じようなことが言えます。

現在の実装

現在のLinuxの実装では、threadがメモリを要求した際は、現在threadが走行中のCPUが所属するNodeからメモリ獲得を行うようになっています。このため、短時間で実行が終了するアプリケーションは大体最適なメモリ配置で動作します。ところが長時間動作するアプリケーションの場合、スケジューラの都合でthreadの走行するCPUを別のNodeに移動されてしまうことがあります。そうすると、元々メモリを獲得したNodeと移動先CPUの位置関係が遠くなるため、メモリアクセスコストが上昇してしまいます。

これは、スケジューラはthreadがどのNodeのメモリを主に使っているかを意識しない実装になっているからです。このため、長時間動作するアプリケーションの場合は、ユーザ側が使用するNodeを固定する等のチューニングを行わないと性能が出にくいことがあります。

従来、性能を重視するアプリケーションは、CPU位置やメモリ位置を指定するシステムコールや、cgroupのcpuset等で自身を特定のNodeにくくりつけることによりNUMAに対応してきました。この方法は、良い性能が出るのはいいのですが、ユーザにくくりつけをさせるので、ユーザがハードウェア構成を理解し、CPUメモリ配分を見切ってアプリケーションとNodeの関係を調整する必要があります。使用するアプリ/ハード構成にあわせて細かいチューニングも必要になり、総じて非NUMAマシンよりも扱いにくくなっているのですが、ここをなんとかしないと性能は出ません。最近はNUMAマシンが増えてきましたので、ハード性能を十分に引き出すための、簡単かつ動的なチューニング方法が求められています。

メモリの開発者達にとってもこれは大きな課題になっていて、議論がされています。これから紹介する2つの提案は、ユーザ側で細かいチューニング・配分などしなくても、ある程度はカーネルにお任せで性能が出るようにしよう、という提案です。1つはPeter Zijlstra氏(Red Hat)から、もう1つは Andrea Arcangeli氏(Red Hat)からの提案です。どちらもアプリケーションが細かくNode位置を意識しなくても自動的にメモリを最適に配置する機能なのですが、それぞれ考え方が異なります。

SchedNUMA

Peter氏の提案はschedNUMAという名前で、いくつかの機能が盛り込まれています。

1つ目は、一度獲得したメモリを「次のアクセスがあったNode」に移動(マイグレーション)するLazy Migration機能です。従来は、ユーザが移動先や固定先を具体的に指示し、使いたいNodeをあらかじめ指示する必要がありましたが、この指定方法は「具体的にはどのNodeか判らないけれども、とりあえずメモリアクセスのあったCPUのNodeに移動する」という指定方式で、ユーザが頑張ってthread配置を見切らなくても必要なページを必要な個所に配置できます。

2つ目は、threadに対して Home Nodeという概念を導入し、できる限りHome Node内でスケジューリングを行い、CPUとメモリの関係を崩さないようにする機能です。threadがHomeNodeを持つ場合、threadは可能な限りHomeNode内のCPUで走行するようにスケジュールします。例えば、一時的に他のNodeに移動してしまってもHome Nodeに戻ってこれるようにします。また、メモリ獲得時には「今threadが走行しているNode」からではなく、Home Nodeからメモリ獲得を行うようにします。これにより、一時的なthreadのNode間移動によってメモリ配置がバラバラになってしまうを現象を排除します。

3つ目は、Home node migrationという仕組みを導入し、threadがどうしてもHome Nodeを離れなければならない場合、threadのCPU移動と同時にメモリ内容も移動させる機能です(前述のLazy Migrationを使います⁠⁠。

これら3つの機能によってスケジューラがthreadとNodeの関係を意識して動作するようにしつつ、メモリ側もスケジューラの意思決定に追従できるようにしています。

最後に、アプリケーションからschedNUMAを使用するための新システムコールをいくつか追加しています。Numa groupという概念を導入し、numa_tbind()/numa_mbind()というシステムコールによって、threadやメモリをNuma groupに関連付けできるようにします。Numa groupというのは「同じNodeに集めるべきスレッドやメモリの組」であり、Numa group内のthreadがNodeを超えてマイグレーションする場合、同じNuma groupに所属するスレッド・メモリをまとめて移動させます。

このNuma groupにより、アプリケーションは、具体的に「Node AのCPU-BにスレッドXを配置!」⁠メモリYY~ZZはNode Aに配置!」と伝えるのではなく、⁠どこでもいいけど同じNuma groupのスレッドとメモリはお互いに近いところに配置してね…」とカーネルに伝えることができるようになります。アプリケーションが Home Nodeに納まらない場合、つまり、アプリケーションが複数Nodeにまたがるような巨大なものである場合、アプリケーションの部位ごとに前述のシステムコールで細かく指定することになりますが、この辺りは研究の余地があるかもしれません。

※)
名前が似ていますがcgroupとは関係ありません。

AutoNUMA

Andrea氏が提案しているのはAutoNUMAという機能です。システムコールは追加せず、カーネル側でアプリケーションの挙動を解析し、自動的に最適なメモリ配置を行うというものになっています(この動作は彼が開発したTransparent Huge page に似ていますね⁠⁠。まず、ページテーブルに細工をし、アプリケーションのメモリアクセスを記録します。その情報を用いて頻繁にリモートメモリにアクセスしている部分を見つけ出し、カーネルスレッドで巡回しながら自動的にメモリを再配置するほか、スケジューラがタスクを移動する際のヒントとしても使います。Peter氏のものと比較して、全自動なのでアプリケーション側の対応がいらなくなりますが、メモリアクセスの記録コストやカーネルスレッドによる巡回コストが大きな問題となっています。

2人ともRed Hat所属なのですが、それぞれ別々の方法を提案し、LKML上で激しく議論をしているのが面白いところです。このオープンさがコミュニティ開発らしいですよね。Peterの方はアプリケーションの修正が必要になりますし、Andrea氏の方はリソースをかなり使いますので、お互いのいいところをマージするような形になるといいですね。

組込みシステム向けの新機能

昨今、組込み系、モバイル系の開発者が積極的にコミュニティのカーネル開発に参加するようになり、様々な機能が提案されています。ここではそのうちの3つを紹介します。

  • CMA(Contiguous Memory Allocator)
  • mem_notify
  • メモリ電源OFF

CMA(Contiguous Memory Allocator)

Marek Szyprowski氏(Samsung)から、組込み向けの連続物理メモリアロケータが提案されています。従来のLinuxのページアロケータでは取得可能な連続物理メモリの上限サイズが決まっており、上限を超えた連続メモリの確保は困難でした。この制限を超えたい場合(ビデオカメラ用の巨大バッファの確保等⁠⁠、ブート時にメモリの一部を隠し、そこに専用のドライバでアクセスする方法などを使っていたようです。

しかしこの方法では、隠したメモリはメモリ管理の制御下には無いため他の用途に使えず、カメラ機能等を使わない場合はメモリが無駄になります。この問題を解決する新しいメモリアロケータがCMAです。CMAから連続メモリをアロケートする場合、カーネルはメモリを確保する範囲を計算し、その範囲内に使用中のメモリがあればページマイグレーションで別の領域に追い出します。マイグレーションを使って一定範囲のメモリを全て未使用にして、空いたところを連続メモリとして割り当てるのです。

ページマイグレーションを確実に行うため、CMAでは新しいCMA用の領域(zone)を定義しています。任意のメモリ領域をCMA領域としてブート時に宣言する必要はあるものの、連続バッファ用に使わないときはユーザメモリやファイルキャッシュとしても使うことができます。順調にいけば、kernel3.5でマージされる見込みです。

メモリ枯渇予兆通知(mem_notify)

メモリが枯渇する予兆を検知した際に、システム管理アプリケーション等に「メモリがもうすぐなくなるかもよ」と通知を行い、ユーザと連携してスムーズにメモリ解放を行うためのmem_notifyという機能が、現在LKMLで議論されています。このmem_notifyという通知を受けたアプリケーションは、ブラウザのキャッシュを解放したり、GC(ガベージコレクション)の機能があればGCを実行したり、メモリを取っている他のアプリケーションを停止したりします。

この機能には複数の提案者がいます。それぞれの提案内容は似ていますが、実際に通知が欲しいタイミングが異なっており、いまのところ実装方針はまとまっていません。たとえば「スワップが使用され始めたら通知する」⁠近いうちにスワップを使いそうだから通知する⁠⁠、⁠メモリ回収が大変そうなら通知する⁠⁠、等々、条件設定ががまず最初の議論となっています。議論は大変ですが、メモリ枯渇の予兆監視というのは、組込みに限らず、エンタープライズでも重要な機能の1つですので、注目を集めている議論の1つと言えます。

メモリ電源OFF

省電力機能として、CPUの電力を調整する機能はすでにありますが、最近、メモリの省電力機能についてのパッチ投稿がMaxsime Coquelin氏(ST Ericsson)からありました。DDR3 SDRAMにオプショナルな機能として搭載されるPASR(Partial Array Self Refresh)と呼ばれる機能は、メモリモジュールをいくつかのバンクと呼ばれる領域に分け、各バンクに対して選択的にリフレッシュ信号を送信する機能です。言い換えれば、メモリの一部に流すリフレッシュ電流をカットできるのです。

DRAMの特性上、リフレッシュ信号の入るバンクのデータは保持できますが、そうでないバンクのデータは保持されません。これは、メモリの一部のデータを捨てる代わりに消費電力を抑えることができる機能と言えます。提案されたパッチでは、メモリアロケータにフックを仕込み、バンク全体が未使用状態になった場合にバンクへのリフレッシュ信号を落とします。誰も使っていないメモリなら電源を落としていいだろう、というわけです。

ただし、この手法の問題点は3つほどあります。1つ目は、ページアロケータへフックを入れることによるオーバヘッドです。2つ目は、ファイルキャッシュの刈り取り処理が必要な事です。Linuxではメモリ上にファイルキャッシュを常に保持し、空きメモリをなるべく作らないようにしています。しかし提案の省電力機能を実現するためには、不要なファイルキャッシュの刈り取りルーチン作り、未使用メモリを増やさなければなりません。3つ目はメモリがフラグメンテーションを起こしていて、未使用のメモリがバラバラに分散していると省電力機能が有効に動かないことです。

CMAで行われたような対処方法(zoneの作成)でフラグメンテーションには対処できそうですが、いまのところ具体的な進展はありません。

次回は、ファイルシステム連携、資源管理、CleanCacheについて説明します。お楽しみに。

おすすめ記事

記事・ニュース一覧