特集 : 起動時間短縮方法 - 起動の基本と時間の測りかた

対象製品: Armadillo-500Armadillo-300Armadillo-9Armadillo-240Armadillo-230Armadillo-220Armadillo-210
シリーズ紹介

起動処理の基本

起動処理は(1)ブートローダーによる初期化と(2)カーネルの起動、(3)ユーザランドの初期化の3つに分けることができます。さっそく、ブートローダーから順番に見ていきましょう。

Hermit-At


Hermit-At v1.1.4 (Armadillo-220/eth) compiled at 21:30:26, Aug 24 2006
hermit> b
Uncompressing kernel................................... [途中省略] ...done.
Uncompressing ramdisk..................................... [途中省略] ...done.

(1)ブートローダーによる初期化

ブートローダーの仕事は、ハードウェアの初期化とLinuxカーネルが起動する環境の用意です。ブートローダは以下のような処理を順番に行ないます。

  1. ハードウェアを初期化
  2. カーネルデータをフラッシュメモリからRAMの特定アドレスに展開
  3. ユーザーランドのデータをフラッシュメモリからRAMの特定アドレスに展開
  4. カーネルに制御を渡す

ハードウェアの初期化は機器によって様々です。DRAMコントローラの初期化や周辺機器の初期化を行ないます。ユーザランドのデータは、ext2ファイルシステムを持つinitrdです。initrdは起動時に使われるRAMデスクです。デスクトップまたはサーバー用のLinuxでは、HDDのルートファイルシステムをマウントする前の一時的なルートファイルシステムとして使われます。組込みLinuxではRAMディスクをそのままルートファイルシステムとして使う場合、そのまま使われます。最後にブートローダからカーネルに制御が移して、ブートローダの仕事は終了です。

(2)カーネルの起動


Doing mtdparts=armadillo2x0-nor:0x10000(bootloader)ro, 0x170000(kernel), 0x670000(userland),-(config)
Linux version 2.6.12.3-a9-6 (nakai@pc-silvia) (gcc version 3.4.4 20050314 (prerelease) (Debian 3.4.3-13)) #1 Wed Aug 16 19:56:11 JST 2006
  :
  :
  :
RAMDISK: ext2 filesystem found at block 0
RAMDISK: Loading 6591KiB [1 disk] into ram disk... done.
VFS: Mounted root (ext2 filesystem).
Freeing init memory: 96K

カーネルもハードウェアの初期化を行ないます。ハードウェアを初期化した後に、カーネルとしてアプリケーションを管理するためにメモリー内に色々なデータ構造を作成し初期化を行ないます。ログに表示されている「Loading 6591KiB [1 disk] into ram disk」は、ブートローダーがメモリに展開したinitrdイメージをRAMディスクとして使用していることを表わしています。その後、カーネルがこのRAMディスク(/dev/ram0)をルートファイルシステムとしてマウントします。

(3)ユーザランドの初期化


init started:  BusyBox v1.00 (2006.08.16-10:57+0000) multi-call binary
Remounting root rw: 
Mounting proc: 
Mounting usbfs: 
Mounting sysfs: 
Loading /etc/config: 
Setting hostname: 
Changing file permissions: 
Starting basic firewall: 
Configuring network interfaces: 
Starting sshd: 
Starting syslogd: 
Starting thttpd: 
Starting avahi-daemon: 
Starting usbmgr: 

atmark-dist v1.6.0 (AtmarkTechno/Armadillo-220.Recover)
Linux 2.6.12.3-a9-6 [armv4tl arch]

a220-0 login: root
Password: 
[root@a220-0 (ttyAM0) ~]# 

ユーザーランドはinitプロセスの実行からはじまります。initは /etc/init.d/にある起動スクリプトを逐次実行していきます。起動スクリプトは、ファイルシステムの準備やネットワーク設定、サーバアプリケーションの起動など、システムとして必要なシステムプログラムの実行を行ないます。

起動時間の計測(ストップウォッチ)

ストップウォッチを使って、電源を入れてからログインプロプトが出るまでの時間を測ってみると約14秒でした。それぞれの区間の時間はおよそ以下の表の通りです。

