[EXPERIMENTAL: NEED DISCUSS]
* vm_trace.c: add events * :thread_begin - hook at thread beggining. * :thead_end - hook at thread ending. * :b_call - hook at block enter. * :b_return - hook at block leave. This change slow down block invocation. Please try and give us feedback until 2.0 code freeze. * include/ruby/ruby.h: ditto. * compile.c (rb_iseq_compile_node): ditto. * insns.def: ditto. * thread.c: ditto. * vm.c: ditto. * include/ruby/debug.h: add a comment. * test/ruby/test_settracefunc.rb: add a tests. git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@38007 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
This commit is contained in:
parent
2dc5e62545
commit
4db8340398
25
ChangeLog
25
ChangeLog
@ -1,3 +1,28 @@
|
|||||||
|
Fri Nov 30 07:21:33 2012 Koichi Sasada <ko1@atdot.net>
|
||||||
|
|
||||||
|
[EXPERIMENTAL: NEED DISCUSS]
|
||||||
|
* vm_trace.c: add events
|
||||||
|
* :thread_begin - hook at thread beggining.
|
||||||
|
* :thead_end - hook at thread ending.
|
||||||
|
* :b_call - hook at block enter.
|
||||||
|
* :b_return - hook at block leave.
|
||||||
|
This change slow down block invocation.
|
||||||
|
Please try and give us feedback until 2.0 code freeze.
|
||||||
|
|
||||||
|
* include/ruby/ruby.h: ditto.
|
||||||
|
|
||||||
|
* compile.c (rb_iseq_compile_node): ditto.
|
||||||
|
|
||||||
|
* insns.def: ditto.
|
||||||
|
|
||||||
|
* thread.c: ditto.
|
||||||
|
|
||||||
|
* vm.c: ditto.
|
||||||
|
|
||||||
|
* include/ruby/debug.h: add a comment.
|
||||||
|
|
||||||
|
* test/ruby/test_settracefunc.rb: add a tests.
|
||||||
|
|
||||||
Fri Nov 30 06:56:30 2012 Ryan Davis <ryand-ruby@zenspider.com>
|
Fri Nov 30 06:56:30 2012 Ryan Davis <ryand-ruby@zenspider.com>
|
||||||
|
|
||||||
* test/minitest/*: Imported minitest 4.3.2 (r8027)
|
* test/minitest/*: Imported minitest 4.3.2 (r8027)
|
||||||
|
51
compile.c
51
compile.c
@ -475,31 +475,36 @@ rb_iseq_compile_node(VALUE self, NODE *node)
|
|||||||
iseq_set_arguments(iseq, ret, node->nd_args);
|
iseq_set_arguments(iseq, ret, node->nd_args);
|
||||||
|
|
||||||
switch (iseq->type) {
|
switch (iseq->type) {
|
||||||
case ISEQ_TYPE_BLOCK: {
|
case ISEQ_TYPE_BLOCK:
|
||||||
LABEL *start = iseq->compile_data->start_label = NEW_LABEL(0);
|
{
|
||||||
LABEL *end = iseq->compile_data->end_label = NEW_LABEL(0);
|
LABEL *start = iseq->compile_data->start_label = NEW_LABEL(0);
|
||||||
|
LABEL *end = iseq->compile_data->end_label = NEW_LABEL(0);
|
||||||
|
|
||||||
ADD_LABEL(ret, start);
|
ADD_LABEL(ret, start);
|
||||||
COMPILE(ret, "block body", node->nd_body);
|
ADD_TRACE(ret, FIX2INT(iseq->location.first_lineno), RUBY_EVENT_B_CALL);
|
||||||
ADD_LABEL(ret, end);
|
COMPILE(ret, "block body", node->nd_body);
|
||||||
|
ADD_TRACE(ret, nd_line(node), RUBY_EVENT_B_RETURN);
|
||||||
|
ADD_LABEL(ret, end);
|
||||||
|
|
||||||
/* wide range catch handler must put at last */
|
/* wide range catch handler must put at last */
|
||||||
ADD_CATCH_ENTRY(CATCH_TYPE_REDO, start, end, 0, start);
|
ADD_CATCH_ENTRY(CATCH_TYPE_REDO, start, end, 0, start);
|
||||||
ADD_CATCH_ENTRY(CATCH_TYPE_NEXT, start, end, 0, end);
|
ADD_CATCH_ENTRY(CATCH_TYPE_NEXT, start, end, 0, end);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case ISEQ_TYPE_CLASS: {
|
case ISEQ_TYPE_CLASS:
|
||||||
ADD_TRACE(ret, FIX2INT(iseq->location.first_lineno), RUBY_EVENT_CLASS);
|
{
|
||||||
COMPILE(ret, "scoped node", node->nd_body);
|
ADD_TRACE(ret, FIX2INT(iseq->location.first_lineno), RUBY_EVENT_CLASS);
|
||||||
ADD_TRACE(ret, nd_line(node), RUBY_EVENT_END);
|
COMPILE(ret, "scoped node", node->nd_body);
|
||||||
break;
|
ADD_TRACE(ret, nd_line(node), RUBY_EVENT_END);
|
||||||
}
|
break;
|
||||||
case ISEQ_TYPE_METHOD: {
|
}
|
||||||
ADD_TRACE(ret, FIX2INT(iseq->location.first_lineno), RUBY_EVENT_CALL);
|
case ISEQ_TYPE_METHOD:
|
||||||
COMPILE(ret, "scoped node", node->nd_body);
|
{
|
||||||
ADD_TRACE(ret, nd_line(node), RUBY_EVENT_RETURN);
|
ADD_TRACE(ret, FIX2INT(iseq->location.first_lineno), RUBY_EVENT_CALL);
|
||||||
break;
|
COMPILE(ret, "scoped node", node->nd_body);
|
||||||
}
|
ADD_TRACE(ret, nd_line(node), RUBY_EVENT_RETURN);
|
||||||
|
break;
|
||||||
|
}
|
||||||
default: {
|
default: {
|
||||||
COMPILE(ret, "scoped node", node->nd_body);
|
COMPILE(ret, "scoped node", node->nd_body);
|
||||||
break;
|
break;
|
||||||
|
@ -38,8 +38,10 @@ VALUE rb_debug_inspector_backtrace_locations(const rb_debug_inspector_t *dc);
|
|||||||
|
|
||||||
/* Old style set_trace_func APIs */
|
/* Old style set_trace_func APIs */
|
||||||
|
|
||||||
|
/* duplicated def of include/ruby/ruby.h */
|
||||||
void rb_add_event_hook(rb_event_hook_func_t func, rb_event_flag_t events, VALUE data);
|
void rb_add_event_hook(rb_event_hook_func_t func, rb_event_flag_t events, VALUE data);
|
||||||
int rb_remove_event_hook(rb_event_hook_func_t func);
|
int rb_remove_event_hook(rb_event_hook_func_t func);
|
||||||
|
|
||||||
int rb_remove_event_hook_with_data(rb_event_hook_func_t func, VALUE data);
|
int rb_remove_event_hook_with_data(rb_event_hook_func_t func, VALUE data);
|
||||||
void rb_thread_add_event_hook(VALUE thval, rb_event_hook_func_t func, rb_event_flag_t events, VALUE data);
|
void rb_thread_add_event_hook(VALUE thval, rb_event_hook_func_t func, rb_event_flag_t events, VALUE data);
|
||||||
int rb_thread_remove_event_hook(VALUE thval, rb_event_hook_func_t func);
|
int rb_thread_remove_event_hook(VALUE thval, rb_event_hook_func_t func);
|
||||||
|
@ -1574,6 +1574,13 @@ int ruby_native_thread_p(void);
|
|||||||
#define RUBY_EVENT_SWITCH 0x20000
|
#define RUBY_EVENT_SWITCH 0x20000
|
||||||
#define RUBY_EVENT_COVERAGE 0x40000
|
#define RUBY_EVENT_COVERAGE 0x40000
|
||||||
|
|
||||||
|
/* 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
|
||||||
|
|
||||||
typedef unsigned int rb_event_flag_t;
|
typedef unsigned int rb_event_flag_t;
|
||||||
typedef void (*rb_event_hook_func_t)(rb_event_flag_t evflag, VALUE data, VALUE self, ID mid, VALUE klass);
|
typedef void (*rb_event_hook_func_t)(rb_event_flag_t evflag, VALUE data, VALUE self, ID mid, VALUE klass);
|
||||||
|
|
||||||
|
@ -871,8 +871,9 @@ trace
|
|||||||
rb_sourceline());
|
rb_sourceline());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
EXEC_EVENT_HOOK(th, flag, GET_SELF(), 0, 0 /* id and klass are resolved at callee */,
|
EXEC_EVENT_HOOK(th, flag, GET_SELF(), 0, 0 /* id and klass are resolved at callee */,
|
||||||
flag & RUBY_EVENT_RETURN ? TOPN(0) : Qundef);
|
(flag & RUBY_EVENT_RETURN | RUBY_EVENT_B_RETURN) ? TOPN(0) : Qundef);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**********************************************************/
|
/**********************************************************/
|
||||||
|
@ -532,9 +532,14 @@ class TestSetTraceFunc < Test::Unit::TestCase
|
|||||||
end
|
end
|
||||||
|
|
||||||
def test_tracepoint
|
def test_tracepoint
|
||||||
events1, answer_events = *trace_by_tracepoint()
|
events1, answer_events = *trace_by_tracepoint(:line, :class, :end, :call, :return, :c_call, :c_return, :raise)
|
||||||
|
|
||||||
mesg = events1.map{|e|
|
mesg = events1.map{|e|
|
||||||
|
if false
|
||||||
|
p [:event, e[0]]
|
||||||
|
p [:line_file, e[1], e[2]]
|
||||||
|
p [:id, e[4]]
|
||||||
|
end
|
||||||
"#{e[0]} - #{e[2]}:#{e[1]} id: #{e[4]}"
|
"#{e[0]} - #{e[2]}:#{e[1]} id: #{e[4]}"
|
||||||
}.join("\n")
|
}.join("\n")
|
||||||
answer_events.zip(events1){|answer, event|
|
answer_events.zip(events1){|answer, event|
|
||||||
@ -682,4 +687,54 @@ class TestSetTraceFunc < Test::Unit::TestCase
|
|||||||
end
|
end
|
||||||
}
|
}
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def method_for_test_tracepoint_block
|
||||||
|
yield
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_tracepoint_block
|
||||||
|
events = []
|
||||||
|
TracePoint.new(:call, :return, :c_call, :b_call, :c_return, :b_return){|tp|
|
||||||
|
events << [
|
||||||
|
tp.event, tp.method_id, tp.defined_class, tp.self.class,
|
||||||
|
/return/ =~ tp.event ? tp.return_value : nil
|
||||||
|
]
|
||||||
|
}.enable{
|
||||||
|
1.times{
|
||||||
|
3
|
||||||
|
}
|
||||||
|
method_for_test_tracepoint_block{
|
||||||
|
4
|
||||||
|
}
|
||||||
|
}
|
||||||
|
# pp events
|
||||||
|
expected_events =
|
||||||
|
[[:b_call, :test_tracepoint_block, TestSetTraceFunc, TestSetTraceFunc, nil],
|
||||||
|
[:c_call, :times, Integer, Fixnum, nil],
|
||||||
|
[:b_call, :test_tracepoint_block, TestSetTraceFunc, TestSetTraceFunc, nil],
|
||||||
|
[:b_return, :test_tracepoint_block, TestSetTraceFunc, TestSetTraceFunc, 3],
|
||||||
|
[:c_return, :times, Integer, Fixnum, 1],
|
||||||
|
[:call, :method_for_test_tracepoint_block, TestSetTraceFunc, TestSetTraceFunc, nil],
|
||||||
|
[:b_call, :test_tracepoint_block, TestSetTraceFunc, TestSetTraceFunc, nil],
|
||||||
|
[:b_return, :test_tracepoint_block, TestSetTraceFunc, TestSetTraceFunc, 4],
|
||||||
|
[:return, :method_for_test_tracepoint_block, TestSetTraceFunc, TestSetTraceFunc, 4],
|
||||||
|
[:b_return, :test_tracepoint_block, TestSetTraceFunc, TestSetTraceFunc, 4]
|
||||||
|
].zip(events){|expected, actual|
|
||||||
|
assert_equal(expected, actual)
|
||||||
|
}
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_tracepoint_thread
|
||||||
|
events = []
|
||||||
|
created_thread = nil
|
||||||
|
TracePoint.new(:thread_begin, :thread_end){|tp|
|
||||||
|
events << [Thread.current, tp.event, tp.self]
|
||||||
|
}.enable{
|
||||||
|
created_thread = Thread.new{}
|
||||||
|
created_thread.join
|
||||||
|
}
|
||||||
|
assert_equal([created_thread, :thread_begin, self], events[0])
|
||||||
|
assert_equal([created_thread, :thread_end, self], events[1])
|
||||||
|
assert_equal(2, events.size)
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
5
thread.c
5
thread.c
@ -478,8 +478,9 @@ thread_start_func_2(rb_thread_t *th, VALUE *stack_start, VALUE *register_stack_s
|
|||||||
th->errinfo = Qnil;
|
th->errinfo = Qnil;
|
||||||
th->root_lep = rb_vm_ep_local_ep(proc->block.ep);
|
th->root_lep = rb_vm_ep_local_ep(proc->block.ep);
|
||||||
th->root_svar = Qnil;
|
th->root_svar = Qnil;
|
||||||
th->value = rb_vm_invoke_proc(th, proc,
|
EXEC_EVENT_HOOK(th, RUBY_EVENT_THREAD_BEGIN, proc->block.self, 0, 0, th->self);
|
||||||
(int)RARRAY_LEN(args), RARRAY_PTR(args), 0);
|
th->value = rb_vm_invoke_proc(th, proc, (int)RARRAY_LEN(args), RARRAY_PTR(args), 0);
|
||||||
|
EXEC_EVENT_HOOK(th, RUBY_EVENT_THREAD_END, proc->block.self, 0, 0, th->self);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
th->value = (*th->first_func)((void *)args);
|
th->value = (*th->first_func)((void *)args);
|
||||||
|
3
vm.c
3
vm.c
@ -1353,6 +1353,9 @@ vm_exec(rb_thread_t *th)
|
|||||||
RUBY_DTRACE_METHOD_RETURN_HOOK(th, 0, 0)
|
RUBY_DTRACE_METHOD_RETURN_HOOK(th, 0, 0)
|
||||||
EXEC_EVENT_HOOK(th, RUBY_EVENT_RETURN, th->cfp->self, 0, 0, Qnil);
|
EXEC_EVENT_HOOK(th, RUBY_EVENT_RETURN, th->cfp->self, 0, 0, Qnil);
|
||||||
break;
|
break;
|
||||||
|
case VM_FRAME_MAGIC_BLOCK:
|
||||||
|
EXEC_EVENT_HOOK(th, RUBY_EVENT_B_RETURN, th->cfp->self, 0, 0, Qnil);
|
||||||
|
break;
|
||||||
case VM_FRAME_MAGIC_CLASS:
|
case VM_FRAME_MAGIC_CLASS:
|
||||||
EXEC_EVENT_HOOK(th, RUBY_EVENT_END, th->cfp->self, 0, 0, Qnil);
|
EXEC_EVENT_HOOK(th, RUBY_EVENT_END, th->cfp->self, 0, 0, Qnil);
|
||||||
break;
|
break;
|
||||||
|
12
vm_trace.c
12
vm_trace.c
@ -507,6 +507,10 @@ get_event_id(rb_event_flag_t event)
|
|||||||
C(c_call, C_CALL);
|
C(c_call, C_CALL);
|
||||||
C(c_return, C_RETURN);
|
C(c_return, C_RETURN);
|
||||||
C(raise, RAISE);
|
C(raise, RAISE);
|
||||||
|
C(b_call, B_CALL);
|
||||||
|
C(b_return, B_RETURN);
|
||||||
|
C(thread_begin, THREAD_BEGIN);
|
||||||
|
C(thread_end, THREAD_END);
|
||||||
#undef C
|
#undef C
|
||||||
default:
|
default:
|
||||||
return 0;
|
return 0;
|
||||||
@ -610,6 +614,10 @@ symbol2event_flag(VALUE v)
|
|||||||
C(c_call, C_CALL);
|
C(c_call, C_CALL);
|
||||||
C(c_return, C_RETURN);
|
C(c_return, C_RETURN);
|
||||||
C(raise, RAISE);
|
C(raise, RAISE);
|
||||||
|
C(b_call, B_CALL);
|
||||||
|
C(b_return, B_RETURN);
|
||||||
|
C(thread_begin, THREAD_BEGIN);
|
||||||
|
C(thread_end, THREAD_END);
|
||||||
#undef C
|
#undef C
|
||||||
rb_raise(rb_eArgError, "unknown event: %s", rb_id2name(SYM2ID(sym)));
|
rb_raise(rb_eArgError, "unknown event: %s", rb_id2name(SYM2ID(sym)));
|
||||||
}
|
}
|
||||||
@ -736,7 +744,7 @@ rb_tracearg_self(rb_trace_arg_t *trace_arg)
|
|||||||
VALUE
|
VALUE
|
||||||
rb_tracearg_return_value(rb_trace_arg_t *trace_arg)
|
rb_tracearg_return_value(rb_trace_arg_t *trace_arg)
|
||||||
{
|
{
|
||||||
if (trace_arg->event & (RUBY_EVENT_RETURN | RUBY_EVENT_C_RETURN)) {
|
if (trace_arg->event & (RUBY_EVENT_RETURN | RUBY_EVENT_C_RETURN | RUBY_EVENT_B_RETURN)) {
|
||||||
/* ok */
|
/* ok */
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
@ -975,7 +983,7 @@ tracepoint_new_s(int argc, VALUE *argv, VALUE self)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
events = RUBY_EVENT_ALL;
|
events = RUBY_EVENT_TRACEPOINT_ALL;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!rb_block_given_p()) {
|
if (!rb_block_given_p()) {
|
||||||
|
Loading…
x
Reference in New Issue
Block a user