2023/1/23
Ruby Association Grant Targets
Developing Pf2
✅ Simultaneous observation of multiple Ruby Threads
✅ Improved visualization
Automated testing
✅ GVL observation
✅ When did the Thread acquire the lock?
Contention information
How long are Threads waiting for the lock?
GC observation
✅ Markers
今回の進捗
中間報告を出した
誰が106回もダウンロードしてるんだろう……
引き続き中身をだいぶ書き直しつつ
安定しているはずの scheduling algorithm だけを収録してリリース
Pf2.profile { your_code_here } API の追加
macOS サポート (TimerThreadScheduler のみ)
これは Mysql2::Client#query の呼び出しをプロファイルしている様子
https://scrapbox.io/files/65af0dee889bfd0023296a44.png
rb_mysql_query() (mysql2 gem), <no debug symbols> (たぶん libmysqlclient), SSL_write() (openssl), write() (libc) などが見えていて面白い
Rust の std::backtrace でもいけるじゃんって思ったけど(↑ はそれで実装した)、やはり関数のアドレスなどはほしいので libbacktrace がよいかも
Native の下に Ruby がくるケースはある?
rb_vm_exec か vm_call_cfunc_with_frame を見つけたらそこで表示を打ち切ってるだけ
なのでいいアルゴリズムを考えてあげる必要がある
現時点の実装は stack top にある C frame を乗せてあげてるだけ
間の Ruby cfunc の部分を Native code にしようとするともっと賢い実装が必要
C extension から rb_funcall されるケース
cfp に iseq があれば Ruby で実装されていることが分かる
algorithm
cfp を順番に見ていく
ec (execution context)
ec->cfp を たどっていく
cfp rb_control_frame_t ->iseq
iseq があったら Ruby だと思っていい
なかったら cfunc (の可能性がある)
ない場合は vm_exec_core() の外側にいることは間違いない (Ruby ではない)
C のスタックを差し込みたい場所の可能性が高い
動かなさそうなケース
vm_exec の中に vm_catch_execption (例外) みたいな関数を通ったとき?
↑ 一番上だけでなく、中間の部分の C func の部分にも C stack を差し込むのをやってみる
次にできそうなこと
普通にプロファイラとしての使い勝手を上げていく
オプションとか Rack middleware
interval, scheduler, time mode
wall time + cpu time の両方を計測することはできそう
2つのタイマーを動かすだけである
その分オーバーヘッドは普通に大きい
wall time で一定の interval で取りつつ、wall time のタイマーが発火するごとに cpu time のクロックを見て、一定時間が経過していたら直前の sample の重み (?) を足す、みたいなことでも近似はできそう
GC の扱いについて
そもそも GC に関するメトリクスの適切な気にしかた(= 何を収集するといいのか)が分からない
GC time をチューニングする際は memory profile を取ってアロケーションの数を見たりする、が
GC time のどれぐらいが scan にかかっているか? みたいなことが分かるとうれしいかもしれない
が、それはスタックとかを見ても別に分かることではなさそう
GC time + GC の種類 (major or minor) ぐらいは取れてもいいかも
major GC が多い場合やりたいチューニング、みたいなのはある
RUBY_REMEMBERED_WB_UNPROTECTED_OBJECTS_LIMIT_RATIO の調整? とか
GC.stats の中に major_gc_count はあるので、どこかでは判定できてはいるはず
あるフレームが JIT されているかは分かる?
eBPF 方面がなんとなく気になっているが特に知見はない call site ごとに山を分けるか?
異なる呼び出しは分けたい
プロファイルの見方
Call graph, Flamegraph → その関数自体を最適化する
Upside down (inverted) → 呼び出し回数を減らす