aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authortenderlove <tenderlove@b2dd03c8-39d4-4d8f-98ff-823fe69b080e>2012-12-01 02:13:06 +0000
committertenderlove <tenderlove@b2dd03c8-39d4-4d8f-98ff-823fe69b080e>2012-12-01 02:13:06 +0000
commitafb02bbe92e55f877d50ed8705c95a41d541458d (patch)
tree8012de32b7703a09be9d25ecfa1915990f1679a4
parentd3c6187a4d968549b689757bb360e482bd881e07 (diff)
downloadruby-afb02bbe92e55f877d50ed8705c95a41d541458d.tar.gz
* variable.c (rb_class_path_no_cache): add a function to get the class
path without caching the computed path. Some classes are frozen, and will raise an exception without this. * probes.d (cmethod-entry, cmethod-return): separate cmethods from regular methods to match set trace func. * probes_helper.h: refactor macros. Fix probes to avoid calling #inspect when profiling. * insns.def: update for use with new macros. * vm_eval.c: ditto * vm_insnhelper.c: ditto * test/dtrace/test_singleton_function.rb: fix test for new output. * test/dtrace/test_cmethod.rb: test the cmethod probes. git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@38099 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
-rw-r--r--ChangeLog22
-rw-r--r--insns.def44
-rw-r--r--probes.d3
-rw-r--r--probes_helper.h71
-rw-r--r--test/dtrace/test_cmethod.rb49
-rw-r--r--test/dtrace/test_singleton_function.rb4
-rw-r--r--variable.c34
-rw-r--r--vm_eval.c10
-rw-r--r--vm_insnhelper.c10
9 files changed, 178 insertions, 69 deletions
diff --git a/ChangeLog b/ChangeLog
index 252d6d4a7d..2c9d962809 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,25 @@
+Sat Dec 1 11:09:12 2012 Aaron Patterson <aaron@tenderlovemaking.com>
+
+ * variable.c (rb_class_path_no_cache): add a function to get the class
+ path without caching the computed path. Some classes are frozen, and
+ will raise an exception without this.
+
+ * probes.d (cmethod-entry, cmethod-return): separate cmethods from
+ regular methods to match set trace func.
+
+ * probes_helper.h: refactor macros. Fix probes to avoid calling
+ #inspect when profiling.
+
+ * insns.def: update for use with new macros.
+
+ * vm_eval.c: ditto
+
+ * vm_insnhelper.c: ditto
+
+ * test/dtrace/test_singleton_function.rb: fix test for new output.
+
+ * test/dtrace/test_cmethod.rb: test the cmethod probes.
+
Sat Dec 1 09:44:16 2012 Eric Hodel <drbrain@segment7.net>
* test/rdoc/test_rdoc_options.rb: Windows drive letters are
diff --git a/insns.def b/insns.def
index e9716f4d0f..c4918961ce 100644
--- a/insns.def
+++ b/insns.def
@@ -843,32 +843,24 @@ trace
{
rb_event_flag_t flag = (rb_event_flag_t)nf;
- if (RUBY_DTRACE_METHOD_ENTRY_ENABLED()) {
- if (flag == RUBY_EVENT_CALL || flag == RUBY_EVENT_C_CALL) {
- VALUE klass;
- ID called_id;
-
- rb_thread_method_id_and_class(th, &called_id, &klass);
-
- RUBY_DTRACE_METHOD_ENTRY(
- RSTRING_PTR(rb_inspect(klass)),
- rb_id2name(called_id),
- rb_sourcefile(),
- rb_sourceline());
- }
- }
- if (RUBY_DTRACE_METHOD_RETURN_ENABLED()) {
- if (flag == RUBY_EVENT_RETURN || flag == RUBY_EVENT_C_RETURN) {
- VALUE klass;
- ID called_id;
-
- rb_thread_method_id_and_class(th, &called_id, &klass);
-
- RUBY_DTRACE_METHOD_RETURN(
- RSTRING_PTR(rb_inspect(klass)),
- rb_id2name(called_id),
- rb_sourcefile(),
- rb_sourceline());
+ if (RUBY_DTRACE_METHOD_ENTRY_ENABLED() ||
+ RUBY_DTRACE_METHOD_RETURN_ENABLED() ||
+ RUBY_DTRACE_CMETHOD_ENTRY_ENABLED() ||
+ RUBY_DTRACE_CMETHOD_RETURN_ENABLED()) {
+
+ switch(flag) {
+ case RUBY_EVENT_CALL:
+ RUBY_DTRACE_METHOD_ENTRY_HOOK(th, 0, 0);
+ break;
+ case RUBY_EVENT_C_CALL:
+ RUBY_DTRACE_CMETHOD_ENTRY_HOOK(th, 0, 0);
+ break;
+ case RUBY_EVENT_RETURN:
+ RUBY_DTRACE_METHOD_RETURN_HOOK(th, 0, 0);
+ break;
+ case RUBY_EVENT_C_RETURN:
+ RUBY_DTRACE_CMETHOD_RETURN_HOOK(th, 0, 0);
+ break;
}
}
diff --git a/probes.d b/probes.d
index 1c5e03f756..591b2f444f 100644
--- a/probes.d
+++ b/probes.d
@@ -4,6 +4,9 @@ provider ruby {
probe method__entry(const char *, const char *, const char *, int);
probe method__return(const char *, const char *, const char *, int);
+ probe cmethod__entry(const char *, const char *, const char *, int);
+ probe cmethod__return(const char *, const char *, const char *, int);
+
probe require__entry(const char *, const char *, int);
probe require__return(const char *);
diff --git a/probes_helper.h b/probes_helper.h
index 7f4beb944f..13bcbdbbda 100644
--- a/probes_helper.h
+++ b/probes_helper.h
@@ -4,23 +4,11 @@
#include "ruby/ruby.h"
#include "probes.h"
-#define RUBY_DTRACE_METHOD_ENTRY_HOOK(klass, id) \
- if (RUBY_DTRACE_METHOD_ENTRY_ENABLED()) { \
- const char * classname = rb_class2name((klass)); \
- const char * methodname = rb_id2name((id)); \
- const char * filename = rb_sourcefile(); \
- if (classname && methodname && filename) { \
- RUBY_DTRACE_METHOD_ENTRY( \
- classname, \
- methodname, \
- filename, \
- rb_sourceline()); \
- } \
- } \
+VALUE rb_class_path_no_cache(VALUE _klass);
-#define RUBY_DTRACE_METHOD_RETURN_HOOK(th, klass, id) \
- if (RUBY_DTRACE_METHOD_RETURN_ENABLED()) { \
- VALUE _klass = (klass); \
+#define RUBY_DTRACE_HOOK(name, th, klazz, id) \
+ if (RUBY_DTRACE_##name##_ENABLED()) { \
+ VALUE _klass = (klazz); \
VALUE _id = (id); \
const char * classname; \
const char * methodname; \
@@ -28,16 +16,49 @@
if (!_klass) { \
rb_thread_method_id_and_class((th), &_id, &_klass); \
} \
- classname = rb_class2name(_klass); \
- methodname = rb_id2name(_id); \
- filename = rb_sourcefile(); \
- if (classname && methodname && filename) { \
- RUBY_DTRACE_METHOD_RETURN( \
- classname, \
- methodname, \
- filename, \
- rb_sourceline()); \
+ if (_klass) { \
+ if (RB_TYPE_P(_klass, T_ICLASS)) { \
+ _klass = RBASIC(_klass)->klass; \
+ } \
+ else if (FL_TEST(_klass, FL_SINGLETON)) { \
+ _klass = rb_iv_get(_klass, "__attached__"); \
+ } \
+ switch(TYPE(_klass)) { \
+ case T_CLASS: \
+ case T_ICLASS: \
+ case T_MODULE: \
+ { \
+ VALUE _name = rb_class_path_no_cache(_klass); \
+ if (!NIL_P(_name)) { \
+ classname = StringValuePtr(_name); \
+ } else { \
+ classname = "<unknown>"; \
+ } \
+ methodname = rb_id2name(_id); \
+ filename = rb_sourcefile(); \
+ if (classname && methodname && filename) { \
+ RUBY_DTRACE_##name( \
+ classname, \
+ methodname, \
+ filename, \
+ rb_sourceline()); \
+ } \
+ break; \
+ } \
+ } \
} \
} \
+#define RUBY_DTRACE_METHOD_ENTRY_HOOK(th, klass, id) \
+ RUBY_DTRACE_HOOK(METHOD_ENTRY, th, klass, id)
+
+#define RUBY_DTRACE_METHOD_RETURN_HOOK(th, klass, id) \
+ RUBY_DTRACE_HOOK(METHOD_RETURN, th, klass, id)
+
+#define RUBY_DTRACE_CMETHOD_ENTRY_HOOK(th, klass, id) \
+ RUBY_DTRACE_HOOK(CMETHOD_ENTRY, th, klass, id)
+
+#define RUBY_DTRACE_CMETHOD_RETURN_HOOK(th, klass, id) \
+ RUBY_DTRACE_HOOK(CMETHOD_RETURN, th, klass, id)
+
#endif /* RUBY_PROBES_HELPER_H */
diff --git a/test/dtrace/test_cmethod.rb b/test/dtrace/test_cmethod.rb
new file mode 100644
index 0000000000..138ec55ab3
--- /dev/null
+++ b/test/dtrace/test_cmethod.rb
@@ -0,0 +1,49 @@
+require 'dtrace/helper'
+
+module DTrace
+ class TestCMethod < TestCase
+ def test_entry
+ probe = <<-eoprobe
+ruby$target:::cmethod-entry
+{
+ printf("%s %s %s %d\\n", copyinstr(arg0), copyinstr(arg1), copyinstr(arg2), arg3);
+}
+ eoprobe
+
+ trap_probe(probe, ruby_program) { |d_file, rb_file, probes|
+ foo_calls = probes.map { |line| line.split }.find_all { |row|
+ row[1] == 'times'
+ }
+
+ assert_equal 1, foo_calls.length
+ }
+ end
+
+ def test_exit
+ probe = <<-eoprobe
+ruby$target:::cmethod-return
+{
+ printf("%s %s %s %d\\n", copyinstr(arg0), copyinstr(arg1), copyinstr(arg2), arg3);
+}
+ eoprobe
+
+ trap_probe(probe, ruby_program) { |d_file, rb_file, probes|
+ foo_calls = probes.map { |line| line.split }.find_all { |row|
+ row[1] == 'times'
+ }
+
+ assert_equal 1, foo_calls.length
+ }
+ end
+
+ def ruby_program
+ <<-eoruby
+ class Foo
+ def self.foo; end
+ end
+ 10.times { Foo.foo }
+ eoruby
+ end
+ end
+end if defined?(DTrace::TestCase)
+
diff --git a/test/dtrace/test_singleton_function.rb b/test/dtrace/test_singleton_function.rb
index 06f070913b..4b5d3d7f18 100644
--- a/test/dtrace/test_singleton_function.rb
+++ b/test/dtrace/test_singleton_function.rb
@@ -13,7 +13,7 @@ ruby$target:::method-entry
trap_probe(probe, ruby_program) { |d_file, rb_file, probes|
foo_calls = probes.map { |line| line.split }.find_all { |row|
- row.first == '#<Class:Foo>' && row[1] == 'foo'
+ row.first == 'Foo' && row[1] == 'foo'
}
assert_equal 10, foo_calls.length
@@ -33,7 +33,7 @@ ruby$target:::method-return
trap_probe(probe, ruby_program) { |d_file, rb_file, probes|
foo_calls = probes.map { |line| line.split }.find_all { |row|
- row.first == '#<Class:Foo>' && row[1] == 'foo'
+ row.first == 'Foo' && row[1] == 'foo'
}
assert_equal 10, foo_calls.length
diff --git a/variable.c b/variable.c
index 601efb955d..ebe532f28a 100644
--- a/variable.c
+++ b/variable.c
@@ -211,8 +211,10 @@ rb_mod_name(VALUE mod)
return path;
}
+typedef VALUE (*path_cache_func)(VALUE obj, ID id, VALUE val);
+
static VALUE
-rb_tmp_class_path(VALUE klass, int *permanent)
+rb_tmp_class_path(VALUE klass, int *permanent, path_cache_func cache_path)
{
VALUE path = classname(klass, permanent);
st_data_t n = (st_data_t)path;
@@ -233,12 +235,17 @@ rb_tmp_class_path(VALUE klass, int *permanent)
s = "Module";
}
else {
- s = rb_class2name(RBASIC(klass)->klass);
+ int perm;
+ VALUE path;
+
+ path = rb_tmp_class_path(RBASIC(klass)->klass, &perm, cache_path);
+ s = RSTRING_PTR(path);
}
}
path = rb_sprintf("#<%s:%p>", s, (void*)klass);
OBJ_FREEZE(path);
- rb_ivar_set(klass, tmp_classpath, path);
+
+ cache_path(klass, tmp_classpath, path);
*permanent = 0;
return path;
@@ -249,7 +256,22 @@ VALUE
rb_class_path(VALUE klass)
{
int permanent;
- VALUE path = rb_tmp_class_path(klass, &permanent);
+ VALUE path = rb_tmp_class_path(klass, &permanent, rb_ivar_set);
+ if (!NIL_P(path)) path = rb_str_dup(path);
+ return path;
+}
+
+static VALUE
+null_cache(VALUE obj, ID id, VALUE val)
+{
+ return Qnil;
+}
+
+VALUE
+rb_class_path_no_cache(VALUE klass)
+{
+ int permanent;
+ VALUE path = rb_tmp_class_path(klass, &permanent, null_cache);
if (!NIL_P(path)) path = rb_str_dup(path);
return path;
}
@@ -265,7 +287,7 @@ rb_set_class_path_string(VALUE klass, VALUE under, VALUE name)
}
else {
int permanent;
- str = rb_str_dup(rb_tmp_class_path(under, &permanent));
+ str = rb_str_dup(rb_tmp_class_path(under, &permanent, rb_ivar_set));
rb_str_cat2(str, "::");
rb_str_append(str, name);
OBJ_FREEZE(str);
@@ -288,7 +310,7 @@ rb_set_class_path(VALUE klass, VALUE under, const char *name)
}
else {
int permanent;
- str = rb_str_dup(rb_tmp_class_path(under, &permanent));
+ str = rb_str_dup(rb_tmp_class_path(under, &permanent, rb_ivar_set));
rb_str_cat2(str, "::");
rb_str_cat2(str, name);
if (!permanent) {
diff --git a/vm_eval.c b/vm_eval.c
index 53c2918d34..f0b0c500e2 100644
--- a/vm_eval.c
+++ b/vm_eval.c
@@ -55,7 +55,7 @@ vm_call0_cfunc(rb_thread_t* th, rb_call_info_t *ci, const VALUE *argv)
{
VALUE val;
- RUBY_DTRACE_METHOD_ENTRY_HOOK(ci->defined_class, ci->mid);
+ RUBY_DTRACE_CMETHOD_ENTRY_HOOK(th, ci->defined_class, ci->mid);
EXEC_EVENT_HOOK(th, RUBY_EVENT_C_CALL, ci->recv, ci->mid, ci->defined_class, Qnil);
{
rb_control_frame_t *reg_cfp = th->cfp;
@@ -85,7 +85,7 @@ vm_call0_cfunc(rb_thread_t* th, rb_call_info_t *ci, const VALUE *argv)
}
}
EXEC_EVENT_HOOK(th, RUBY_EVENT_C_RETURN, ci->recv, ci->mid, ci->defined_class, val);
- RUBY_DTRACE_METHOD_RETURN_HOOK(th, ci->defined_class, ci->mid);
+ RUBY_DTRACE_CMETHOD_RETURN_HOOK(th, ci->defined_class, ci->mid);
return val;
}
@@ -103,7 +103,7 @@ vm_call0_cfunc_with_frame(rb_thread_t* th, rb_call_info_t *ci, const VALUE *argv
ID mid = ci->mid;
rb_block_t *blockptr = ci->blockptr;
- RUBY_DTRACE_METHOD_ENTRY_HOOK(defined_class, mid);
+ RUBY_DTRACE_CMETHOD_ENTRY_HOOK(th, defined_class, mid);
EXEC_EVENT_HOOK(th, RUBY_EVENT_C_CALL, recv, mid, defined_class, Qnil);
{
rb_control_frame_t *reg_cfp = th->cfp;
@@ -123,7 +123,7 @@ vm_call0_cfunc_with_frame(rb_thread_t* th, rb_call_info_t *ci, const VALUE *argv
vm_pop_frame(th);
}
EXEC_EVENT_HOOK(th, RUBY_EVENT_C_RETURN, recv, mid, defined_class, val);
- RUBY_DTRACE_METHOD_RETURN_HOOK(th, defined_class, mid);
+ RUBY_DTRACE_CMETHOD_RETURN_HOOK(th, defined_class, mid);
return val;
}
@@ -1015,7 +1015,7 @@ rb_iterate(VALUE (* it_proc) (VALUE), VALUE data1,
if (UNLIKELY(VM_FRAME_TYPE(th->cfp) == VM_FRAME_MAGIC_CFUNC)) {
const rb_method_entry_t *me = th->cfp->me;
EXEC_EVENT_HOOK(th, RUBY_EVENT_C_RETURN, th->cfp->self, me->called_id, me->klass, Qnil);
- RUBY_DTRACE_METHOD_RETURN_HOOK(th, me->klass, me->called_id);
+ RUBY_DTRACE_CMETHOD_RETURN_HOOK(th, me->klass, me->called_id);
}
th->cfp = RUBY_VM_PREVIOUS_CONTROL_FRAME(th->cfp);
diff --git a/vm_insnhelper.c b/vm_insnhelper.c
index c40f66bbe9..75da83e525 100644
--- a/vm_insnhelper.c
+++ b/vm_insnhelper.c
@@ -1449,7 +1449,7 @@ vm_call_cfunc_with_frame(rb_thread_t *th, rb_control_frame_t *reg_cfp, rb_call_i
rb_block_t *blockptr = ci->blockptr;
int argc = ci->argc;
- RUBY_DTRACE_METHOD_ENTRY_HOOK(me->klass, me->called_id);
+ RUBY_DTRACE_CMETHOD_ENTRY_HOOK(th, me->klass, me->called_id);
EXEC_EVENT_HOOK(th, RUBY_EVENT_C_CALL, recv, me->called_id, me->klass, Qundef);
vm_push_frame(th, 0, VM_FRAME_MAGIC_CFUNC, recv, defined_class,
@@ -1468,7 +1468,7 @@ vm_call_cfunc_with_frame(rb_thread_t *th, rb_control_frame_t *reg_cfp, rb_call_i
vm_pop_frame(th);
EXEC_EVENT_HOOK(th, RUBY_EVENT_C_RETURN, recv, me->called_id, me->klass, val);
- RUBY_DTRACE_METHOD_RETURN_HOOK(th, me->klass, me->called_id);
+ RUBY_DTRACE_CMETHOD_RETURN_HOOK(th, me->klass, me->called_id);
return val;
}
@@ -1516,7 +1516,7 @@ vm_call_cfunc(rb_thread_t *th, rb_control_frame_t *reg_cfp, rb_call_info_t *ci)
if (len >= 0) rb_check_arity(ci->argc, len, len);
- RUBY_DTRACE_METHOD_ENTRY_HOOK(me->klass, me->called_id);
+ RUBY_DTRACE_CMETHOD_ENTRY_HOOK(th, me->klass, me->called_id);
EXEC_EVENT_HOOK(th, RUBY_EVENT_C_CALL, recv, me->called_id, me->klass, Qnil);
if (!(ci->me->flag & NOEX_PROTECTED) &&
@@ -1526,7 +1526,7 @@ vm_call_cfunc(rb_thread_t *th, rb_control_frame_t *reg_cfp, rb_call_info_t *ci)
val = vm_call_cfunc_latter(th, reg_cfp, ci);
EXEC_EVENT_HOOK(th, RUBY_EVENT_C_RETURN, recv, me->called_id, me->klass, val);
- RUBY_DTRACE_METHOD_RETURN_HOOK(th, me->klass, me->called_id);
+ RUBY_DTRACE_CMETHOD_RETURN_HOOK(th, me->klass, me->called_id);
return val;
}
@@ -1575,7 +1575,7 @@ vm_call_bmethod_body(rb_thread_t *th, rb_call_info_t *ci, const VALUE *argv)
rb_proc_t *proc;
VALUE val;
- RUBY_DTRACE_METHOD_ENTRY_HOOK(ci->me->klass, ci->me->called_id);
+ RUBY_DTRACE_METHOD_ENTRY_HOOK(th, ci->me->klass, ci->me->called_id);
EXEC_EVENT_HOOK(th, RUBY_EVENT_CALL, ci->recv, ci->me->called_id, ci->me->klass, Qnil);
/* control block frame */