
第7号(2007年4月)
Red Hat Enterprise Linux 5
(Part2:SystemTapによるライブカーネルプローブ)
SystemTapによるライブカーネルプローブ
RHEL4 Update2からテクノロジープレビューとして同梱されるようになったSystemTapを皆さんはご存じでしょうか。SolarisのDTrace に対するLinuxコミュニティからの「回答」として2005年1月から始まったこのオープンソースのプロジェクトは、Red Hat、Intel、IBMが主体となって開発が進行しています。
SystemTapの機能を一言で表すと「実行中のシステムをより深く探査するツール」です。RHEL5ではサポートの提供される開発用ツールとして同 梱されるようになり、いよいよ本格的に利用できる素地が整ってきました。今回は少しディープな話題となりますが、このSystemTapをご紹介したい と思います。
SystemTapを利用するにはいくつか前提条件があります。まず、systemtapのRPMパッケージそのものがインストールされている必要があ ります。また、このRPMパッケージが依存する、主に「開発」パッケージグループに属するいくつかのRPMパッケージも必要となります。プロダクション システムでは「開発」パッケージグループをインストールしていないことが多いと思いますので、
# yum install systemtap
とすることでSystemTapの実行に必要な最小限のパッケージが自動的にインストールされます。
もう一つ必須となるのは、プローブの対象となるカーネルのdebuginfoパッケージです。例えば、RHEL5の本原稿執筆時点での最新カーネルは、
kernel-2.6.18-8.1.1.el5.i686.rpm
ですので、このカーネルをプローブ対象とするには、
kernel-debuginfo-2.6.18-8.1.1.el5.i686.rpmと
kernel-debuginfo-common-2.6.18-8.1.1.el5.i686.rpmの2つのRPMパッケージが必要です。
入手方法は、
ftp://ftp.redhat.com/pub/redhat/linux/enterprise/5Server/en/os/i386/ Debuginfo/
からダウンロードするか、SRPM(ソースRPM)を入手してrpmbuildコマンドでRPMパッケージを作成するかのいずれかになります。
準備が整ったところで早速実行といきたいところですが、SystemTapがどのように動作するのか、プローブを停止するにはどうしたら良いのかを先に 確認しておきましょう。
まず、エディタを用いてprobeスクリプトを記述します。このスクリプトはawkによく似たSystemTap固有の文法で記述する必要があります が、ステートメントや条件式などはC言語ライクなので「習得」というほどの手間はかからないと思います。詳細な文法の説明は
# man stap
を参照してください。
記述したスクリプトをstapコマンドの引数として渡すと、最初にスクリプトが文法的に間違いが無いか、あるいはセキュリティやシステムへの負荷といっ た観点から問題が無いかといったことが評価されます。例えば、無限ループに陥る条件式が無いかといったことです。次にprobe-setライブラリから スクリプトの実行に必要な関数等がマージされた後、C言語のソースに変換され、カーネルのモジュールとしてコンパイルされます。コンパイルに問題が無け れば、そのままカーネルにモジュールがロードされプローブが開始されます。
実行終了時にまとめてモジュールからの出力を参照することも可能ですが、SystemTapは「ライブ」カーネルプローブですので、通常はプローブで得 られたデータをリアルタイムで出力させる状況の方が多いでしょう。最後にユーザが[Ctrl]+[c]をキーボードからタイプするとモジュールがカーネ ルからアンロードされ、プローブが終了します。
この一連のフローは、各ステップを個別に実行させることも可能です。
いきなりこのスクリプトを書くのは難しいと思いますので、以下のサンプルを見てください。
SystemTapのサンプルは
/usr/share/doc/systemtap-version/examples/small_demos/
にありますので、この中からtop.stpを例に挙げます。
#!/usr/bin/env stap
#
# This script continuously lists the top 20 systemcalls on
the system
#
global syscalls
function print_top () {
cnt=0
printf ("SYSCALL\t\t\t\tCOUNT\n")
foreach ([name] in syscalls-) {
printf("%-20s\t\t%5d\n",name, syscalls[name])
if (cnt++ == 20)
break
}
printf("--------------------------------------\n")
delete syscalls
}
probe kernel.function("sys_*") {
syscalls[probefunc()]++
}
# print top syscalls every 5 seconds
probe timer.ms(5000) {
print_top ()
}
スクリプトにはprobeとfunctionという2種類のコンストラクタが必要です。
top.stpには、2つのprobeコンストラクタが含まれ、1つはプローブ中に呼ばれるカーネルAPIのうち、"sys_"で始まるAPIだけを フックして、大域変数であるsyscallsを呼び出されたAPIの名称をキー(ハッシュ)としてインクリメントします。もう1つのprobeは5秒ご とにprint_top()という関数を呼び出しています。print_top()関数は標準出力にsyscallsの上位20要素だけを出力し、 syscallsをクリアします。
では実行してみます。
[root@localhost ~]# stap /usr/share/doc/systemtap-0.5.12/examples/small_demos/top.stp
SYSCALL COUNT
sys_futex 1013
sys_gettimeofday 770
sys_poll 402
sys_ioctl 318
sys_read 178
sys_select 124
sys_setitimer 54
sys_write 38
sys_sigreturn 33
sys_inotify_add_watch 28
sys_time 26
sys_writev 25
sys_clock_gettime 20
sys_stat64 7
sys_rt_sigprocmask 6
sys_rt_sigaction 6
sys_open 3
sys_close 3
sys_nanosleep 3
sys_alarm 1
sys_fstat64 1
--------------------------------------
SYSCALL COUNT
sys_futex 1014
sys_gettimeofday 793
sys_poll 404
sys_ioctl 319
sys_read 181
sys_select 128
sys_write 64
sys_setitimer 52
sys_sigreturn 33
sys_time 28
sys_writev 25
sys_clock_gettime 20
sys_inotify_add_watch 17
sys_rt_sigprocmask 8
sys_stat64 7
sys_lstat64 5
sys_rt_sigaction 5
sys_fstat64 2
sys_kill 2
sys_alarm 2
sys_open 2
--------------------------------------
....... [Ctrl]+[C]でブレーク。
このように動作中のカーネルの様子が「ライブ」で観察出来ることは、得てして「何が起きているか分からない」状況を分析するのに非常に役に立つ機能では ないかと思います。是非SystemTapを利用して、パフォーマンスの問題などの実際に起こりうるシステムトラブルの解決に役立ててください。
お問い合わせメールアドレス:
sales-jp@redhat.com
レッドハット株式会社/ニュースレター編集部