Rubyは 2.0 から --enable-dtrace
オプションでコンパイルが可能になったんですが、
一方で現代のLinuxとしてはこれらのトレースポイントは USDT としてトレースできます。今日はその手順など。
--enable-dtrace
で作ったRubyをコンパイル
rbenv なら CONFIGURE_OPTS='--enable-dtrace'
という環境変数で渡せばOK。
$ CONFIGURE_OPTS='--enable-dtrace' rbenv install 2.6.4 ... $ ruby -r rbconfig -e 'puts RbConfig::CONFIG["configure_args"]' '--prefix=/home/vagrant/.rbenv/versions/2.6.4' '--enable-dtrace' 'LDFLAGS=-L/home/vagrant/.rbenv/versions/2.6.4/lib ' 'CPPFLAGS=-I/home/vagrant/.rbenv/versions/2.6.4/include '
プローブの一覧
bpftrace を使うので snap install bpftrace
などしてください。
$ ruby -e 'loop { File.read("/etc/hosts"); sleep 1 }' & [1] 14665 $ sudo bpftrace -p 14665 -l 'usdt:*ruby*' usdt:/home/vagrant/.rbenv/versions/2.6.4/bin/ruby:ruby:raise usdt:/home/vagrant/.rbenv/versions/2.6.4/bin/ruby:ruby:gc__mark__end usdt:/home/vagrant/.rbenv/versions/2.6.4/bin/ruby:ruby:gc__mark__begin usdt:/home/vagrant/.rbenv/versions/2.6.4/bin/ruby:ruby:gc__sweep__end usdt:/home/vagrant/.rbenv/versions/2.6.4/bin/ruby:ruby:gc__sweep__begin usdt:/home/vagrant/.rbenv/versions/2.6.4/bin/ruby:ruby:hash__create usdt:/home/vagrant/.rbenv/versions/2.6.4/bin/ruby:ruby:load__entry usdt:/home/vagrant/.rbenv/versions/2.6.4/bin/ruby:ruby:load__return usdt:/home/vagrant/.rbenv/versions/2.6.4/bin/ruby:ruby:find__require__return usdt:/home/vagrant/.rbenv/versions/2.6.4/bin/ruby:ruby:require__entry usdt:/home/vagrant/.rbenv/versions/2.6.4/bin/ruby:ruby:find__require__entry usdt:/home/vagrant/.rbenv/versions/2.6.4/bin/ruby:ruby:require__return usdt:/home/vagrant/.rbenv/versions/2.6.4/bin/ruby:ruby:object__create usdt:/home/vagrant/.rbenv/versions/2.6.4/bin/ruby:ruby:parse__begin usdt:/home/vagrant/.rbenv/versions/2.6.4/bin/ruby:ruby:parse__end usdt:/home/vagrant/.rbenv/versions/2.6.4/bin/ruby:ruby:string__create usdt:/home/vagrant/.rbenv/versions/2.6.4/bin/ruby:ruby:symbol__create usdt:/home/vagrant/.rbenv/versions/2.6.4/bin/ruby:ruby:method__cache__clear usdt:/home/vagrant/.rbenv/versions/2.6.4/bin/ruby:ruby:cmethod__entry usdt:/home/vagrant/.rbenv/versions/2.6.4/bin/ruby:ruby:cmethod__return usdt:/home/vagrant/.rbenv/versions/2.6.4/bin/ruby:ruby:method__return usdt:/home/vagrant/.rbenv/versions/2.6.4/bin/ruby:ruby:method__entry usdt:/home/vagrant/.rbenv/versions/2.6.4/bin/ruby:ruby:array__create
るびまの解説記事と同じようなポイントが定義されている。
$ sudo bpftrace -p 14665 -e 'usdt:/home/vagrant/.rbenv/versions/2.6.4/bin/ruby:ruby:cmethod__entry { printf("cmethod__entry: %s#%s\n", str(arg0), str(arg1)); }' Attaching 1 probe... cmethod__entry: IO#read cmethod__entry: Kernel#sleep cmethod__entry: IO#read cmethod__entry: Kernel#sleep cmethod__entry: IO#read cmethod__entry: Kernel#sleep cmethod__entry: IO#read cmethod__entry: Kernel#sleep cmethod__entry: IO#read cmethod__entry: Kernel#sleep cmethod__entry: IO#read cmethod__entry: Kernel#sleep
IO#readもKernel#sleep も cmethod__entry
を通る。
$ ruby -e 'def foobar; Object.new; end; loop { foobar; sleep 1 }' & [1] 15744 $ sudo bpftrace -p 15744 -e 'usdt:/home/vagrant/.rbenv/versions/2.6.4/bin/ruby:ruby:object__create{ printf("object class: %s\n", str(arg0)); }' Attaching 1 probe... object class: Object object class: Object object class: Object object class: Object object class: Object object class: Object object class: Object
オブジェクトの生成を検知したり、などなど。
動いているプロセスにアタッチできたりもするのと、他のkprobe/uprobeと組み合わせるなどして、何かしら使えるかもしれませんね。