LinuxTiny、カーネル2.6の安定化(その2)

7月16日から18日の3日間、今年もオタワにてLinuxカーネル開発者たちが集う「2006 Linux Kernel Developers Summit」が開かれた。今回はMichael J. Hammelによって書かれたLWN.netの記事を手がかりにして、Matt MackallがリードしたEmbedded systemsのセッションについて取り上げる。

Embedded Linux: Small Kernels

LWNでは2003年12月7日に、「Linux for little systems」というタイトルで、肥大化するLinuxカーネルのスリム化を助けるためにMatt Mackallが率いる、新しいTinyLinuxプロジェクトを紹介した。

Mackallが2004年のオタワLinuxシンポジウムで示した論文では、特定クラスのハードウェアためのパフォーマンスを改善するためにこの数年間カーネルに多くのコードを加えたが、時間とともにこのコードは、より新しいハードウェアやいくつかのケースで性能劣化を起こしたため、それほど有用ではなくなったと説明した。

解決策としては、特定クラスのハードウェアに不要な機能をカーネルから取り除くメカニズムを用意して、カーネルをより小さくし、特定の環境にさらに適合させることだった。これは家電市場のような組込みデバイスだけでなく、386ベースのハードウェアやハンドヘルドのような典型的にリソース(メモリやキャッシュやストレージなど)が少ない古いシステムへの対応を含んでいる。この目的のためにMackallは、カーネルのオプションで様々な機能によりカーネルのサイズを縮小することを目指した、1セットのPatch(あるいは1つのジャイアントPatch)を用意する、TinyLinuxプロジェクトを作成した。 有意義な最初のステップ

Mackallのオリジナルペーパに基づいたプロジェクトはTinyLinuxと呼び、-tinyのツリーとして知られている。これは、ユーザがconfig可能な様々な機能を無効にするための、多くの小さなパッチからできている。これにはSLABアロケータをSLOBと呼ぶスペース効率の良いバージョンへの切り替え、config可能なIDEとシリアルPCIハードウェアサポートのほか、オプションとしての非同期入出力サポート、sysfsとvm86、およびVTサポートの最小化を含んでいる。またnetconsole、kgdbとkgdb-over-ethernetの、デバッグ用パッチも含んでいる。

TinyLinuxは1セットのパッチとしてやって来る。ユーザはカーネルソースにどのパッチを適用したいかを、自由に選択することができる。あるいは、ソースにTinyLinux機能をすべて適用する、単一のパッチを利用することもできる。一旦パッチを適用すれば、TinyLinux機能は"make menuconfig"により、"General Setup->Configure standard kernel features"メニューの下で表示されて有効になる。

プロジェクトのゴールは、常に2MBかそれ以下のRAMで実行する最新のカーネルを構築することであった。それはコンソール、ディスクおよびネットワークサポートを含んでいる。プロジェクトのためにMackallによるガイドラインには次のものを含んでいる。

  1. すべてのシステムに適用可能でないあらゆるオプションは、config可能であるべきだ。
  2. インテグレータが必用だと判断する価値あるものを選ぶことができるように、パッチは小さく独立させるべきである。
  3. パッチをメインラインでマージすることができるように試みる。
TinyLinuxの機能

一旦選択したパッチを適用した後は、config可能なオプションは General Setup pageの下のカーネルconfigメニューでmake menuconfig後に見つかる。一番下のこのオプションは、"Configure standard kernel features (for small systems)"とラベル付けしてある。configファイル中のCONFIG_EMBEDDEDオプションは、TinyLinuxオプションが働いているところで次のレベルのメニューを生かすためにセットしなくてはならない。