区間時間
ブートローダー3秒
カーネル2〜3秒
ユーザーランド8秒

起動時間の計測(カーネル)

バージョン 2.6以降のLinuxカーネルにはタイミング情報を出力する機能が追加されました。カーネルにパラメータを渡すことでタイミング情報の出力を有効にすることができます。タイミング情報を有効にするとカーネルが行なうすべての出力に


[00000000.000000] printk'ed string

のように「[]」に囲まれた数字が表示されるようになります。この数字はある特定の値からの経過時間を秒であらわしています。ある区間の経過時間を計算するには、後に表示された数字から前に表示された時間を引き算することで求めることができます。電源投入時からの秒数ではありませんので、注意が必要です。

タイミング情報から経過時間を調べる時に便利なスクリプトが、linux-2.6.x/scriptsの下にshow_deltaという名前で置いてあります。ぜひ使ってみてください。

カーネルパラメータはブートローダで以下のように設定することができます。


 hermit> setenv time
 hermit> setenv
 1: time
 hermit> b
 Kernel command line: time mtdparts=armadillo2x0-nor:0x10000(bootloader)ro, 0x170000(kernel), 0x670000(userland),-(config)
 [42949372.960000] PID hash table entries: 256 (order: 8, 4096 bytes)
 [42949372.970000] Dentry cache hash table entries: 8192 (order: 3, 32768 bytes)
 [...]
 [42949375.140000] VFS: Mounted root (ext2 filesystem).
 [42949375.150000] Freeing init memory: 96K
 init started:  BusyBox v1.00 (2006.08.16-10:57+0000) multi-call binary

設定後、起動ログの行頭に経過時間が表示されていることがわかります。最初に表示された時間から、initの文字列が表示される直前の時間まで計算してみると、カーネルの起動時間が2.19秒だったことがわかります。これで、かなりの精度で時間を測れるようになりました。さっそく起動時間を短縮をしてみたいと思います。

デフォルトでは起動ログがシリアルコンソールに出力されるように設定されています。しかしシリアル通信にCPUの時間が取られてしまうために、カーネルの起動が遅くなってしまいます。そこで、起動パラメータでquietを指定し、シリアルコンソールにログが出力しないようにします。


hermit> setenv time quiet
hermit> setenv
1: time
2: quiet
hermit> b

起動ログはリアルタイムに見ることができませんが、dmesgというコマンドでログインした後に確認することができます。


 a220-0 login: root
 Password:
 [root@a220-0 (ttyAM0) ~]# dmesg
 [...]
 Kernel command line: time quiet mtdparts=armadillo2x0-nor:0x10000(bootloader)ro, 0x170000(kernel), 0x670000(userland),-(config)
 [42949372.960000] PID hash table entries: 256 (order: 8, 4096 bytes)
 [42949372.960000] Dentry cache hash table entries: 8192 (order: 3, 32768 bytes)
 [...]
 [42949374.200000] RAMDISK: Loading 6591KiB [1 disk] into ram disk... done.
 [42949374.540000] VFS: Mounted root (ext2 filesystem).
 [42949374.540000] Freeing init memory: 96K

シリアルコンソールにログを表示しないだけで、起動時間は 2.19秒から 1.58秒に短縮することができました。

テスト用の設定

これからテストを進めていく上で、いくつかカーネルの設定をデフォルト状態から変更しておきたいと思います。変更点は

  • タイミング情報の設定をコンパイル時に設定する
  • カーネルのログバッファを大きくする
  • プロセスの起動をログに出す

タイミング情報をパラメータで設定した場合、起動直後のログにタイミング情報が表示されません。このため、この設定をコンパイル時に設定することにします。また、プロセスの起動情報をログに出すために、dmesgで取得しなければいけな情報が大きくなります。このために、カーネルのログバッファを大きくします。


 Kernel hacking  --->
 [*] Show timing information on printks
 [*] Kernel debugging
 (14 -> 16)  Kernel log buffer size (16 => 64KB, 17 => 128KB)

