目次
openSUSE では、お使いのシステムに関する便利な情報を採取するための 様々なツールが提供されています。採取可能な情報としては、たとえばお使いの プログラムにおけるデバッグや問題発見のための情報や、性能を落としている 原因を発見するための情報、もしくは実行中のプロセスに対して使用している システム資源を追跡するための情報などがあります。これらのツールは主に インストールメディア内に含まれていますが、 SUSE ソフトウエア開発キット からインストールするもの もあります。
トレースと性能への影響 | |
---|---|
プロセスに対してシステムやライブラリ呼び出しのトレース (追跡) を行なった 場合、そのプロセスの性能は大きく落ちます。そのため、トレース関連のツールは データの収集を行なうときにだけご利用ください。 |
strace コマンドは、プロセスが利用するシステムコールや 受信するシグナルについて、それらを追跡するためのプログラムです。 strace はコマンドを新たに起動してシステムコールを追跡 させることができるほか、既に動作しているコマンドに対して strace を設定することもできます。このコマンドの出力には、 システムコールの名称のほか、そこで指定したパラメータ (括弧内) や戻り値など が含まれています。
新しいコマンドを起動してシステムコールの追跡を行なうには、コマンドラインの 冒頭に strace と入力してから、あとは通常通りのコマンド ラインを入力します:
tux@mercury:~> strace ls execve("/bin/ls", ["ls"], [/* 52 vars */]) = 0 brk(0) = 0x618000 mmap(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) \ = 0x7f9848667000 mmap(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) \ = 0x7f9848666000 access("/etc/ld.so.preload", R_OK) = -1 ENOENT \ (No such file or directory) open("/etc/ld.so.cache", O_RDONLY) = 3 fstat(3, {st_mode=S_IFREG|0644, st_size=200411, ...}) = 0 mmap(NULL, 200411, PROT_READ, MAP_PRIVATE, 3, 0) = 0x7f9848635000 close(3) = 0 open("/lib64/librt.so.1", O_RDONLY) = 3 [...] mmap(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) \ = 0x7fd780f79000 write(1, "Desktop\nDocuments\nbin\ninst-sys\n", 31Desktop Documents bin inst-sys ) = 31 close(1) = 0 munmap(0x7fd780f79000, 4096) = 0 close(2) = 0 exit_group(0) = ?
既に起動済みのプロセスに対して strace を設定するには、
-p
オプションを利用して監視したいプロセスのプロセス
ID (PID
) を指定する必要があります:
tux@mercury:~> strace -p `pidof mysqld` Process 2868 attached - interrupt to quit select(15, [13 14], NULL, NULL, NULL) = 1 (in [14]) fcntl(14, F_SETFL, O_RDWR|O_NONBLOCK) = 0 accept(14, {sa_family=AF_FILE, NULL}, [2]) = 31 fcntl(14, F_SETFL, O_RDWR) = 0 getsockname(31, {sa_family=AF_FILE, path="/var/run/mysql"}, [28]) = 0 fcntl(31, F_SETFL, O_RDONLY) = 0 fcntl(31, F_GETFL) = 0x2 (flags O_RDWR) fcntl(31, F_SETFL, O_RDWR|O_NONBLOCK) = 0 [...] setsockopt(31, SOL_IP, IP_TOS, [8], 4) = -1 EOPNOTSUPP (Operation \ not supported) clone(child_stack=0x7fd1864801f0, flags=CLONE_VM|CLONE_FS|CLONE_ \ FILES|CLONE_SIGHAND|CLONE_THREAD|CLONE_SYSVSEM|CLONE_SETTLS|CLONE_ \ PARENT_SETTID|CLONE_CHILD_CLEARTID, parent_tidptr=0x7fd1864809e0, \ tls=0x7fd186480910, child_tidptr=0x7fd1864809e0) = 21993 select(15, [13 14], NULL, NULL, NULL
-e
オプションでは複数のサブオプションやパラメータを
指定することができます。たとえばファイルを開く処理や書き込む処理だけ
を追跡するには、下記のように実行します:
tux@mercury:~> strace -e trace=open,write ls ~ open("/etc/ld.so.cache", O_RDONLY) = 3 open("/lib64/librt.so.1", O_RDONLY) = 3 open("/lib64/libselinux.so.1", O_RDONLY) = 3 open("/lib64/libacl.so.1", O_RDONLY) = 3 open("/lib64/libc.so.6", O_RDONLY) = 3 open("/lib64/libpthread.so.0", O_RDONLY) = 3 [...] open("/usr/lib/locale/cs_CZ.utf8/LC_CTYPE", O_RDONLY) = 3 open(".", O_RDONLY|O_NONBLOCK|O_DIRECTORY|O_CLOEXEC) = 3 write(1, "addressbook.db.bak\nbin\ncxoffice\n"..., 311) = 311
ネットワーク関連のシステムコールだけを追跡するには、 -e
trace=network
と指定します:
tux@mercury:~> strace -e trace=network -p 26520 Process 26520 attached - interrupt to quit socket(PF_NETLINK, SOCK_RAW, 0) = 50 bind(50, {sa_family=AF_NETLINK, pid=0, groups=00000000}, 12) = 0 getsockname(50, {sa_family=AF_NETLINK, pid=26520, groups=00000000}, \ [12]) = 0 sendto(50, "\24\0\0\0\26\0\1\3~p\315K\0\0\0\0\0\0\0\0", 20, 0, {sa_family=AF_NETLINK, pid=0, groups=00000000}, 12) = 20 [...]
-c
オプションを指定すると、それぞれのシステムコールに
費やした時間が計算されるようになります:
tux@mercury:~> strace -c find /etc -name xorg.conf /etc/X11/xorg.conf % time seconds usecs/call calls errors syscall ------ ----------- ----------- --------- --------- ---------------- 32.38 0.000181 181 1 execve 22.00 0.000123 0 576 getdents64 19.50 0.000109 0 917 31 open 19.14 0.000107 0 888 close 4.11 0.000023 2 10 mprotect 0.00 0.000000 0 1 write [...] 0.00 0.000000 0 1 getrlimit 0.00 0.000000 0 1 arch_prctl 0.00 0.000000 0 3 1 futex 0.00 0.000000 0 1 set_tid_address 0.00 0.000000 0 4 fadvise64 0.00 0.000000 0 1 set_robust_list ------ ----------- ----------- --------- --------- ---------------- 100.00 0.000559 3633 33 total
特定のプロセスに対して、それらの子プロセスもあわせて監視するように
するには、 -f
を指定します:
tux@mercury:~> strace -f rcapache2 status execve("/usr/sbin/rcapache2", ["rcapache2", "status"], [/* 81 vars */]) = 0 brk(0) = 0x69e000 mmap(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) \ = 0x7f3bb553b000 mmap(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) \ = 0x7f3bb553a000 [...] [pid 4823] rt_sigprocmask(SIG_SETMASK, [], <unfinished ...> [pid 4822] close(4 <unfinished ...> [pid 4823] <... rt_sigprocmask resumed> NULL, 8) = 0 [pid 4822] <... close resumed> ) = 0 [...] [pid 4825] mprotect(0x7fc42cbbd000, 16384, PROT_READ) = 0 [pid 4825] mprotect(0x60a000, 4096, PROT_READ) = 0 [pid 4825] mprotect(0x7fc42cde4000, 4096, PROT_READ) = 0 [pid 4825] munmap(0x7fc42cda2000, 261953) = 0 [...] [pid 4830] munmap(0x7fb1fff10000, 261953) = 0 [pid 4830] rt_sigprocmask(SIG_BLOCK, NULL, [], 8) = 0 [pid 4830] open("/dev/tty", O_RDWR|O_NONBLOCK) = 3 [pid 4830] close(3) [...] read(255, "\n\n# Inform the caller not only v"..., 8192) = 73 rt_sigprocmask(SIG_BLOCK, NULL, [], 8) = 0 rt_sigprocmask(SIG_BLOCK, NULL, [], 8) = 0 exit_group(0)
strace の出力を分析する必要がある場合や、出力される
メッセージが長すぎるため、コンソールで直接確認するのが困難である場合は、
-o
オプションをお使いください。この場合は、プロセスへの
接続や接続解除のメッセージなど、不要な情報は省略されます。これらの
メッセージ (通常は標準出力に出力されます) を省略するには、
-q
を指定します。また、各行に対してタイムスタンプを
表示したい場合は、 -t
を使用します:
tux@mercury:~> strace -t -o strace_sleep.txt sleep 1; more strace_sleep.txt 08:44:06 execve("/bin/sleep", ["sleep", "1"], [/* 81 vars */]) = 0 08:44:06 brk(0) = 0x606000 08:44:06 mmap(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, \ -1, 0) = 0x7f8e78cc5000 [...] 08:44:06 close(3) = 0 08:44:06 nanosleep({1, 0}, NULL) = 0 08:44:07 close(1) = 0 08:44:07 close(2) = 0 08:44:07 exit_group(0) = ?
strace の動作と出力形式は幅広い範囲でカスタマイズが可能です。詳しくは 関連するマニュアルページ (man 1 strace) をお読みください。
ltrace はプロセスに対する動的なライブラリ呼び出しを
追跡します。 strace に似た方法を使用するもので、
パラメータの多くも似通っていたり、全く同じ意味であったりします。既定では
ltrace は /etc/ltrace.conf
または
~/.ltrace.conf
にある設定ファイルを使用します。
-F
を使用する
ことで、独自の設定ファイルを指定することもできます。
設定ファイル
ライブラリの呼び出しに加えて、 ltrace では
-S
オプションでシステムコールを同時に追跡することもできます:
tux@mercury:~> ltrace -S -o ltrace_find.txt find /etc -name \ xorg.conf; more ltrace_find.txt SYS_brk(NULL) = 0x00628000 SYS_mmap(0, 4096, 3, 34, 0xffffffff) = 0x7f1327ea1000 SYS_mmap(0, 4096, 3, 34, 0xffffffff) = 0x7f1327ea0000 [...] fnmatch("xorg.conf", "xorg.conf", 0) = 0 free(0x0062db80) = <void> __errno_location() = 0x7f1327e5d698 __ctype_get_mb_cur_max(0x7fff25227af0, 8192, 0x62e020, -1, 0) = 6 __ctype_get_mb_cur_max(0x7fff25227af0, 18, 0x7f1327e5d6f0, 0x7fff25227af0, 0x62e031) = 6 __fprintf_chk(0x7f1327821780, 1, 0x420cf7, 0x7fff25227af0, 0x62e031 <unfinished ...> SYS_fstat(1, 0x7fff25227230) = 0 SYS_mmap(0, 4096, 3, 34, 0xffffffff) = 0x7f1327e72000 SYS_write(1, "/etc/X11/xorg.conf\n", 19) = 19 [...]
-e
オプションを利用することで、追跡するイベントの種類を
変更することができます。下記の例では、 fnmatch
と
strlen
の関数に関連したライブラリ呼び出しについて
表示を行なっています:
tux@mercury:~> ltrace -e fnmatch,strlen find /etc -name xorg.conf [...] fnmatch("xorg.conf", "xorg.conf", 0) = 0 strlen("Xresources") = 10 strlen("Xresources") = 10 strlen("Xresources") = 10 fnmatch("xorg.conf", "Xresources", 0) = 1 strlen("xorg.conf.install") = 17 [...]
特定のライブラリに含まれるシンボルだけを表示するには、
-l
を
使用します:
ライブラリへのパス
tux@mercury:~> ltrace -l /lib64/librt.so.1 sleep 1 clock_gettime(1, 0x7fff4b5c34d0, 0, 0, 0) = 0 clock_gettime(1, 0x7fff4b5c34c0, 0xffffffffff600180, -1, 0) = 0 +++ exited (status 0) +++
-n
を指定することで、
それぞれ再帰的に呼び出されているライブラリ呼び出しについて、それらを
インデント表示させることができます。これによって、出力を読みやすく
することができます。
空白数
Valgrind はお買いのプログラムに対してデバッグやプロファイル機能を提供 するツール集で、高速にエラーもなく動作できる仕組みです。 Valgrind は メモリ管理やスレッド処理に関する問題を検出することができるほか、新しい デバッグツールを構築する際のフレームワークとしても利用することができます。
Valgrind は標準の openSUSE 配布物には含まれていません。お使いの システムにインストールするには SUSE ソフトウエア開発キット を取得し、アドオン製品として追加した あと、
zypper install
を実行します。
valgrind
それ以外にも、 SUSE ソフトウエア開発キット のディレクトリツリーを参照して Valgrind パッケージの 場所を見つけ、
rpm -i
valgrind-バージョン/アーキテクチャ
.rpm
のように実行してもかまいません。
Valgrind を使用する主な目的は、既存のコンパイル済み実行ファイルを利用 して調査するという点にあります。 Valgrind を使用するにあたってコンパイル し直したり、プログラムを修正したりする必要はありません。 Valgrind は 下記のようにして実行します:
valgrind Valgrind のオプション
プログラム
プログラムのオプション
Valgrind は複数のツールから構成されていて、それぞれのツールは固有の機能が
用意されています。また、この章における情報は、使用するツールに関係なく一般的に
利用可能なものだけを紹介しています。その中でも最も重要な設定オプションは
--tool
で、このオプションは Valgrind に対して実行する
ツールを指定するためのものです。このオプションを省略すると、既定で
memcheck
が選択されます。たとえば Valgrind の
memcheck
ツールを find ~
-name
.bashrc というコマンドラインに対して
実行したい場合は、下記のように入力します:
valgrind
--tool
=memcheck
find ~ -name
.bashrc
また、下記には標準的な Valgrind ツールと、それについての簡単な説明を示します:
memcheck
メモリエラーの検出を行ないます。お使いのプログラムが正しく動作するか どうかを確かめることができます。
cachegrind
キャッシュの予測をプロファイルします。お使いのプログラムが高速に 動作するかどうかを確かめることができます。
callgrind
cachegrind
に似た動作を行ないますが、
キャッシュプロファイル情報を追加で収集します。
exp-drd
スレッドエラーを検出します。複数のスレッドが動作するプログラムについて、 正しく動作するかどうかを確かめることができます。
helgrind
もう 1 つのスレッドエラー検出器です。 exp-drd
に似た機能ですが、問題の分析時に異なる技術を使用します。
massif
ヒープのプロファイルを行ないます。ヒープとは動的に割り当てられるタイプの メモリ領域のことで、これによってお使いのプログラムをより少ないメモリで 動作できるように、チューニングすることができます。
lackey
基本的な仕組みを理解するためのサンプルツールです。
Valgrind は起動時にオプションを読み込みます。オプションは下記の 3 種類の 場所で指定できます:
Valgrind を実行するユーザのホームディレクトリ内にある
.valgrindrc
ファイル。
環境変数 $VALGRIND_OPTS
。
Valgrind を起動した時点でのカレントディレクトリにある
.valgrindrc
ファイル。
これらのパラメータは上記の順序で処理され、後者での設定は前者での設定を
上書きすることができるようになっています。特定の Valgrind に対する固有の
オプションは、ツール名に続けてコロン (:) を追加し、その後にオプション名を
続けます。たとえば cachegrind
に対して、
プロファイルデータを必ず
/tmp/cachegrind_
ファイルに書き込ませたい場合は、ホームディレクトリ内の
PID
.log.valgrindrc
ファイルで、下記のように設定します:
--cachegrind:cachegrind-out-file=/tmp/cachegrind_%p.log
Valgrind は、対象のプログラムが起動する前の段階から制御を獲得するように なっています。まずは実行ファイルからデバッグ情報を読み込み、関連する共有 ライブラリを読み込みます。実行ファイル内のコードは選択した Valgrind ツールに転送され、ツールはデバッグを行なうためのコードを追加します。 最後にコードは Valgrind の中枢部分に戻され、実行が開始されます。
たとえば memcheck
では、それぞれのメモリアクセス
に対してチェックを行なうコードを追加します。これにより、ネイティブな実行
環境に比べるとずっと遅い動作になってしまいます。
Valgrind では、プログラム内の各命令をシミュレートします。そのため、
プログラムのコードをチェックするだけではなく、関連するライブラリ (C
ライブラリを含む) やグラフィカル環境のライブラリなどについてもチェックを
行なうことができます。つまり、 Valgrind でエラーを検出する場合は、関連する
ライブラリ (C, X11, Gtk ライブラリなど) に関するエラーもチェックすることに
なります。これらのエラーが不要な場合は、 Valgrind 側に設定を行なうことで
出力を省略することができます。 --gen-suppressions=yes
を指定すると、これら省略したものをレポートさせることができます。
なお Valgrind を実行する際は、実際の実行ファイル (マシンコード) に対して
実行してください。たとえばシェルや Perl スクリプトからアプリケーションを
起動すると、 /bin/sh や /usr/bin/perl
を調査することになってしまい、誤った結果をもたらしてしまいます。このような
場合は --trace-children=
を
指定するか、もしくはシェルやスクリプトではなく、実行ファイルを指定して実行
してください。
yes
Valgrind の実行中には、詳細なエラー内容や重要なイベントを含むメッセージが 随時表示されます。たとえば下記のようになります:
tux@mercury:~> valgrind --tool=memcheck find ~ -name .bashrc [...] ==6558== Conditional jump or move depends on uninitialised value(s) ==6558== at 0x400AE79: _dl_relocate_object (in /lib64/ld-2.11.1.so) ==6558== by 0x4003868: dl_main (in /lib64/ld-2.11.1.so) [...] ==6558== Conditional jump or move depends on uninitialised value(s) ==6558== at 0x400AE82: _dl_relocate_object (in /lib64/ld-2.11.1.so) ==6558== by 0x4003868: dl_main (in /lib64/ld-2.11.1.so) [...] ==6558== ERROR SUMMARY: 2 errors from 2 contexts (suppressed: 0 from 0) ==6558== malloc/free: in use at exit: 2,228 bytes in 8 blocks. ==6558== malloc/free: 235 allocs, 227 frees, 489,675 bytes allocated. ==6558== For counts of detected errors, rerun with: -v ==6558== searching for pointers to 8 not-freed blocks. ==6558== checked 122,584 bytes. ==6558== ==6558== LEAK SUMMARY: ==6558== definitely lost: 0 bytes in 0 blocks. ==6558== possibly lost: 0 bytes in 0 blocks. ==6558== still reachable: 2,228 bytes in 8 blocks. ==6558== suppressed: 0 bytes in 0 blocks. ==6558== Rerun with --leak-check=full to see details of leaked memory.
==6558==
として表示されている数値はプロセスの ID
番号 (PID) で、それに続けて Valgrind からのメッセージが表示されます。
これによりプログラム自体からの出力と Valgrind からの出力を区別すること
ができるほか、どのプロセスに属するメッセージなのかがわかるようになって
います。
Valgrind のメッセージをより詳細に表示したい場合は、 -v
や -v -v
の各オプションを使用します。
基本的には Valgrind は自分自身のメッセージを 3 箇所に出力することが できます:
既定では Valgrind は自分自身のメッセージをファイルディスクリプタ 2 に
送信します。これは一般的には標準エラー出力 (stderr) と呼ばれているもので、
独自のファイルディスクリプタに送信させたい場合は、
--log-fd=
オプションを使用します。
ファイルディスクリプタ番号
2 番目の出力先としては、
--log-file=
で指定するファイル出力があります。なお、このオプションではいくつかの変数を
使用することができます。たとえば ファイル名
%p
は、現在プロファイル
されているプロセスのプロセス ID (PID) に置き換えることができます。この
方式を使用すると、プロセス ID ごとに異なるファイルに出力させることが
できます。また %q{env_var}
では、
env_var
の名前を持つ環境変数について、設定されて
いる値に置き換えることができます。
下記の例では、 Apache Web サーバが再起動する際にメモリエラーが存在して いないかどうかをチェックしています。このとき、子プロセスについてもチェック を行なうものとし、詳細な Valgrind からのメッセージはそれぞれ現在の プロセス ID で示されるファイルに出力しています:
tux@mercury:~> valgrind -v --tool=memcheck --trace-children=yes \ --log-file=valgrind_pid_%p.log rcapache2 restart
このプロセスはテストシステム内に 52 個のログファイルを作成し、 Valgrind を使用しない場合は通常 7 秒程度かかる rcapache2 restart コマンドが 10 倍の 75 秒程度かかる環境であるものとします。すると、下記のような 状況になります。
tux@mercury:~> ls -1 valgrind_pid_*log valgrind_pid_11780.log valgrind_pid_11782.log valgrind_pid_11783.log [...] valgrind_pid_11860.log valgrind_pid_11862.log valgrind_pid_11863.log
Valgrind のメッセージをネットワーク経由で送信したい場合は、それぞれ
aa.bb.cc.dd
の形式で IP アドレスを、 番号
の形式でポート番号を用意し、
--log-socket=
のようにして実行します。ポート番号を省略した場合は、 1500 が使用されます。
aa.bb.cc.dd:port_num
なお、送信先のマシン側には Valgrind のメッセージを受信するため、 アプリケーションを起動する必要があります。このアプリケーションとしては、 Valgrind 同梱の valgrind-listener を利用するのが よいでしょう。これは指定したポートで接続を待ち受けて、受信した メッセージを標準出力に出力します。
Valgrind はすべてのエラーメッセージを記憶し、新しいエラーを検出すると 古いエラーメッセージとの比較が行なわれます。この方法により、 Valgrind は エラーメッセージの重複をチェックしています。重複したエラーであることが 判明した場合、それは記憶されるだけで表示はされません。これにより、数多く のエラーメッセージが表示されることによる混乱を防ぐようになっています。
なお、 -v
オプションを指定することで、 Valgrind の実行時
出力の最後に全レポートの概要 (発生回数順) を表示させることができます。
ただし、 Valgrind は 1,000 種類以上の異なるエラーを検出した場合や、全部で
10,000,000 回以上のエラーを検出した場合は、エラー収集を停止してしまうこと
に注意してください。この制限を取り払ってすべてのエラーメッセージを表示
させたい場合は、 --error-limit=no
を指定してください。
また、あるエラーが別のエラーを呼び起こす場合もあります。このような場合は、 発生した順序どおりに問題を修正し、プログラムを再度チェックすることを お勧めします。
上記のトレースツールに関連したオプションについて、完全な一覧を読みたい 場合は、それぞれのマニュアルページ (man 1 strace, man 1 ltrace, man 1 valgrind) をお読みください。
Valgrind のより高度な使用方法に関する説明は、 Valgrind User Manual (英語) をお読みください。これらのページは Valgrind を高度な機能を使用したり、標準ツールの使用方法や目的を 調べたりしたい場合には欠くことのできないものです。