From abcbd7ea38f64f942a934ba065aabf9da81a21bc Mon Sep 17 00:00:00 2001 From: ko1 Date: Wed, 25 Apr 2007 03:50:00 +0000 Subject: * yarvcore.h: remove rb_control_frame_t#callee_id. * vm_macro.def: ditto. * eval_intern.h (exec_event_hooks): fix to check event flags * eval_intern.h (EXEC_EVENT_HOOK): fix to re-check event flags. * ext/probeprofiler : added. this profiler is sampling based profiler. * vm.c: add rb_thread_current_status() API for probeprofiler. * thread.c (rb_thread_execute_interrupts): add comments. git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@12213 b2dd03c8-39d4-4d8f-98ff-823fe69b080e --- ChangeLog | 17 +++++++++ eval_intern.h | 20 ++++++----- ext/probeprofiler/extconf.rb | 2 ++ ext/probeprofiler/lib/probeprofile.rb | 7 ++++ ext/probeprofiler/lib/probeprofiler.rb | 14 ++++++++ ext/probeprofiler/probeprofiler.c | 63 ++++++++++++++++++++++++++++++++++ thread.c | 17 ++++++++- vm.c | 53 +++++++++++++++++++++++++--- vm_macro.def | 1 - yarvcore.h | 40 ++++++++++----------- 10 files changed, 199 insertions(+), 35 deletions(-) create mode 100644 ext/probeprofiler/extconf.rb create mode 100644 ext/probeprofiler/lib/probeprofile.rb create mode 100644 ext/probeprofiler/lib/probeprofiler.rb create mode 100644 ext/probeprofiler/probeprofiler.c diff --git a/ChangeLog b/ChangeLog index e9738889d5..3fa67e9457 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,20 @@ +Wed Apr 25 12:42:40 2007 Koichi Sasada + + * yarvcore.h: remove rb_control_frame_t#callee_id. + + * vm_macro.def: ditto. + + * eval_intern.h (exec_event_hooks): fix to check event flags + + * eval_intern.h (EXEC_EVENT_HOOK): fix to re-check event flags. + + * ext/probeprofiler : added. this profiler is sampling based + profiler. + + * vm.c: add rb_thread_current_status() API for probeprofiler. + + * thread.c (rb_thread_execute_interrupts): add comments. + Wed Apr 25 10:36:03 2007 Nobuyoshi Nakada * eval_intern.h (PUSH_TAG): no argument now. diff --git a/eval_intern.h b/eval_intern.h index ce059ae04b..2bc529db93 100644 --- a/eval_intern.h +++ b/eval_intern.h @@ -234,7 +234,9 @@ static void inline exec_event_hooks(rb_event_hook_t *hook, rb_event_flag_t flag, VALUE self, ID id, VALUE klass) { while (hook) { - (*hook->func)(flag, hook->data, self, id, klass); + if (flag & hook->flag) { + (*hook->func)(flag, hook->data, self, id, klass); + } hook = hook->next; } } @@ -242,13 +244,15 @@ exec_event_hooks(rb_event_hook_t *hook, rb_event_flag_t flag, VALUE self, ID id, #define EXEC_EVENT_HOOK(th, flag, self, id, klass) do { \ rb_event_flag_t wait_event__ = th->event_flags; \ if (UNLIKELY(wait_event__)) { \ - VALUE self__ = (self), klass__ = (klass); \ - ID id__ = (id); \ - if (wait_event__ & flag) { \ - exec_event_hooks(th->event_hooks, flag, self__, id__, klass__); \ - } \ - if (wait_event__ & RUBY_EVENT_VM) { \ - exec_event_hooks(th->vm->event_hooks, flag, self__, id__, klass__); \ + if (wait_event__ & (flag | RUBY_EVENT_VM)) { \ + VALUE self__ = (self), klass__ = (klass); \ + ID id__ = (id); \ + if (wait_event__ & flag) { \ + exec_event_hooks(th->event_hooks, flag, self__, id__, klass__); \ + } \ + if (wait_event__ & RUBY_EVENT_VM) { \ + exec_event_hooks(th->vm->event_hooks, flag, self__, id__, klass__); \ + } \ } \ } \ } while (0) diff --git a/ext/probeprofiler/extconf.rb b/ext/probeprofiler/extconf.rb new file mode 100644 index 0000000000..1592971d4c --- /dev/null +++ b/ext/probeprofiler/extconf.rb @@ -0,0 +1,2 @@ +require 'mkmf' +create_makefile("probeprofiler") diff --git a/ext/probeprofiler/lib/probeprofile.rb b/ext/probeprofiler/lib/probeprofile.rb new file mode 100644 index 0000000000..f5ff40d2cc --- /dev/null +++ b/ext/probeprofiler/lib/probeprofile.rb @@ -0,0 +1,7 @@ +require 'probeprofiler' +END{ + ProbeProfiler.stop_profile + ProbeProfiler.print_profile +} + +ProbeProfiler.start_profile diff --git a/ext/probeprofiler/lib/probeprofiler.rb b/ext/probeprofiler/lib/probeprofiler.rb new file mode 100644 index 0000000000..e014adda2f --- /dev/null +++ b/ext/probeprofiler/lib/probeprofiler.rb @@ -0,0 +1,14 @@ + +require 'probeprofiler.so' + +def ProbeProfiler.print_profile + data = ProbeProfiler.profile_data + total = 0.0 + printf("%-60s %-8s %-7s\n", "ProbeProfile Result: Method signature", "count", "ratio") + data.map{|k, n| total += n; [n, k]}.sort.reverse.each{|n, sig| + # + printf("%-60s %8d %7.2f%%\n", sig, n, 100 * n / total) + } + printf("%60s %8d\n", "total:", total) +end + diff --git a/ext/probeprofiler/probeprofiler.c b/ext/probeprofiler/probeprofiler.c new file mode 100644 index 0000000000..9d67160bc4 --- /dev/null +++ b/ext/probeprofiler/probeprofiler.c @@ -0,0 +1,63 @@ +#include +#include + +static void +hash_inc(VALUE data, VALUE key) +{ + VALUE num = INT2FIX(0); + + if (num = rb_hash_aref(data, key)) { + num = INT2FIX(FIX2INT(num) + 1); + } + + rb_hash_aset(data, key, num); +} + +static void +pprof_hook(rb_event_flag_t flag, VALUE data, + VALUE dmyid, VALUE dmyklass) +{ + rb_thread_t *th = GET_THREAD(); + VALUE sig = rb_thread_current_sig(th); + hash_inc(data, sig); +} + +static VALUE +pprof_data(VALUE mod) +{ + rb_const_get_at(mod, rb_intern("#pprof_data")); +} + +static VALUE +pprof_start(VALUE self) +{ + VALUE data = pprof_data(self); + rb_add_event_hook(pprof_hook, RUBY_EVENT_SWITCH, data); + return Qnil; +} + +static VALUE +pprof_stop(VALUE self) +{ + rb_remove_event_hook(pprof_hook); + return Qnil; +} + +static int +hash_to_ary_i(VALUE key, VALUE value, VALUE ary) +{ + rb_ary_push(ary, rb_ary_new3(2, value, key)); + return ST_CONTINUE; +} + +Init_probeprofiler(void) +{ + VALUE mPProf; + + mPProf = rb_define_module("ProbeProfiler"); + rb_const_set(mPProf, rb_intern("#pprof_data"), rb_hash_new()); + rb_define_module_function(mPProf, "start_profile", pprof_start, 0); + rb_define_module_function(mPProf, "stop_profile", pprof_stop, 0); + rb_define_module_function(mPProf, "profile_data", pprof_data, 0); +} + diff --git a/thread.c b/thread.c index bcff909484..5e8c915aa6 100644 --- a/thread.c +++ b/thread.c @@ -717,6 +717,7 @@ rb_thread_execute_interrupts(rb_thread_t *th) /* thread pass */ rb_thread_schedule(); } + EXEC_EVENT_HOOK(th, RUBY_EVENT_SWITCH, th->cfp->self, 0, 0); } @@ -1836,14 +1837,28 @@ static void timer_thread_function(void) { rb_vm_t *vm = GET_VM(); /* TODO: fix me for Multi-VM */ + + /* for time slice */ vm->running_thread->interrupt_flag = 1; - + + /* check signal */ if (vm->bufferd_signal_size && vm->main_thread->exec_signal == 0) { vm->main_thread->exec_signal = rb_get_next_signal(vm); thread_debug("bufferd_signal_size: %d, sig: %d\n", vm->bufferd_signal_size, vm->main_thread->exec_signal); rb_thread_interrupt(vm->main_thread); } + +#if 0 + /* prove profiler */ + if (vm->prove_profile.enable) { + rb_thread_t *th = vm->running_thread; + + if (vm->during_gc) { + /* GC prove profiling */ + } + } +#endif } void diff --git a/vm.c b/vm.c index c3cba1ea21..c1793ae760 100644 --- a/vm.c +++ b/vm.c @@ -106,7 +106,7 @@ push_frame(rb_thread_t *th, rb_iseq_t *iseq, VALUE magic, cfp->dfp = dfp; cfp->proc = 0; cfp->method_id = 0; - cfp->callee_id = 0; + cfp->method_klass = 0; #define COLLECT_PROFILE 0 #if COLLECT_PROFILE @@ -541,7 +541,6 @@ th_call0(rb_thread_t *th, VALUE klass, VALUE recv, push_frame(th, 0, FRAME_MAGIC_CFUNC, recv, (VALUE)blockptr, 0, reg_cfp->sp, 0, 1); - cfp->callee_id = oid; cfp->method_id = id; cfp->method_klass = klass; @@ -983,11 +982,10 @@ th_backtrace_each(rb_thread_t *th, rb_ary_push(ary, str); } } - else if (cfp->callee_id) { + else if (cfp->method_id) { str = rb_sprintf("%s:%d:in `%s'", file, line_no, - /* TODO: method_id? callee_id? */ - rb_id2name(cfp->callee_id)); + rb_id2name(cfp->method_id)); rb_ary_push(ary, str); } cfp = RUBY_VM_NEXT_CONTROL_FRAME(cfp); @@ -1807,3 +1805,48 @@ rb_thread_eval(rb_thread_t *th, VALUE iseqval) return val; } +int +rb_thread_method_id_and_klass(rb_thread_t *th, ID *idp, VALUE *klassp) +{ + rb_control_frame_t *cfp = th->cfp; + + if (cfp->iseq) { + if (cfp->pc != 0) { + rb_iseq_t *iseq = cfp->iseq->local_iseq; + if (idp) *idp = rb_intern(RSTRING_PTR(iseq->name)); + if (klassp) *klassp = iseq->klass; + return 1; + } + } + else { + if (idp) *idp = cfp->method_id; + if (klassp) *klassp = cfp->method_klass; + return 1; + } + *idp = *klassp = 0; + return 0; +} + +VALUE +rb_thread_current_status(rb_thread_t *th) +{ + rb_control_frame_t *cfp = th->cfp; + VALUE str = Qnil; + + if (cfp->iseq != 0) { + if (cfp->pc != 0) { + rb_iseq_t *iseq = cfp->iseq; + int line_no = th_get_sourceline(cfp); + char *file = RSTRING_PTR(iseq->filename); + str = rb_sprintf("%s:%d:in `%s'", + file, line_no, RSTRING_PTR(iseq->name)); + } + } + else if (cfp->method_id) { + str = rb_sprintf("`%s#%s' (cfunc)", + RSTRING_PTR(rb_class_name(cfp->method_klass)), + rb_id2name(cfp->method_id)); + } + + return str; +} diff --git a/vm_macro.def b/vm_macro.def index 2cb9fd7c6d..7d95b13ba7 100644 --- a/vm_macro.def +++ b/vm_macro.def @@ -61,7 +61,6 @@ MACRO macro_eval_invoke_cfunc(num, id, recv, klass, mn, blockptr) rb_control_frame_t *cfp = push_frame(th, 0, FRAME_MAGIC_CFUNC, recv, (VALUE) blockptr, 0, GET_SP(), 0, 1); - cfp->callee_id = id; /* TODO */ cfp->method_id = id; cfp->method_klass = klass; diff --git a/yarvcore.h b/yarvcore.h index 56d17f0654..532b613c47 100644 --- a/yarvcore.h +++ b/yarvcore.h @@ -253,20 +253,20 @@ struct rb_iseq_struct { void *jit_compiled; void *iseq_orig; - /** - * argument information - * - * def m(a1, a2, ..., aM, b1=(...), b2=(...), ..., bN=(...), *c, &d) - * => - * - * argc = M - * arg_rest = M+N + 1 // if no rest arguments, rest is 0 - * arg_opts = N - * arg_opts_tbl = [ (N entries) ] - * arg_block = M+N + 1 (rest) + 1 (block) - * check: - * M <= num - */ + /** + * argument information + * + * def m(a1, a2, ..., aM, b1=(...), b2=(...), ..., bN=(...), *c, &d) + * => + * + * argc = M + * arg_rest = M+N + 1 // if no rest arguments, rest is 0 + * arg_opts = N + * arg_opts_tbl = [ (N entries) ] + * arg_block = M+N + 1 (rest) + 1 (block) + * check: + * M <= num + */ int argc; int arg_simple; @@ -316,6 +316,7 @@ typedef struct rb_iseq_struct rb_iseq_t; #define RUBY_EVENT_RAISE 0x80 #define RUBY_EVENT_ALL 0xff #define RUBY_EVENT_VM 0x100 +#define RUBY_EVENT_SWITCH 0x200 typedef unsigned int rb_event_flag_t; typedef void (*rb_event_hook_func_t)(rb_event_flag_t, VALUE data, VALUE, ID, VALUE klass); @@ -371,12 +372,10 @@ typedef struct { VALUE *dfp; /* cfp[7] / block[2] */ rb_iseq_t *block_iseq; /* cfp[8] / block[3] */ VALUE proc; /* cfp[9] / block[4] */ - ID callee_id; /* cfp[10] */ - ID method_id; /* cfp[11] saved in special case */ - VALUE method_klass; /* cfp[12] saved in special case */ - VALUE prof_time_self; /* cfp[13] */ - VALUE prof_time_chld; /* cfp[14] */ - VALUE dummy; /* cfp[15] */ + ID method_id; /* cfp[10] saved in special case */ + VALUE method_klass; /* cfp[11] saved in special case */ + VALUE prof_time_self; /* cfp[12] */ + VALUE prof_time_chld; /* cfp[13] */ } rb_control_frame_t; typedef struct { @@ -629,6 +628,7 @@ void yarv_bug(void); VALUE rb_thread_eval(rb_thread_t *th, VALUE iseqval); void rb_enable_interrupt(void); void rb_disable_interrupt(void); +int rb_thread_method_id_and_klass(rb_thread_t *th, ID *idp, VALUE *klassp); VALUE th_eval_body(rb_thread_t *th); VALUE th_set_eval_stack(rb_thread_t *, VALUE iseq); -- cgit v1.2.3