Linux カーネルプロファイリング

このドキュメントでは組込み Linux 開発用 CPU ボード Bishop でカーネルレベルのプロファイリングを行う手順として、 最もシンプルな readprofile と今後 Linux カーネルの標準的なプロファイラとなると思われる OProfile の 簡単な使用方法を紹介します。

1. readprofile

1.1. 概要

Linuxカーネルに標準で含まれるシンプルなプロファイラ (kernel/profile.c) は tick 毎に実行アドレスをカーネル内部のプロファイリングバッファに保持します。このバッファは仮想ファイル /proc/profile を通じてユーザ空間からアクセスできますが、/proc/profile はバイナリファイルであるためそのままでは読めません。readprofile は /proc/profile を可読化するために使用されるツールです。

1.2. 使用方法

1.2.1. readprofile のインストール

readprofile コマンドをインストールしてください。Debian の場合、readprofile は util-linux パッケージに含まれます。

# aptitude install util-linux

開発ホストとターゲットの両方にインストールしておくと便利です。

1.2.2. Linux カーネルのビルド

CONFIG_PROFILING を有効にしてカーネルをビルドします。

$ cd linux-2.6.26.8-pylone0
$ make ARCH=arm menuconfig
  General setup  --->
   [*] Profiling support (EXPERIMENTAL)
$ make ARCH=arm CROSS_COMPILE=arm-linux-gnu- uImage

uImage と同時に作られる System.map も後で使用します。

1.2.3. Linux カーネルを起動

プロファイラを有効にするカーネル起動パラメータ profile を追加して前節でビルドしたカーネルを起動します。

U-Boot のモニタコマンドでカーネルパラメータを追加する例:

Bishop # setenv bootargs console=....  profile=2

profile= に渡される数値が大きい程プロファイラのバッファが小さくなります。

起動後に /proc/profile が存在すれば、カーネルのプロファイラが有効になっています。

1.2.4. readprofile の基本的な使い方

-m オプションで System.map を指定します。

bishop:~# readprofile -m /PATH/TO/System.map

/proc/profile を可読化したものが出力されます。

bishop:~# readprofile
     3 start_kernel                               0.0045
     1 tcp_init                                   0.0014
    18 calibrate_delay                            0.0464
    19 do_DataAbort                               0.1187
     7 __dabt_svc                                 0.0729
       [...]
     1 down_write                                 0.0500
     1 down_read                                  0.0500
     4 __down_write_nested                        0.0182
     1 __down_write                               0.0417
     0 *unknown*
 15409 total                                      0.0047

1番目のカラムが tick 毎にサンプリングされた tick 回数で、 2番目のカラムが関数名です。 3番目のカラムは正規化された負荷で、サンプリングされた tick 回数と関数の長さの比率です。[1]

-p オプションで /proc/profile を変更できますので、ターゲット側のプロファイリングをホスト側で見たい場合は

ターゲット

bishop:~# cat /proc/profile > profile-shapshot

ホスト:

# readprofile -p profile-snapshot -m /PATH/TO/System.map

のようにすればよいでしょう。

また、-r オプションでプロファイラのバッファをリセットできるので、特定のプログラム (your_program) 実行中のプロファイリングしたい場合は

bishop:~# readprofile -r
bishop:~# your_program
bishop:~# readprofile -m /PATH/TO/System.map

とすることもできます。

さらに詳しい使い方については readprofile(1) を参照してください。

1.3. プロファイリングバッファのサイズについて

プロファイラのバッファは kernel/profile.c の profile_init() で確保されます。

void __init profile_init(void)
{
	if (!prof_on)
		return;

	/* only text is profiled */
	prof_len = (_etext - _stext) >> prof_shift;
	prof_buffer = alloc_bootmem(prof_len*sizeof(atomic_t));
}

prof_shift は profile= パラメータで渡された数値です。

_etext と _stext は以下のようにすれば知ることができます。

$ arm-linux-gnu-objdump -t vmlinux | grep _[es]text
c0376000 g       *ABS*  00000000 _etext
c0008000 g       .text.head     00000000 _stext

Linux/ARM の場合、上記の _etext, _stext で profile=2 とするとバッファサイズは

バッファサイズ = ((_etext - _stext) >> prof_shift) * sizeof(struct atomic_t)
               = ((0xc0376000 - 0xc0008000) >> 2) * 4
               = 0x36e000
                 (約3.5MB)

となります。

/proc/profile のファイルサイズはこれと同じになっている筈です。

2. OProfile

2.1. 概要