プロセスの起動情報をログに出すにはカーネルを修正する必要があります。以下のパッチをカーネルに当て、プロセスがforkとexecveする度にログにメッセージを出力するように変更します。

注意:このパッチは現状有姿(as is)提供され、いかなる保証もありません。このパッチを適用したことにより生じた不具合や障害について一切の責任を負いません。


[PC ~/atmark-dist/linux-2.6.x]$ patch -p1 < fork-reporting.patch
[PC ~/atmark-dist/linux-2.6.x]$ patch -p1 < execve-reporting.patch

上記の変更を加えた後、一度カーネルとユーザランドを作成し、生成されるイメージのサイズと起動時間を確認します。だたし、ネットワークの設定は固定IPアドレスに変更します。DHCPを使用するとIP番号の割り当てに必要な時間が外部環境に依存してしまうために、計測している場合には不安定要素になってしまうためです。

まずは生成されたイメージの大きさですが、以下のようになりました。

ファイル名 サイズ(Byte)
linux.bin 3234829
linux.bin.gz1431836
romfs.img 6291501
romfs.img.gz2218893

次のカーネルパラメータを設定した後に起動し、dmesgを利用して起動時間を確認します。


hermit> setenv print_fork print_execve
hermit> setenv
1: print_fork
2: print_execve
hermit> b
[...]
Doing print_fork
Doing print_execve
Doing mtdparts=armadillo2x0-nor:0x10000(bootloader)ro,\
0x170000(kernel), 0x670000(userland),-(config)
[42949372.960000] Linux version 2.6.12.3-a9-7 (chris@ubun52x)  \ 
(gcc version 3.4.4 20050314 (prerelease) \
(Debian 3.4.3-13)) #1 Fri Oct 6 16:11:40 JST 2006
[42949372.960000] CPU: ARM920Tid(wb) [41129200] revision 0 (ARMv4T)
[...]
a220-0 login: root
Password:
[root@a220-0 (ttyAM0) ~]# dmesg -s 64000
[...]
[42949375.160000] VFS: Mounted root (ext2 filesystem).
[42949375.170000] Freeing init memory: 96K
[42949375.180000] execve: /sbin/init
[...]
[42949383.330000] execve: /bin/ledctrl
[42949383.340000] forked: init (788)
[42949383.350000] execve: /sbin/getty

カーネルの起動(Linux versionから/sbin/initまで)が2.22秒で、ユーザランドの起動(/sbin/gettyまで)が8.17秒になりました。カーネルとユーザランドの詳細な調査は次回のHowtoで行なうことにして、今回はAtmark Distのコンフィギュレーションだけで、「どこまで最短で起動するカーネルとユーザランドを作成できるか」に挑戦したいと思います。。

小さいカーネル

Linuxカーネルにはいろいろな機能が入っています。しかし、ただ起動するだけで良いカーネルを作るのであれば、かなりの機能を外すことができます。機能が減ることで、カーネルのサイズが小さくなりますし、実行時に初期化やデバイスの捜査を行う必要がなくなります。カーネルが小さければ、ブートローダーによるフラッシュメモリからRAMへのコピーや圧縮されたカーネルの展開に必要な時間も短くなります。テストの為に以下の機能を全て外してみましたが、カーネルは正常に立ち上がりました。


General setup  --->
 [ ] Support for paging of anonymous memory (swap)
 [ ] System V IPC
 [ ] Sysctl support
 [ ] Kernel Userspace Events 
 [*] Configure standard kernel features (for small systems)  --->
   [ ]   Load all symbols for debugging/kksymoops
   [ ]   Enable futex support
   [ ]   Enable eventpoll support
   [ ]   Use full shmem filesystem

Loadable module support  --->
 [ ] Enable loadable module support

File systems  --->
 < > Ext3 journalling file system support
 DOS/FAT/NT Filesystems  --->
  < > MSDOS fs support
  < > VFAT (Windows-95) fs support
 Pseudo filesystems  --->
  [ ] /proc file system support
  [ ] sysfs file system support
 Miscellaneous filesystems  --->
  < > Journalling Flash File System v2 (JFFS2) support
 Native Language Support  --->
  < > Base native language support

