K.Sasada's Home Page

こめんとのついか

こめんとこめんと!

message

please set comment :).

_15(Sat)

Ruby VM アドベントカレンダーの 15 日目です.

昨日まで,3 回に渡って TracePoint の紹介をしてきました.今日は,TracePoint の機能を C 拡張から利用するための C API についてご紹介します.

include/ruby/debug.h というファイルをご覧下さい.「/* TracePoint APIs */」というコメントから始まる箇所がそれに当たります.

短いですので,全部引用してみましょう.

VALUE rb_tracepoint_new(VALUE target_thread_not_supported_yet,
                        rb_event_flag_t events, 
                        void (*func)(VALUE, void *), void *data);
VALUE rb_tracepoint_enable(VALUE tpval);
VALUE rb_tracepoint_disable(VALUE tpval);
VALUE rb_tracepoint_enabled_p(VALUE tpval);

typedef struct rb_trace_arg_struct rb_trace_arg_t;
rb_trace_arg_t *rb_tracearg_from_tracepoint(VALUE tpval);

VALUE rb_tracearg_event(rb_trace_arg_t *trace_arg);
VALUE rb_tracearg_lineno(rb_trace_arg_t *trace_arg);
VALUE rb_tracearg_path(rb_trace_arg_t *trace_arg);
VALUE rb_tracearg_method_id(rb_trace_arg_t *trace_arg);
VALUE rb_tracearg_defined_class(rb_trace_arg_t *trace_arg);
VALUE rb_tracearg_binding(rb_trace_arg_t *trace_arg);
VALUE rb_tracearg_self(rb_trace_arg_t *trace_arg);
VALUE rb_tracearg_return_value(rb_trace_arg_t *trace_arg);
VALUE rb_tracearg_raised_exception(rb_trace_arg_t *trace_arg);

TracePoint.new に相当するのが rb_tracepoint_new() です.引数に「トレースを有効にするスレッド」,「トレースしたいイベント」,「トレースに相当する C 関数のポインタ func」および「func を呼ぶときに渡すポインタ」を意味します.返値は TracePoint オブジェクトになります.まぁ,わかりますよね.

スレッドの指定するべきパラメータ名が target_thread_not_supported_yet となっていますが,テストしていないので未サポートということにしています.誰かテストして下さい.イベント指定の events は,イベントを表す数値の論理和になります.

現在の trunk では,指定できるイベントは include/ruby/ruby.h に下記のように定義されています.それぞれ,名前を見れば何を意味するかわかりますよね.

/* traditional set_trace_func events */
#define RUBY_EVENT_NONE      0x0000
#define RUBY_EVENT_LINE      0x0001
#define RUBY_EVENT_CLASS     0x0002
#define RUBY_EVENT_END       0x0004
#define RUBY_EVENT_CALL      0x0008
#define RUBY_EVENT_RETURN    0x0010
#define RUBY_EVENT_C_CALL    0x0020
#define RUBY_EVENT_C_RETURN  0x0040
#define RUBY_EVENT_RAISE     0x0080
#define RUBY_EVENT_ALL       0x00ff

/* for TracePoint extended events */
#define RUBY_EVENT_B_CALL          0x0100
#define RUBY_EVENT_B_RETURN        0x0200
#define RUBY_EVENT_THREAD_BEGIN    0x0400
#define RUBY_EVENT_THREAD_END      0x0800
#define RUBY_EVENT_TRACEPOINT_ALL  0xFFFF

/* special events */
#define RUBY_EVENT_SPECIFIED_LINE 0x10000
#define RUBY_EVENT_SWITCH         0x20000
#define RUBY_EVENT_COVERAGE       0x40000

func と data も勘でわかるんじゃないかと思います.ちなみに,func の第一引数は,生成した TracePoint オブジェクトになります.これも,TracePoint.new に渡すブロックと同じですね.

さて,作成したトレースはまだ有効になっていないので rb_tracepoint_enable() によって有効にします.無効にするには rb_tracepoint_disable() ですね.

さて,指定したイベントが発生すると,func が TracePoint オブジェクトと data とともに呼ばれます.TracePoint#event などを実行したいわけですが,ここで一手間書ける必要があります.rb_tracearg_from_tracepoint() に TracePoint オブジェクトを渡して rb_trace_arg_t へのポインタを取得して下さい.ここで得られたポインタを使って rb_tracearg_event() などを呼び出すことで,情報を取得することが出来ます.

具体的には,次のようになるんじゃないかと思います.

void
func(VALUE tpobj, void *data)
{
  rb_trace_arg_t *trace_arg = rb_tracearg_from_tracepoint(tpobj);
  VALUE event_sym = rb_tracearg_event(trace_arg);
  ...
}

あとは,使い方わかりますよね,勘で.

というわけで,駆け足ですが,TrcaePoint を C 拡張から使うための C API をご紹介しました.これで高速なプロファイラとか誰か作って.

おっと,大事なことを言い忘れていました.debug.h の先頭を見ると書いてある

/* Note: This file contains experimental APIs. */
/* APIs can be replaced at Ruby 2.0.1 or later */

に注意して下さい.この辺の C API は,まだ,作ったばかりなので,色んなまずい点があるんじゃないかと思っているんですが,実際いくつかすでに見つかっています.なので,今作る人はあとで変わったときに追従する覚悟で使ってやって下さい.ゴメンね.また,なんか都合の悪い部分を見つけましたらコッソリ教えて下さい.

では,今日はこの辺で.


好きにコメントを編集してください。ただし、あまり他の人のコメントを書き換えることは感心しません。



back

tton 記述が使えます。YukiWikiな記述してりゃ問題ありません。

「行頭に#code」 と、「行頭に#end」 で挟むと、その間の行は pre で囲まれます。プログラムのソースを書くときに使ってください。

例:

#code

(なんかプログラム書く)

#end

リンクは

[[なまえ|http://www.example.org]]

とか

[[http://www.example.org]]

で貼れます。

$Date: 2003/04/28 10:27:51 $