実行中のシステムの挙動を詳細にトレースする仕組みは、特に
eBPFに関する記事が今回以降、
- 第688回 eBPFのコンパイラーに対応したツールでさまざまな挙動を可視化する
(今回の記事) - 第690回 BCCでeBPFのコードを書いてみる
- 第692回 sysfsやbpftoolを用いたeBPFの活用
- 第694回 libbpfとclangでポータブルなBPF CO-REバイナリ作成
- 第695回 入門BPF CO-RE
eBPFとBPF Compiler Collection
改めて言うまでもなく、
第584回の
それに対して、
気をつけなければいけないのは
- Ubuntu 14.
04 LTS (ESM):3. 13から4. 4 - Ubuntu 16.
04 LTS (ESM):4. 4から4. 15 - Ubuntu 18.
04 LTS:4. 15から5. 4 - Ubuntu 20.
04 LTS:5. 4から5. 13以降 - Ubuntu 21.
04:5. 11 - Ubuntu 21.
10:5. 13
ここで
4.
eBPFを使うツールはいろいろ存在しますが、
BCCのインストール方法
Ubuntuの場合、
apt版は普通にDebianパッケージとしてインストールする方法です。シンブルな方法ではあるものの、
- Ubuntu 18.
04 LTS: 0. 5.0 - Ubuntu 20.
04 LTS: 0. 12. 0 - Ubuntu 21.
04: 0. 18. 0 - Ubuntu 21.
10: 0. 18. 0
それに対してsnap版のBCCは、
特にBCCの場合は、
apt版のインストール
apt版のパッケージ名は
- 2021年11月1日訂正
- 記事公開時には
「コンパイラーであるbpfcが含まれる」 と記述していましたが、 bpfcはnetsniff-ngパッケージに含まれる、 Classic BPF向けのコンパイラーでした。大変失礼いたしました。
$ sudo apt instal bpfcc-tools
各種ツールにはすべて-bpfcc
」
ちなみにDebianの場合は、CONFIG_
」/sys/
からカーネルのヘッダーファイルを取得できないためです。
snap版のインストール
snap版のパッケージ名はそのまま
$ sudo snap install bcc --devmode
現状のbccパッケージは--devmode
」snap connect
」
各種ツールにはすべてbcc.
」snap alias bcc.
」snap unalias bcc.
」
Linuxカーネルのフレーバーに注意
BCCはeBPFだけでなくツールに応じてdebugfsやkprobesなどといった、
たとえばUbuntu Cloud Imagesから提供され、CONFIG_
が有効になっていないため、
$ sudo bcc.execsnoop create_probe_event: open(/sys/kernel/debug/tracing/kprobe_events): No such file or directory Traceback (most recent call last): File "/snap/bcc/159/usr/share/bcc/tools/execsnoop", line 229, in <module> b.attach_kprobe(event=execve_fnname, fn_name="syscall__execve") File "/snap/bcc/159/usr/lib/python3/dist-packages/bcc/__init__.py", line 834, in attach_kprobe (fn_name, event)) Exception: Failed to attach BPF program b'syscall__execve' to kprobe b'sys_execve'
よってKVMフレーバーを使っている環境でどうしてもBCCを使いたい場合は、
$ sudo apt install -y linux-generic $ sudo apt remove -y --purge '~nlinux-.*kvm ~i'
2行目でKVMフレーバーを削除しているのは、Ubuntu, with Linux 5.
」
なお、
ちなみに今のところ問題になりそうなのは、
BCCの便利なツールたち
現状のBCCには、
なお、
特定のイベントを監視するsnoop系ツール
特定のイベントが発生したときに順次記録していくツールは
その中でもexecsnoopやopensnoop、
たとえばexecsnoopは、exec()
システムコールの呼び出しを検知します。いわゆるpsコマンドは
コマンド自体は引数なしで起動するだけでも十分に使えます。-T
」-U
」-x
」exec()
が失敗した場合も記録してくれます。
$ sudo execsnoop-bpfcc -UTx TIME UID PCOMM PID PPID RET ARGS 01:07:55 1000 sh 2109659 4089 0 /bin/sh -c byobu-status tmux_left 01:07:55 1000 byobu-status 2109660 2109659 0 /usr/bin/byobu-status tmux_left 01:07:55 1000 sed 2109662 2109660 0 /usr/bin/sed --follow-symlinks s/// /dev/null 01:07:55 1000 sh 2109661 4089 0 /bin/sh -c byobu-status tmux_right
逆にプロセスの終了を検知したい場合はexitsnoopやkillsnoopが使えます。
もうひとつよく使う可能性があるのがopen()
システムコールを検知する、
$ sudo opensnoop-bpfcc -U -u 1000 UID PID COMM FD ERR PATH 1000 572612 chrome 179 0 /dev/shm/.com.google.Chrome.jX9pnM 1000 4089 tmux: server 19 0 /proc/2113318/cmdline 1000 3449 gnome-shell 91 0 /proc/self/stat 1000 3694 multipass.gui 20 0 /home/shibata/snap/multipass/5309/config/multipass/multipass.conf 1000 3694 multipass.gui 20 0 /home/shibata/snap/multipass/5309/config/multipass/multipass.conf
他にもbiosnoopやdcsnoopはブロックデバイスのI/
定期的に描画を更新するtop系ツール
snoopが発生したイベントをそのままシーケンシャルに表示し続けるのに対して、
- biotop:ブロックI/
Oのイベントを表示 - filetop:ファイルのI/
Oとそれを行うプロセスを表示 - dirtop:特定のディレクトリ以下のI/
Oを表示 - cachetop:ページキャッシュのヒット/
ミスなど統計情報を表示 - slabratetop:Kernelのメモリアロケーションの情報を表示
- netqtop:指定したNICのキューの情報を表示
- tcptop:プロセスごとのTCPの送受信のスループットを表示
期間中に取得した情報の統計を表示するdist系ツール
perfコマンドのように一定期間情報を取得し、
- argdist:指定した関数の呼び出しとその引数に応じたヒストグラムの表示
- cpudist:タスクごとにCPUがオンになった期間に応じたヒストグラムの表示
- ext4dist/
btrfsdist/ nfsdis/ xfsdist/ zfsdist:ファイルシステムのレイテンシーのヒストグラムの表示
たとえばkmalloc()
に渡されたサイズごとのヒストグラムは次のように表示します。これはargdist --help
」
$ sudo argdist-bpfcc -H 'p::__kmalloc(u64 size):u64:size' [02:08:08] size : count distribution 0 -> 1 : 0 | | 2 -> 3 : 0 | | 4 -> 7 : 0 | | 8 -> 15 : 74 |*********** | 16 -> 31 : 30 |**** | 32 -> 63 : 65 |********** | 64 -> 127 : 13 |** | 128 -> 255 : 88 |************* | 256 -> 511 : 260 |****************************************| 512 -> 1023 : 57 |******** | 1024 -> 2047 : 3 | |
ext4distなどのファイルシステム系のツールは操作ごとに整形して表示してくれます。
$ sudo ext4dist-bpfcc operation = open usecs : count distribution 0 -> 1 : 2038 |****************************************| 2 -> 3 : 95 |* | 4 -> 7 : 30 | | 8 -> 15 : 1 | | 16 -> 31 : 1 | | operation = fsync usecs : count distribution 0 -> 1 : 0 | | 2 -> 3 : 0 | | 4 -> 7 : 0 | | 8 -> 15 : 0 | | 16 -> 31 : 0 | | 32 -> 63 : 0 | | 64 -> 127 : 0 | | 128 -> 255 : 0 | | 256 -> 511 : 0 | | 512 -> 1023 : 1 |****************************************| 1024 -> 2047 : 1 |****************************************| 2048 -> 4095 : 0 | | 4096 -> 8191 : 0 | | 8192 -> 16383 : 1 |****************************************| operation = write usecs : count distribution 0 -> 1 : 0 | | 2 -> 3 : 282 |************************ | 4 -> 7 : 463 |****************************************| 8 -> 15 : 27 |** | 16 -> 31 : 14 |* | 32 -> 63 : 37 |*** | 64 -> 127 : 9 | | 128 -> 255 : 0 | | 256 -> 511 : 0 | | 512 -> 1023 : 0 | | 1024 -> 2047 : 0 | | 2048 -> 4095 : 0 | | 4096 -> 8191 : 0 | | 8192 -> 16383 : 0 | | 16384 -> 32767 : 0 | | 32768 -> 65535 : 1 | | operation = read usecs : count distribution 0 -> 1 : 3714 |****************************************| 2 -> 3 : 170 |* | 4 -> 7 : 32 | | 8 -> 15 : 9 | | 16 -> 31 : 5 | |
またfilelatencyやbiolatencyのように、
時間がかかっている処理だけを見つけるslower系ツール
特定のしきい値よりも時間のかかっている処理を見つけるためのツールは
こちらはdistのようにファイルシステムだけでなく、mysqld_
やdbslower
のように、
特にfuncslowerはカーネル上の特定の関数で時間がかかっているものを見つける際に、
特定の言語に特化したツール
uflowやucallsなど、
たとえばuflowは言語ごとのメソッド呼び出しのトレースを表示してくれます。
$ sudo uflow -l python 2168801 CPU PID TID TIME(us) METHOD 1 2168801 2168801 18.819 <- /usr/lib/python3/dist-packages/dbus/connection.py.msg_reply_handler 1 2168801 2168801 18.820 -> /usr/lib/python3/dist-packages/dbus/connection.py.msg_reply_handler 1 2168801 2168801 18.820 -> /usr/lib/python3/dist-packages/dbus/proxies.py._introspect_reply_handler 1 2168801 2168801 18.820 -> /usr/lib/python3/dist-packages/dbus/_expat_introspect_parser.py.process_introspection_data 1 2168801 2168801 18.820 -> /usr/lib/python3/dist-packages/dbus/_expat_introspect_parser.py.__init__ 1 2168801 2168801 18.820 <- /usr/lib/python3/dist-packages/dbus/_expat_introspect_parser.py.__init__ 1 2168801 2168801 18.820 -> /usr/lib/python3/dist-packages/dbus/_expat_introspect_parser.py.parse
それに対してucallsは一定期間内におけるメソッドの呼び出し回数をまとめてくれます。
$ sudo ucalls -l python 2168801 METHOD # CALLS /usr/lib/python3/dist-packages/UpdateManager/UpdatesAvailable.py.get_restart_icon 1 /usr/lib/python3/dist-packages/UpdateManager/Dialogs.py.on_settings_button_clicked 1 /usr/lib/python3/dist-packages/UpdateManager/Core/UpdateList.py._init_deps 1 /usr/lib/python3.9/re.py.compile 1
「-l
」
ちなみに
その他のツール
ここまでは比較的同じ系統としてまとまっていそうなものを紹介してきましたが、
たとえばネットワーク系はconnect()
やaccept()
を検知しますし、connect()
で時間がかかっているものを調べられます。tcplifeはTCPセッションの時間と送受信バイトを表示してくれます。セッションの状態遷移を表示してくれるtcpstatesなんてコマンドもあります。何ができるのかを把握するためにも、
$ sudo tcpstates-bpfcc SKADDR C-PID C-COMM LADDR LPORT RADDR RPORT OLDSTATE -> NEWSTATE MS ffff8c62d94d2bc0 0 swapper/7 192.168.0.59 39242 162.213.33.6 443 ESTABLISHED -> CLOSE_WAIT 0.000 ffff8c62d94d2bc0 1711445 Socket Thr 192.168.0.59 39242 162.213.33.6 443 CLOSE_WAIT -> LAST_ACK 0.086 ffff8c62d94d2bc0 56 ksoftirqd/ 192.168.0.59 39242 162.213.33.6 443 LAST_ACK -> CLOSE 234.077
memleakやoomkill、
ほとんどのコマンドが--help
」