diff options
-rw-r--r-- | ChangeLog | 26 | ||||
-rw-r--r-- | include/ruby/debug.h | 11 | ||||
-rw-r--r-- | iseq.c | 2 | ||||
-rw-r--r-- | vm_backtrace.c | 87 |
4 files changed, 124 insertions, 2 deletions
@@ -1,7 +1,31 @@ +Mon Oct 7 16:12:36 2013 Koichi Sasada <ko1@atdot.net> + + * include/ruby/debug.h: add backtrace collecting APIs for profiler. + * int rb_profile_frames(int start, int limit, VALUE *buff, int *lines); + Collect information of frame information. + + * VALUE rb_profile_frame_path(VALUE frame); + * VALUE rb_profile_frame_absolute_path(VALUE frame); + * VALUE rb_profile_frame_label(VALUE frame); + * VALUE rb_profile_frame_base_label(VALUE frame); + * VALUE rb_profile_frame_first_lineno(VALUE frame); + * VALUE rb_profile_frame_classpath(VALUE frame); + * VALUE rb_profile_frame_singleton_method_p(VALUE frame); + Get information about each frame. + + These APIs are designed for profilers, for example, no objectallocation, + and enough information for profilers. + In this version, this API collects only collect Ruby level frames. + This issue will be fixed after Ruby 2.1. + + * vm_backtrace.c: implement above APIs. + + * iseq.c (rb_iseq_klass): return local_iseq's class. + Mon Oct 7 14:26:01 2013 Koichi Sasada <ko1@atdot.net> * proc.c: catch up last commit. - Type of return value of rb_iseq_first_lineno() is now VALUE. + Type of return value of rb_iseq_first_lioneno() is now VALUE. * vm_insnhelper.c (argument_error): ditto. diff --git a/include/ruby/debug.h b/include/ruby/debug.h index dca0f1087b..2ef99d4185 100644 --- a/include/ruby/debug.h +++ b/include/ruby/debug.h @@ -24,6 +24,17 @@ RUBY_SYMBOL_EXPORT_BEGIN /* Note: This file contains experimental APIs. */ /* APIs can be replaced at Ruby 2.0.1 or later */ + +/* profile frames APIs */ +int rb_profile_frames(int start, int limit, VALUE *buff, int *lines); +VALUE rb_profile_frame_path(VALUE frame); +VALUE rb_profile_frame_absolute_path(VALUE frame); +VALUE rb_profile_frame_label(VALUE frame); +VALUE rb_profile_frame_base_label(VALUE frame); +VALUE rb_profile_frame_first_lineno(VALUE frame); +VALUE rb_profile_frame_classpath(VALUE frame); +VALUE rb_profile_frame_singleton_method_p(VALUE frame); + /* debug inspector APIs */ typedef struct rb_debug_inspector_struct rb_debug_inspector_t; typedef VALUE (*rb_debug_inspector_func_t)(const rb_debug_inspector_t *, void *); @@ -956,7 +956,7 @@ rb_iseq_klass(VALUE self) { rb_iseq_t *iseq; GetISeqPtr(self, iseq); - return iseq->klass; + return iseq->local_iseq->klass; } static diff --git a/vm_backtrace.c b/vm_backtrace.c index 3945993e42..b4f16f68fc 100644 --- a/vm_backtrace.c +++ b/vm_backtrace.c @@ -1200,3 +1200,90 @@ rb_debug_inspector_backtrace_locations(const rb_debug_inspector_t *dc) return dc->backtrace; } +int +rb_profile_frames(int start, int limit, VALUE *buff, int *lines) +{ + int i; + rb_thread_t *th = GET_THREAD(); + rb_control_frame_t *cfp = th->cfp, *end_cfp = RUBY_VM_END_CONTROL_FRAME(th); + + for (i=0; i<limit && cfp != end_cfp;) { + if (cfp->iseq && cfp->pc) { /* should be NORMAL_ISEQ */ + if (start > 0) { + start--; + continue; + } + + /* record frame info */ + buff[i] = cfp->iseq->self; + if (lines) lines[i] = calc_lineno(cfp->iseq, cfp->pc); + i++; + } + cfp = RUBY_VM_PREVIOUS_CONTROL_FRAME(cfp); + } + + return i; +} + +#define frame2iseq(frame) frame + +VALUE +rb_profile_frame_path(VALUE frame) +{ + return rb_iseq_path(frame2iseq(frame)); +} + +VALUE +rb_profile_frame_absolute_path(VALUE frame) +{ + return rb_iseq_absolute_path(frame2iseq(frame)); +} + +VALUE +rb_profile_frame_label(VALUE frame) +{ + return rb_iseq_label(frame2iseq(frame)); +} + +VALUE +rb_profile_frame_base_label(VALUE frame) +{ + return rb_iseq_base_label(frame2iseq(frame)); +} + +VALUE +rb_profile_frame_first_lineno(VALUE frame) +{ + return rb_iseq_first_lineno(frame2iseq(frame)); +} + +VALUE +rb_profile_frame_classpath(VALUE frame) +{ + VALUE klass = rb_iseq_klass(frame2iseq(frame)); + + if (klass && !NIL_P(klass)) { + if (RB_TYPE_P(klass, T_ICLASS)) { + klass = RBASIC(klass)->klass; + } + else if (FL_TEST(klass, FL_SINGLETON)) { + klass = rb_ivar_get(klass, id__attached__); + } + return rb_class_path(klass); + } + else { + return Qnil; + } +} + +VALUE +rb_profile_frame_singleton_method_p(VALUE frame) +{ + VALUE klass = rb_iseq_klass(frame2iseq(frame)); + if (klass && !NIL_P(klass) && FL_TEST(klass, FL_SINGLETON)) { + return Qtrue; + } + else { + return Qfalse; + } +} |