TinyLinux用2.6.14リリース版には、config可能なカーネルオプションをはるかに小さくする設定を追加する80個のPatchがある。さらにいくつかの興味深いオプションでは、次のような括弧中のカーネルconfigファイルオプションに続くmenuconfigラベルでリストされたものを含んでいる。
  • Enabled accounting of kmalloc/kfree allocations (CONFIG_KMALLOC_ACCOUNTING)

    このパッチは、kmalloc/kfree呼出しを集計する機能を加える。 カーネル・イメージサイズやランタイムのメモリ割当てには効果が無いが、メモリリークや濫用を追跡するのに役立つ。 このPatchは、kmalloc/kfreeのusage statisticsを読み出す事ができる/proc/kmallocエントリを加える。 詳細は、2005年からこのパッチのLWNでのアナウンスメントを参照すること。
  • BUG() support (CONFIG_BUG)

    このパッチは2.6.14パッチセットにはない。オリジナルは2005年の初めに発表したが、それ以来カーネルメインラインへと伸びている。 このconfigオプションはカーネルBUGとWARNメッセージをすべて削除する。それはシステムを僅かだが速くさせるとともに典型的なカーネルから約35kをスリム化すると言われている。
  • Enable ELF core dumps (CONFIG_ELF_CORE)

    このパッチは、ELFコアダンプを扱うコードを削除する。 恐らく利用者はダンプを見るための方法がないか、あるいは見たいとも思わないので、小さなシステムでは、ELFコアダンプを必要とはしない。 configオプションでは、これがセットされてなくとも、fs/binfmt_elf.cファイルからかなりのラインを取り除く。
  • Enable inline measurement (CONFIG_MEASURE_INLINES)

    このオプションが有効な場合、ファイルに保存でき、コードの具体的な数を表示するためのcount-inlinesスクリプトによって処理できるデータを、カーネルコンパイル中に生成する。 このオプションは、推奨されないようなインライン関数をマークすることで、その具体例を数える。 これをセットした場合、ビルド時に非常に冗長な出力をするための準備する必用がある。
  • Number of swap files log2 (0 => 1, 5 => 32) (CONFIG_MAX_SWAPFILES_SHIFT)

    これは設定することができるスワップファイルの最大数をセットする。値はlog2であるため、0は1つのスワップファイルを、5は最大値で、32個のスワップファイルを意図する。 古いデフォルトは5である。そしてこのオプションを変更しない場合は、同じ設定でなる。
  • Use full SLAB allocator (CONFIG_SLAB)

    これをセットしない場合、-tinyではSLOBと呼ぶ、より単純なシステムにkmallocを実行させる、高度なSLABアロケータに置き換える。 SLOBに関するMattのオリジナルのポストでは次のように説明している。
    SLOBはSLABエミュレーションレイヤを持つ、伝統的なのK&R/UNIXアロケータである。 また、SLABが置き換えたオリジナルのLinux kmallocアロケータに似ているとも言える。これは著しくより小さなコードで、はるかに効率的なメモリ管理を行う。 しかしすべての同様なアロケータのように、フラグメンテーションについては、SLABと比較して貧弱である。したがって小さなシステムに限って、適切なだけである。
  • Use mempool allocator (CONFIG_MEMPOOL)

    Mempoolsは初期のカーネル2.5のツリーの一部を構成し、後で新しいブロックI/Oレイヤのパーツとして導入された。 目的は、成功しなければスリープできないメモリ要求に対して、デッドロックを防ぐ解決方法を用意することである。 このオプションにより、いくつかの小さなシステム構成では、事前割り付けによるメモリプールを、 「不要」と「リソース限界の浪費」の両方の間で検討することができる。 しかしながら、このオプションの導入はいくつかの興味ある問題を示すことになる。 それは、mempoolsが実際にデッドロックをゼロまで削減するのかどうかと、mempoolsを完全に削除することは「デッドロックの発生を保証する」ようになるのか、ということである。 いずれにしてもこのオプションの使用は、小さなメモリのシステムを助けることができるが、 「デッドロックの発生率はいくつかのシナリオにおいて、明らかに高くなる」とMattが言ったことを知っておくべきである。
Working With TinyLinux

TinyLinuxは先日、2.6.14カーネル用に更新された。 Imageサイズを縮小し、かつ2MBほどのメモリの中でカーネルを走らせるために、これらのパッチが実際に動作するかどうかを確認するために、私は、このカーネルで-tinyパッチを実験した。私は最初にVIA EPIA-M用にカーネルをコンパイルした後、単純なシェルが起動するようにBusyBoxを initramfsにStripして導入した。

その後、私はTinyLinuxの単一パッチを適用した。ここで構築したカーネルは、「CE Linux Forum」の「about using TinyLinux」のページで指定されたconfigオプションをベースにした。このページは、最新のTinyLinuxには全く同期していないため、私は彼らの提案をわずかばかり修正しなければならなかったのである。

コンパイルされたカーネルは、テストボードで起動するために圧縮される。圧縮ファイルは次のように、TinyLinuxイメージでざっと410KBをセーブしている。 mjhammel(tty3)$ l linux-2.6.14* -rw-r--r-- 1 root root 1550312 Jun 25 23:09 linux-2.6.14-via -rw-r--r-- 1 root root 1139708 Jun 26 22:08 linux-2.6.14-tinylinux Memory Usage

TinyLinuxが実際に助けになったかを確認するために、我々はイメージ中のテキスト、データおよびbssサイズが著しく変わったかどうかを最初にチェックすることができる。CE Linuxフォーラムのsize-deltaスクリプト・プログラムは、圧縮されていないLinuxカーネルイメージを読み、TinyLinuxの効果がどれ位かを、比較することができる。 $ size-delta vmlinux.via vmlinux.tinylinux vmlinux.via => vmlinux.tinylinux text: 2695282 2050286 -644996 -23% data: 440124 229107 -211017 -47% bss: 178912 129976 -48936 -27% total: 3314318 2409369 -904949 -27%

見ればわかるように、最終コンフィギュレーションは元のVIAコンフィギュレーションと比較して、サイズで27%以下の削減を生んでいる。

