Skip to main content.
Google custom search

NetBSD ドキュメンテーション: カーネルプロファイリング HOWTO

この文章にはどのようにカーネルプロファイリングが動作し、 どう使うのかが書かれています。このドキュメントは Matthias Drochner の筆によります。

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


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

どのように動作するのか (トップ)

プロファイル済みのコードの振る舞いに関する、 2種類のデータが個別に記録されます: 全関数の呼び出し頻度 (呼び出しグラフプロファイリング) と各関数の処理にかかった時間です。 これらは、適当にサンプルされた時に関数内にあるプログラムカウンターの確率によって概算され、 その確率は、調べている関数が実行中に起こる、 プロファイリングタイマーの割り込み率によって逆に概算されます。 gprof(1) というユーティリティーを使って、データを解釈します。 しかし、二つのデータの相関性がないため、いくつか制限が出てきます。 これは、manページのBUGSの章に書かれています。

カーネルのプロファイリングとユーザープログラムのプロファイリングは、 よく似ています; プロファイリングデータを処理する方法と、 コントロールする方法が若干違う程度です。

カーネルプロファイリングに関係するデータは、 グローバル構造体の _gmonparam 内にあります。 この構造体は、( kern/subr_prof.c 中の) kmstartup() により、 システムが初期化する際に初期化されます。 ユーザーレベルのコントロールプログラムである kgmon(8) は、 コントロールとデータアクセスのために sysctl(3) を呼び出し、 一部 kvm(3) アクセスを呼び出しています (動作しているカーネルがプロファイルされる標準的な場合もです!) 。

呼び出しグラフの記録 (トップ)

プロファイリングのフラグ (-pg) により、 コンパイラーは関数のエントリーごとに mcount() を呼び出します。 これは、マシン独自の橋渡しによって、 _mcount(frompc,selfpc) へ送られます。 _mcount(frompc,selfpc)sys/lib/libkern/mcount.c で実装されます。 frompc は関数を呼び出すアドレスで、 selfpc は呼ばれる関数自体のアドレスです。

プロファイル中に遭遇する全ての (frompc, selfpc) 用に、 struct tostruct_gmonparam.tos が示す配列から割り当てられます。 エントリーは最初に使用する順番で、 始めから終わりまで単純に割り当てられます。 kmstartup() 内のあるマジックによって、 カーネルのテキストサイズから配列のサイズが決められます -- 一種の"経験則" のようです。

struct tostruct のエントリーは、ヒストグラムカウンターと一緒に、呼ばれた関数 (selfpc) のアドレスを持っています。 同じ呼び出しアドレスにあるエントリーは、リンクした一覧を形成します。 一覧のヘッド (つまり、特定の呼び出しアドレスに属する _gmonparam.tos 配列内の最初のエントリーの見出し) は、 _gmonparam.froms という二つ目のデータ配列にあります。この _gmonparam.froms は、 ある値によって分割された呼び出しアドレス (frompc) により、見出しを付けられます (ある値は、コード内の二つの呼び出しの最短距離 より長くなることはありません - sys/sys/gmon.h にあるコメントを見てください) 。

標準的な関数呼び出しには、それぞれの frompc に対して selfpc がひとつしかないことに注意してください。 その結果、典型的な一覧が一つのメンバーのみで構成されるようになります。

統計的なプロファイリング (トップ)

プロファイリングが始まると、プロファイリングタイマーの割り込みが セットされ、 statclock() を呼び出します ( sys/kern/kern_clock.c を参照してください) 。 プロファイリングタイマーは、関数への干渉がシステムのクロックと 同期して動かなくならないように、通常のシステムクロックから独立した タイマーであるべきです。 statclock() はユーザープログラムでも、 カーネルプロファイリングでも使われます。

ある値で再分割されていれば、 割り込み時にプログラムカウンターは見出しとして使われて、 ヒストグラムの _gmonparam.kcount に記録され、該当するセルの値が増えます。

使い方 (トップ)

  • プロファイリングカーネルを構築し、ブートします。 これには、 -p フラグを用いて config(8) します。 用いなければ、特別なことはありません。プロファイリングカーネルは 以下のようなメッセージを自動設定後、ルートファイルシステムが マウントされる前に出力します。
    Profiling kernel, textsize=1611256 [f0100000..f02895f8]
  • /netbsd が現在動作しているカーネルであるか 確認してください。もし違えば、下の kgmon(8) の呼び出しで、 -N オプションを使ってください。
  • kgmon -b でプロファイリングを開始します。
  • いくつかアプリケーションを起動して、システムの中でも調べたい部分に 負担をかけます。
  • kgmon -h でプロファイリングを止めます。
  • kgmon -p を起動して、収集したデータを gmon.out というファイルに書き込みます。
  • 他のものを計測する前に、 kgmon -r でカーネル内のプロファイリングデータのバッファーをリセットします。
  • gmon.out から人間が判読できる解釈を入手するため、 以下のコマンドを実行します。
    % gprof /netbsd gmon.out > gprof.txt
  • データの解釈をします。

Back to NetBSD ドキュメンテーション: カーネル