Device Drivers  ---> 
 Memory Technology Devices (MTD)  --->
  [ ]   Caching block device access to MTD devices 
  NAND Flash Device Drivers  --->
   [ ] NAND Device Support
 Block devices  --->
  [ ] Loopback device support
  IO Schedulers  ---> 
   [ ] Deadline I/O scheduler
   [ ] CFQ I/O scheduler
 SCSI device support  --->
   [ ]   SCSI disk support
   [ ]   SCSI CDROM support
 Networking support  --->
  [ ] Networking support
 Character devices  --->
  [ ] Armadillo-210/220/230/240 GPIO driver
  [ ] Armadillo-210/220/230/240 LED driver
  [ ] Armadillo-220/230/240 Tact Switch driver
  [ ] Legacy (BSD) PTY support
 I2C support  ---> 
  [ ]   I2C device interface
 USB support  --->
  [ ] Support for Host-side USB

Cryptographic options  --->
 [ ] Cryptographic API

Library routines  --->
 [ ] CRC32 functions

この設定でカーネルをビルドしたところ、以下のサイズになりました。

ファイル名 オリジナルサイズ(Byte)今回のサイズ(Byte)サイズ比(%)
linux.bin 3,234,829 899,249 27.7
linux.bin.gz1,431,836 388,672 27.1

小さいユーザランド

通常、カーネルは起動時に/sbin/initを実行します。しかし、/sbin/initがルートファイルシステムにない場合、/bin/shを代わりに実行します。これを利用して、/bin/shだけを持つ busyboxだけ入ったユーザランドで起動してみます(ただ、シェルだけではなにもできないので、lsとdmesgを入れておきます)。atmark-distのmenu configで、以下の機能だけ有効にし、他はすべて無効にしました。


Busybox -->
[*] dmesg
[*] ls
[*] shell
[*] ash:  ASH shell
[*]       ASH is /bin/sh
[*]       ASH Optimize for size instead of speed  
[*] sh: Hide message on interactive shell startup
[*] test

atmark-distビルドすると、ユーザランドのイメージが自動計算で以下のサイズになりました。ほとんどlibcです。

ファイル名 オリジナルサイズ今回のサイズ(Byte)サイズ比(%)
romfs.img 6,291,501 2,097,209 33.3
romfs.img.gz2,218,893 683,561 30.8

それでは、このカーネルとユーザランドの起動時間を測ってみましょう。以下に起動ログのすべてを載せます。


