Linux:カーネルまで含めたプロファイルの取り方
UNIX系OSでプログラミングをしていて、性能面で悩んだときには、gprofというプロファイラを使うと、簡単にプログラム中の関数呼び出し回数や関数実行時間などを測定することができます。gccのオプションに-pgをつければ良いだけということでとても簡単で便利です。
ところが、gprofで測定できるのは、あくまでもプログラム自体の処理だけで、カーネルやドライバまで含めた測定はできません。
このところ、ネットワークプログラムの10Gイーサーでの性能向上をしているのですが、10Gクラスになるとプログラム自体の処理はもちろんですが、カーネル内の処理やデバイスドライバでの処理もかなり大きな影響がでてきます。特に、ネットワークでの通信は、ネットワークデバイスでの出入りは並列化できなかったり、パケットの順序を入れ替えられないことがほとんどなど、どれだけCPUが並列処理に強くなっても、ネットワーク関連の処理自体がボトルネックになってしまうことも多いのです。
いろいろ調べてみると、oprofileというものを使うと、カーネルまで含めたプロファイルが取れることが分かりました。簡単に使い方のポイントだけ紹介しましょう。
・カーネルでバッグ用のRPMを取得しインストール
CentOSならhttp://debuginfo.centos.org/から対象バージョンのkernel-debuginfo-common,kernel-debuginfoを取得。
rpm -ivh kernel-debuginfo-*.rpm
測定開始までの準備
opcontrol --init
opcontrol --start --vmlinux=/usr/lib/debug/lib/modules/[カーネルバージョン]/vmlinux
測定したい処理を実行
測定終了
opcontrol --stop
opcontrol --dump
レポート出力
opreport -l -p /lib/modules/2.6.32-220.el6.i686/kernel/
カウンターのリセット・終了
opcontrol --reset
opcontrol --shutdown
という感じです。
レポートはこんな感じに出力されます。
CPU: Intel Atom, speed 1600 MHz (estimated)
Counted CPU_CLK_UNHALTED events (Clock cycles when not halted) with a unit mask of 0x00 (core_p Core cycles when core is not halted) count 100000
samples % image name app name symbol name
203311 11.3525 vmlinux vmlinux read_hpet
124735 6.9650 e1000e.ko e1000e.ko e1000_clean
97403 5.4388 e1000e.ko e1000e.ko e1000_intr_msi
66204 3.6967 vmlinux vmlinux copy_from_user
53908 3.0101 vmlinux vmlinux memcpy
49449 2.7611 pf_ring.ko pf_ring.ko skb_ring_handler
36418 2.0335 e1000e.ko e1000e.ko e1000_clean_rx_irq
33838 1.8894 pf_ring.ko pf_ring.ko parse_raw_pkt
30666 1.7123 e1000e.ko e1000e.ko e1000_xmit_frame
23663 1.3213 vmlinux vmlinux kfree
22491 1.2559 pf_ring.ko pf_ring.ko ring_sendmsg
20894 1.1667 vmlinux vmlinux sysenter_past_esp
20597 1.1501 vmlinux vmlinux dev_hard_start_xmit
20333 1.1354 libpthread-2.12.so libpthread-2.12.so __pthread_disable_asynccancel
20174 1.1265 libpthread-2.12.so libpthread-2.12.so __pthread_enable_asynccancel
vmlinuxがカーネル本体で、*.koはドライバーですね。*.soは共有ライブラリーです。hpetという高精度イベントタイマーの読み出しを先頭に、e1000eというネットワークデバイスドライバー、ユーザランドからのコピーなどが続いています。実はこのずっと先の方を見ないと、対象のプログラムは登場しないのです。ということは、この処理ではプログラム自体を改良してもそれほど性能向上は望めず、ドライバーや、そもそもの処理全体を見直さないとダメ、という感じかもしれません。まあ、このサンプルは性能面で困っている部分でないところをあえて載せましたので、このままで性能も十分なのですが。。
oprofileには他にもプログラムを指定して測定したり、カーネルは除いて測定したり、結果を保存しておくなど、オプションがいろいろありますので、興味がある方は調べてみてください。
自分のプログラムが遅いのか、そもそもデバイスやカーネルが遅いのかなどを見分けるには、とても便利ですね!