|
linux
での代表的なプロファイル測定の実装を解説します。
関連して、マルチスレッドプログラムのプロファイル測定の注意点を述べます。
なお、gprof、oprofile
の基本的な使い方は既知のものとし、本書では特に解説はいたしません。
|
|
|
|
測定ツールとその実装 - gprof |
|
|
|
linux では gprof は glibc
に付属するツールです。ここでは glibc-2.3.6
を使って説明します。
gprof によるプロファイル測定を行うには、 -pg
コンパイルオプションをつけてプログラムをコンパイルします。
このことにより、プログラムに以下の処理が追加されます。
|
|
|
|
各関数の先頭からの mcount 関数の呼出し |
|
-pg
オプションをつけてコンパイルすると、関数の先頭から
mcount への呼出しが行われます。
例えば i386
アーキテクチャでは以下のようになります。
|
|
$ cat a.c
int
f(int a) {
return a;
}
$ cc -pg -S a.c
$ cat a.s
.file "a.c"
.text
.globl f
.type f, @function
f:
pushl %ebp
movl %esp, %ebp
call mcount
movl 8(%ebp), %eax
popl %ebp
ret
.size f, .-f
.section .note.GNU-stack,"",@progbits
.ident "GCC: (GNU) 3.3.5 (Debian 1:3.3.5-13)" |
|
|
|
mcount の実体は glibc-2.3.6/gmon/mcount.c
にあります。
|
|
_MCOUNT_DECL(frompc,
selfpc) /* _mcount; may
be static, inline, etc
*/
{ |
|
|
|
ここで、_MCOUNT_DECL
となっているのは、この関数には呼出し元とその親のプログラムカウンタ(それぞれ
selfpc、frompc)が渡される必要があり、アーキテクチャ依存のコードが必要になるため、アーキテクチャ毎の違いを吸収するためにマクロになっています。
この関数は、frompc と selfpc
の組に対応するカウンタをインクリメントするので、各関数が何回、どこから呼ばれたかがわかります。
|
|
プログラム起動時の setitimer() の実行 |
|
プログラム起動時に
|
|
__monstartup ((u_long)
TEXT_START, (u_long) &etext); |
|
|
|
が実行されます。
__monstartup
は gmon/gmon.c
にあり、プロファイル測定用テーブルの初期化を行い、
|
|
__profil((void *)
p->kcount,
p->kcountsize, p->lowpc,
s_scale); |
|
|
|
によって、一定実行時間毎にプログラムカウンタの位置に対応するカウンタがインクリメントされるようになります。
profil
は BSD 系 UNIX などではシステムコールですが、linux
ではタイマ割り込みとシグナルハンドラを用いて実装されています。
__profil
の定義は sysdeps/posix/profil.c
にあり、
__setitimer(ITIMER_PROF,
...) を実行し、一定 CPU 実行時間毎に
SIGPROF
シグナルが発生するようになります。linux-2.6.11
以前では、この setitimer
はスレッド毎なので、マルチスレッドプログラムでは、 gmon-helper.o(※1)などを使用して、スレッド毎に
setitimer を実行する必要があります。
|
|
プログラム終了時の gmon.out の書き出し |
|
|
|
が実行され、プロセス終了時に _mcleanup
から呼ばれる write_gmon
関数から上記のカウンタの値がファイルに書き出されます。
デフォルトの出力ファイル名は gmon.out
ですが、環境変数 GMON_OUT_PREFIX
で変更することができます。
_mcleanup は atexit
を利用して呼ばれるので、プロセスの異常終了時には
gmon.out は生成されません。
|
|
|
上記の3つの処理によって、以下の情報を取得することができます。
|
|
|
|
|
|
|
|
次へ
 |