OProfile は Linux カーネルに標準で含まれるオーバーヘッドが少ないシステムワイドなプロファイラです。 gprof などのユーザ空間プロファイラと違い、カーネル空間も含めたプロファイリングが可能です。

2.2. 使用方法

2.2.1. Linux カーネルのビルド

CONFIG_PROFILING と CONFIG_OPROFILE を有効にしてカーネルをビルドします。

$ cd linux-2.6.26.8-pylone0
$ make ARCH=arm menuconfig
  General setup  --->
   [*] Profiling support (EXPERIMENTAL)
   [ ] Activate markers
   <*> OProfile system profiling (EXPERIMENTAL)
$ make ARCH=arm CROSS_COMPILE=arm-linux-gnu- uImage

カーネル空間のプロファイリングを行うのであれば、uImage だけでなく vmlinux も後で使用します。

2.2.2. Linux カーネルを起動

CONFIG_OPROFILE を有効にしたカーネルで起動します。OProfile だけを使うのであれば起動パラメータを追加する必要はありません。

2.2.3. OProfile のインストール

ターゲットの /etc/apt/sources.list に以下の apt-line を追加します。

deb http://downloads.pylone.jp/bishop/deb/etch ./

oprofile-common パッケージ をインストールします。

bishop:~# aptitude update
bishop:~# aptitude install oprofile-common

株式会社パイロンが etch の oprofile パッケージを ARM 用にリビルドした非公式パッケージです。このパッケージに関する質問を Debian プロジェクトにすることはご遠慮ください。

2.2.4. OProfile の基本的な使い方

a.out 実行中のプロファイリングを行うには opcontrol コマンドを以下のように実行します。

bishop:~# opcontrol --vmlinux=/PATH/TO/vmlinux
bishop:~# opcontrol --reset
bishop:~# opcontrol --start ; a.out ; opcontrol --stop

カーネル空間のプロファイリングが不要であれば --vmlinux= の代わりに --no-vmlinux を指定します。

bishop:~# opcontrol --no-vmlinux

プロファイルの結果を見るためには opreport コマンドを使用します。

bishop:~# opreport
CPU: CPU with timer interrupt, speed 0 MHz (estimated)
Profiling through timer interrupt
          TIMER:0|
  samples|      %|
------------------
     3475 89.1940 a.out
      356  9.1376 vmlinux
       34  0.8727 bash
       17  0.4363 libc-2.3.6.so
       12  0.3080 ld-2.3.6.so
        1  0.0257 mktemp
        1  0.0257 oprofiled

上記の通りオプション無しで opreport を実行すると各プロセス毎のサンプリング数で表示されます。Bishop の S3C2440 を含めハードウェアパフォーマンスモニタをサポートしていない CPU の場合はタイマ割込みによるサンプリングとなり、粒度は CONFIG_HZ によって変わります。

-l オプションをつけて opreport を実行すればプロセス毎ではなくシンボル名毎の表示になります。

bishop:~# opreport -l
CPU: CPU with timer interrupt, speed 0 MHz (estimated)
Profiling through timer interrupt
samples  %        app name                 symbol name
3473     89.1427  a.out                    function_heavy
185       4.7485  vmlinux                  default_idle
34        0.8727  bash                     (no symbols)
17        0.4363  libc-2.3.6.so            (no symbols)
16        0.4107  vmlinux                  $a
16        0.4107  vmlinux                  update_mmu_cache
[...]
1         0.0257  vmlinux                  write_cache_pages
1         0.0257  vmlinux                  xprt_release_rqst_cong
1         0.0257  vmlinux                  xprt_reserve_xprt_cong

上記の libc-2.3.6.so のように実行ファイルにシンボルが含まれていない場合は (no symbols) と表示されます。

実行ファイルを指定することで特定のプログラムのみを表示させることもできます。

bishop:~# opreport -l a.out
CPU: CPU with timer interrupt, speed 0 MHz (estimated)
Profiling through timer interrupt
samples  %        symbol name
3473     99.9424  function_heavy
1         0.0288  function_light
1         0.0288  function_nop

シンボル情報付きの実行ファイルとソースコードがあれば、opannotate コマンドでプロファイリング結果とソースを関連付けて表示することもできます。

Cのソースと関連付けて表示:

bishop:~# opannotate -s a.out

アセンブリと関連付けて表示:

bishop:~# opannotate -a a.out

Cとアセンブリの表示をミックス:

bishop:~# opannotate -sa a.out

さらに詳しい使い方については OProfile のマニュアルを参照してください。

3. 関連リンク

  1. ^ the normalized `load' of the procedure, calculated as a ratio between the number of ticks and the length of the procedure
cc