Slide 1

Slide 1 text

PEPABO SUMMER INTERN VERSION 近藤うちお / GMO Pepabo, Inc. 2020.09.08 bcc Python
 Developer Tutorial 徹 底 解 説 !

Slide 2

Slide 2 text

この資料は何 •Python版「bcc Python Developer Tutorial」を通しでやってみる 際に参考になるかもしれない解説スライドです •@udzura の独断と偏見が含まれます •@udzura はRuby版BCCポート(*)を開発した人で、TutorialもRuby に移植した経験がありますが、それでも間違ったことを言っている可 能性はあります。 IUUQTHJUIVCDPNVE[VSBSCCDD

Slide 3

Slide 3 text

全体の攻略方針 •三分割できる •Lesson 1〜6: 第一章 BCCプログラミングの基本 •Lesson 7〜11: 第二章 収集したデータの出力方法 •Lesson 12〜16: 第三章 様々なるProbe •とにかく第一章が重要で難しい。 •ここさえ乗り切れば後はAPIを覚えていくフェーズになる。 •インターンの半分でLesson 6までやり切れば、ツールは何とか作れるはず?

Slide 4

Slide 4 text

環境について •Ubuntu Bionic で大丈夫 •カーネル 5.3 あたりを明示的に入れたければどうぞ。
 その場合、linux-libc-dev パッケージを先のバージョンから
 ダウンロードして入れても良いかも。 •Focal はなんか不安定な印象がまだあるが、挑戦はいいんでは •Vagrant を使えば十分、むしろコンテナでは如何ともし難い •Linux の人も、いちおうVMを挟んでおきましょう

Slide 5

Slide 5 text

第一章 BCCプログラミングの基本

Slide 6

Slide 6 text

1. Hello World

Slide 7

Slide 7 text

BCCの動作確認 •やってることは: clone(2) のトレース •clone(2) は要するにfork()で、プロセスを作ったら呼ばれるsyscall •fork() -> exec() -> exit() の流れを復習しよう

Slide 8

Slide 8 text

2. sys_sync()

Slide 9

Slide 9 text

対象システムコールの変更 •kprobe__sys_BAR(...) という関数名をBCCで定義すると、
 自動でkprobeにアタッチされる。 •sys_BAR kprobe はシステムコール BAR(2) に対応する ※ hello_world.py を改修する ※kprobe = カーネルのシンボルに紐づくフック

Slide 10

Slide 10 text

3. hello_fields.py

Slide 11

Slide 11 text

プログラムの基本形を覚える ※ printk() したら msg で取れる

Slide 12

Slide 12 text

4. sync_timing.py

Slide 13

Slide 13 text

BPF Mapの基本的な使い方

Slide 14

Slide 14 text

BPF Mapの基本的な使い方

Slide 15

Slide 15 text

BPF Mapの基本的な使い方

Slide 16

Slide 16 text

5. sync_count.py

Slide 17

Slide 17 text

前のコードを改修しよう • ヒントなど: • key に 0 以外を指定すればストアする 値を増やせるよ(不要か?) • lookup()してNULLなら初期値、
 そうでなければ +1 した値を保存すれ ばカウンターになるのでは? • もう差を取る必要は実はない • outputの手段は今のとこprintk()しか ありませんね...

Slide 18

Slide 18 text

6. disksnoop.py

Slide 19

Slide 19 text

ブロックデバイスI/Oのトレース例 •押さえるべきこと: •trace_start()からtrace_completion()までの差分を計測している •struct request * のアドレスをキーがわりにする •一回一回のリクエスト構造体はカーネルのメモリ上では別々の位置 にあるはず(アドレスの使い回しはあるが、同時にはない) •printk() で無理やり3つの値を送っている

Slide 20

Slide 20 text

自力でゆっくり 読んでみましょう

Slide 21

Slide 21 text

第二章 収集したデータの出力方法

Slide 22

Slide 22 text

7. hello_perf_output.py

Slide 23

Slide 23 text

Perf buffer の使い方 •コツ: •trace_fields() 系はtracefsの一つのファイルをtailしてるだけで、 複数同時にアウトプットできなくて混ざる •Perf bufferにデータを送り込む専用のデータ構造
 BPF_PERF_OUTPUT() •open_perf_buffer() はデータが来たときのコールバックの登録 •perf_buffer_poll() で待つ

Slide 24

Slide 24 text

8. sync_perf_output.py

Slide 25

Slide 25 text

4. の書き換え。 •コツ: •7. のコード構造を頭に叩き込んで落ち着いて頑張る。

Slide 26

Slide 26 text

9. bitehist.py

Slide 27

Slide 27 text

ヒストグラムの出し方 •コツ: •ヒストグラム専用のデータ構造とヘルパーがあって便利ですね •struct request のメンバの確認の仕方などを押さえとくといい

Slide 28

Slide 28 text

10. disklatency.py

Slide 29

Slide 29 text

disksnoop.py のリライト •コツ: •レイテンシ計測のパターンを思い出す •あとはレイテンシをヒストグラムに登録するだけ

Slide 30

Slide 30 text

11. vfsreadlat.py

Slide 31

Slide 31 text

定期表示系のトレーサの実装 •コツ: •CとPythonのファイル分割、b["dist"].clear() の2つの方法を
 覚えるためのレッスン。 •他は新しいことはないので復習。

Slide 32

Slide 32 text

第三章 様々なるProbe、そして伝説へ...

Slide 33

Slide 33 text

12. urandomread.py

Slide 34

Slide 34 text

tracepoint の利用 •コツ: •普通にtracepointを使う場合専用のマクロがある •マクロ経由の場合明示的なアタッチは不要 •tracepoint のフォーマット確認の仕方を押さえる

Slide 35

Slide 35 text

ちなみに •@udzura が雑に書いたtracepoint補完確認コマンドがある。 • https://gist.github.com/udzura/6d40a3f010aff2a4a58f632627ab7f89

Slide 36

Slide 36 text

13. disksnoop.py fixed

Slide 37

Slide 37 text

kprobe → tracepoint の書き換え •コツというか...: •trepo() を使って当該tracepointの確認を... •してもよくわからんとなった場合は、 @udzura のRuby実装を眺め てもいいと思います。 •トレースポイント、ドキュメントがないよね...。

Slide 38

Slide 38 text

14. strlen_count.py

Slide 39

Slide 39 text

uprobe の利用 •コツ: •地味に初めて「文字列をキーとしたハッシュ」を扱うので注意 •その他は既存のProbeと扱いは変わらない •get_table() で取れるテーブルはdict風のインタフェースがある

Slide 40

Slide 40 text

uprobe の確認方法 •1) readelf -s •2) bpftrace (ただし、snap版は使えない)

Slide 41

Slide 41 text

15. nodejs_http_server.py

Slide 42

Slide 42 text

USDTの利用... •コツというか...: •node.jsをUSDT有効で用意するのが大変。頑張って •ヒント: “同じディレクトリにあるnode.jsのサーバプログラムを、 USDTを有効にした(--enable-dtrace)ビルドのnode.jsバイナリ で実行して計測する必要があります” •nodebrew はビルドオプションを渡せる。もしくは自分でbuild •USDT有効になっても、さらにusdt系の関数は癖があって大変。

Slide 43

Slide 43 text

USDTの確認方法 •1) readelf -n

Slide 44

Slide 44 text

USDTの確認方法 •2) bpftrace

Slide 45

Slide 45 text

16. task_switch.c

Slide 46

Slide 46 text

ここまでの総集編 •コツというか...: •finish_task_switch() の定義をちゃんとカーネルソースコードを見て 確認するといいと思う •eBPF C側の関数の第2引数以降は、元の関数の引数がスライドする •後は、今までの知識で!

Slide 47

Slide 47 text

17. Further Study

Slide 48

Slide 48 text

登り始めた ばかりだからな...(AA略)