この記事は RubyMotion Advent Calendar 2012 の 3 日目の記事です。
DTrace は Sun Microsystems が開発した実行中のアプリの情報を取得する仕組みです。DTrace を使用するとアプリケーションを一切変更することなく情報取得を可能にします。 Xcode に付属している Instruments が様々な情報を表示できるのは、縁の下に DTrace が存在しているからです。
Ruby 2.0 preview2 でいよいよ DTrace がサポートされましたが、MacRuby や RubyMotion ではすでに DTrace をサポートしています。
プローブを確認してみる
DTrace では、アプリに埋め込まれている「プローブ」と呼ばれる計測ポイントを用い、追跡をおこないます。
現在利用可能なプローブの一覧は sudo dtrace -l で確認することができます。シミュレータで RubyMotion アプリを実行した状態で確認してみましょう。
1 2 3 | |
別の Terminal ウィンドウで sudo dtrace -l を実行してみます。
1 2 3 4 5 6 7 8 | |
各列の説明を簡単にします。
PROVIDERは、プローブを提供しているプログラムの識別子のようなものです。MODULEは、プローブが属するカーネルモジュール名やライブラリ名が入ります。上のように、存在しない場合もあります。FUNCTIONは、プローブが属するプログラムの関数名を表します。上の例のように、存在しない場合もあります。NAMEは、プローブの機能を表す名前を表します。
大量に表示されるプローブの一覧から RubyMotion が提供しているものを探し出すのは不可能に近いので grep で検索してみましょう。
1 2 3 4 | |
RubyMotion は MacRuby と同様に macruby というプロバイダ名でプローブを提供しています。プローブは method-entry、 method-return と raise の 3 種類あることが分かります。
プローブ説明
| プローブ名 | 実行タイミング | 変数 arg0 | 変数 arg1 | 変数 arg2 | 変数 arg3 |
|---|---|---|---|---|---|
| method-entry | メソッド呼出開始 | クラス名 | メソッド名 | ソースファイル名 | 行番号 | method-return | メソッド呼出終了 | クラス名 | メソッド名 | ソースファイル名 | 行番号 | raise | 例外発生時 | クラス名 | ソースファイル名 | 行番号 | - |
method-entry プローブが実行されるとき、変数 arg0 にはクラス名、変数 arg1 には メソッド名が格納されています。(ソースファイル名と行番号は正しく格納されていない)
とりあえず動かしてみよう
準備
最初に作成した HelloDTrace アプリの app/app_delegate.rb を以下のように変更しておきます。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 | |
次に以下のような DTrace 用のスクリプト trace.d を用意します。
1 2 3 4 5 6 7 8 9 | |
実行してみよう
まずは RubyMotion アプリを rake コマンドで起動します。
シミュレータが起動したところで、別の Terminal ウィンドウで起動したアプリのプロセス ID を ps コマンドやアクティビティモニターで調べておきます。DTrace を実行する際にこのプロセス ID を使用します。
1 2 | |
プロセス ID は 5140 でした。
次に DTrace を実行します。dtrace の後に -s オプションで用意した DTrace 用のスクリプト、-p で情報を取得するプロセスの ID を指定します。
1
| |
マウスカーソルを移動するたびに DTrace の実行画面にトレース情報が表示されるかと思います。シミュレータ上でマウスオーバーを検出するためにマウスカーソルのイベントが発生するとやりとりしているようです。(キーボード操作だけで乗り切ると、余計なログが表示されず見やすくなります)
RubyMotion の REPL で hello_dtrace メソッドを実行してみましょう。シミュレータにはアラートビューが表示され、DTrace を実行している Terminal には以下のように DTrace を起動した後に実行されたメソッドが表示されます。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 | |
インデントの深さに応じて、メソッドがどのような順序で呼び出されているかが分かります。
CTRL + c か RubyMotion アプリを終了させると DTrace が終了します。
メソッドの実行時間を計測してみよう
今度はメソッドの実行時間を計測してみよう。使用するスクリプトは以下のようになります。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 | |
/ copyinstr(arg0) == "String" / という記述を追加すると、変数 arg0 が “String” と一致するときだけ計測されるようになります。
DTrace で上のスクリプトを実行すると次のように、String クラスのメソッドの実行時間の合計が表示されます。
1 2 3 4 5 | |
わざわざアプリにパフォーマンスを計測するためのコードを追加しなくても、どのメソッドの処理が重たいのかが分かります。
まとめ
DTrace を利用すると、アプリケーションは全く変更しなくても実行をトレースすることができます。RubyMotion アプリはもちろん、Ruby 2.0 で DTrace がサポートされると Web アプリでも同様にトレースできることでしょう。
参考
MacRuby の DTrace のサンプルです。メソッドの実行回数を計測するスクリプトがあったりします。
DTrace の基本が書かれています。
DTrace についてはオラクルのドキュメントが一番詳しいです。