しかしランタイムメモリ使用量をチェックすることで、TinyLinuxパッチの効果を実際に見ることができる。カーネルがどのように起動したかを確認する最良の方法は、dmesgのmemory usageの行をチェックすることである。私は最初に、TinyLinuxパッチ無しのカーネルのmemory usageをチェックした。 % dmesg | grep Memory Memory: 4028k/8192k available (2179k kernel code, 3756k reserved, 727k data, 160k init, 0k highmem)

そしてTinyLinuxカーネルで試した。ここでdmesgを使用することには、ちょっとした問題がある。このカーネル用のconfigの中で、CEフォーラムコンフィギュレーションに提案されるように、私はTinyLinuxオプションを使用するのでprintk()を無効になった、しかし、dmesgはprintk()を必要とする。printk()'sを再度つけることは、カーネル用のメモリ使用量を増加させる訳である。ランタイムでメモリ使用量の変化を見ることを簡単にするために必要とされることとは、トレードオフである。

TinyLinuxカーネルは、起動時にこのような行を生成した。 % dmesg | grep Memory Memory: 4028k/8192k available (1794k kernel code, 3072k reserved, 484k data, 136k init, 0k highmem)

この「reserved」数値は、全てが動作し始める前に、カーネルがサーキュレーションから取り出したメモリの量である。それは「カーネルコード」を始め、様々な他のものを含んでいる。両方のカーネルはmem=8Mで起動した。TinyLinuxカーネルでは、約400kのカーネルコードと700k近くの「reserved」メモリをセーブした。

CEフォーラムの提案ではリストされていなかった、カーネルをより小さくする他のオプションを使用することができるかどうか確かめるために、私は下記を試みた。 Disabled these: - Enable panic reporting code - Enable various size reductions for networking - Enable ethtool support - Enable device multicast support - Enable inline measurement Enabled these: - Optimize for size

結果は、さらに良くなった。 % dmesg | grep Memory Memory: 5016k/8192k available (1526k kernel code, 2768k reserved, 464k data, 126k init, 0k highmem)

1M近くをセーブしているが、まだ私は、不要なカーネルドライバをまだstripしていない。

もっと入れたい場合は、/proc/slabinfoを見ることである。それはシステムSLABキャッシュと、各々にどれだけのメモリをコミットするかを含んでいる。これは低レベルの下手な情報であるが、どんな-tinyの部分がSLABの多くのサイズ縮小をするかがわかる。/proc/meminfoの中の「slab」行は、SLABによって消費されたメモリの合計を与えてくれる。私が構築した最新のカーネルでは、meminfoは796kBのSLAB値を示した。オリジナルのカーネルにおいては、この値が872kBだった。 TinyLinuxの将来

最新のTinyLinuxパッチセットは2.6.14カーネルで動作する。既に2.6のメインラインのカーネルへと、Linux-tinyからの多くの機能を統合した。また、Mackallは最終的なマージに残るものを、クリーンアップしている最中でる。

CELFのプレゼンテーションでMackallは、TinyLinuxは最早手伝っていないとで述べた。さらに彼は、新しいカーネルリリースのために新しいTinyLinuxリリースをなおいっそう頑張って作成するために努力しているため、プロジェクトに対してあまり多くのフィード・バックや貢献を得ていなかった。Mackallによれば次のように、その問題は彼が迅速にプロジェクトを進め、早い段階から成功していたからではないかという。
私は非常に早い時期に、低く吊るされたすべての果物を手に入れた。したがって、他の人々が貢献をするための容易な方法がなかった。同時にメインストロームの開発に注目することは、自分のツリーで動作するより広い聴衆とテストベースを集める。それは私が焦点をシフトした主要な理由である。


Mackallは、メインラインにほとんどのパッチを発展させている最中である。 TinyLinuxの向こうには

カーネルサイズを縮小するためにほかに何を行うことができるか。CE LinuxフォーラムOpen Test Labシステムサイズで動作するためのリソースについて提示している。いくつかの提案では、非常にコンパクトなramdiskベースのルートファイルシステムを使用するために、SquashFSとCramFSの使用を含んでいる。これは、私が組み込みLinuxについて次の記事で取り上げるテーマである。

uIPスタックのような、より小さなnetwork stackの使用法で議論されない領域の解決策は、システム・インテグレーターの初心者向けではないが、単純なPatchとカーネルコンパイルの向こうにある。

このシリーズの次の回は、私はカーネルを通り越して、ルートファイルシステムまで移動している。ルートファイルシステムは起動するだけでなく、小さなシステム上で、必然的に実行するつもりのアプリケーションにアクセスするのに必要である。ルートファイルシステムを小さくしておくことは、利口なカーネルモジュールと共に特別の構造ツールとユーティリティの混合物を含んでいる。私は、BusyBox、SquashFSのような圧縮したファイルシステムおよび特別のUnionFSファイルシステムを見よう。

注:この文章はLWNの主宰であるJonathan Corbet氏に確認して、http://lwn.net/Articles/191137/の記事を翻訳したものを含んでいる。

日高 亜友:株式会社デバイスドライバーズ、代表取締役社長。http://www.devdrv.co.jp/