オルタナティブ・ブログ > プログラマー社長のブログ >

プログラミングでメシが食えるか!?

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には他にもプログラムを指定して測定したり、カーネルは除いて測定したり、結果を保存しておくなど、オプションがいろいろありますので、興味がある方は調べてみてください。

自分のプログラムが遅いのか、そもそもデバイスやカーネルが遅いのかなどを見分けるには、とても便利ですね!

Comment(0)