hermit> setenv
1: print_fork
2: print_execve
hermit> b
Uncompressing  kernel............................done.
Uncompressing ramdisk.................................................done.
Doing print_fork
Doing print_execve
Doing mtdparts=armadillo2x0-nor:0x10000(bootloader)ro,0x170000(kernel),
0x670000(userland),-(config)
[42949372.960000] Linux version 2.6.12.3-a9-7 (chris@ubun52x) (gcc version 3.4.4 20050314 (prerelease) (Debian 3.4.3-13)) #3 Fri Oct 6 17:16:57 JST 2006
[42949372.960000] CPU: ARM920Tid(wb) [41129200] revision 0 (ARMv4T)
[42949372.960000] CPU0: D VIVT write-back cache
[42949372.960000] CPU0: I cache: 16384 bytes, associativity 64, 32 byte lines, 8 sets
[42949372.960000] CPU0: D cache: 16384 bytes, associativity 64, 32 byte lines, 8 sets
[42949372.960000] Machine: Armadillo-220
[42949372.960000] ATAG_INITRD is deprecated; please update your bootloader.
[42949372.960000] Memory policy: ECC disabled, Data cache writeback
[42949372.960000] Built 1 zonelists
[42949372.960000] Kernel command line: print_fork print_execve mtdparts=armadillo2x0-nor:0x10000(bootloader)ro,0x170000(kernel),0x670000(userland),-(config)
[42949372.960000] PID hash table entries: 256 (order: 8, 4096 bytes)
[42949372.970000] Dentry cache hash table entries: 8192 (order: 3, 32768 bytes)
[42949372.980000] Inode-cache hash table entries: 4096 (order: 2, 16384 bytes)
[42949372.990000] Memory: 8MB 8MB 16MB = 32MB total
[42949373.000000] Memory: 29296KB available (782K code, 159K data, 64K init)
[42949373.200000] Mount-cache hash table entries: 512
[42949373.200000] CPU: Testing write buffer coherency: ok
[42949373.210000] checking if image is initramfs...it isn't (bad gzip magic numbers); looks like an initrd
[42949373.270000] Freeing initrd memory: 2048K
[42949373.280000] Linux NoNET1.0 for Linux 2.6
[42949373.290000] SCSI subsystem initialized
[42949373.300000] NetWinder Floating Point Emulator V0.97 (double precision)
[42949373.310000] ttyAM0 at MMIO 0x808c0000 (irq = 52) is a EP93XX
[42949373.320000] ttyAM1 at MMIO 0x808d0000 (irq = 54) is a EP93XX
[42949373.320000] ttyAM2 at MMIO 0x808e0000 (irq = 55) is a EP93XX
[42949373.330000] io scheduler noop registered
[42949373.340000] io scheduler anticipatory registered
[42949373.350000] RAMDISK driver initialized: 16 RAM disks of 16384K size 1024 blocksize
[42949373.360000] armadillo2x0-nor: Found 1 x16 devices at 0x0 in 16-bit bank
[42949373.370000]  Amd/Fujitsu Extended Query Table at 0x0040
[42949373.370000] armadillo2x0-nor: CFI does not contain boot bank location. Assuming top.
[42949373.380000] number of CFI chips: 1
[42949373.380000] cfi_cmdset_0002: Disabling erase-suspend-program due to code brokenness.
[42949373.390000] 4 cmdlinepart partitions found on MTD device armadillo2x0-nor
[42949373.400000] parse_mtd_partitions:4
[42949373.400000] Creating 4 MTD partitions on "armadillo2x0-nor":
[42949373.410000] 0x00000000-0x00010000 : "bootloader"
[42949373.410000] 0x00010000-0x00180000 : "kernel"
[42949373.420000] 0x00180000-0x007f0000 : "userland"
[42949373.420000] 0x007f0000-0x00800000 : "config"
[42949373.430000] RAMDISK: ext2 filesystem found at block 0
[42949373.430000] RAMDISK: Loading 2048KiB [1 disk] into ram disk... done.
[42949373.570000] VFS: Mounted root (ext2 filesystem).
[42949373.580000] Freeing init memory: 64K
# ls /bin
busybox  dmesg    ash      sh       ls
# dmesg -s 64000
[...]
[42949373.430000] RAMDISK: Loading 2048KiB [1 disk] into ram disk... done.
[42949373.570000] VFS: Mounted root (ext2 filesystem).
[42949373.580000] Freeing init memory: 64K
[42949373.590000] execve: /bin/sh
[...]

カーネルとbusyboxのシェルが0.63秒で起動します。また、quietを指定して起動してみると0.39秒です。Hermit-Atでの展開を含めても2秒ほどです!

もちろんこのカーネルとユーザランドはそのまま製品に使えませんが、大事なことを2つ実感できると思います。

  • カーネルには必要のない機能が多い
  • 自由な発想で起動時間を短縮することができる

Armadilloを製品化する時、デフォルトのカーネル設定から外せる機能がきっとあるはずです。それらを外すことで起動時間は短縮することができます。また、ユーザランドのディレクトリ構成やブートの流れをLinuxやUnixの標準に沿って構築することはメンテナンスを考えるととても良いことだと思います。しかし、組込み機器なのですから速い起動時間を目指し、ユーザランドの構成を変更するのも同じく良いことだと思います。

次回

次回からArmadillo-220のRecover機能を提供しながら起動時間を短縮する方法を見て行きたいと思います。2秒から14秒までの間、何秒になるでしょうか。その時まで ぜひ Armadilloの起動時間を調査していろいろ試してみてください。

シリーズ紹介