Skip to content

Instantly share code, notes, and snippets.

@tiegz
Created August 3, 2012 18:15
Show Gist options
  • Save tiegz/3250123 to your computer and use it in GitHub Desktop.
Save tiegz/3250123 to your computer and use it in GitHub Desktop.
DTrace probes for ruby 1.9.3-HEAD

What?

This is a starting point to get something similar to memprof running in ruby 1.9. So far it adds DTrace probes to ruby 1.9.3, which we output and parse at some point later.

This will generate 2 types of probes so far:

  • RUBY_OBJ_NEW(): capture the file, line and type of a newly allocated object.
  • RUBY_CALL(): capture the function name of every function called. 😱

Partly inspired by this blog post: http://tenderlovemaking.com/2011/06/29/i-want-dtrace-probes-in-ruby.html

Installation w/rvm

curl https://raw.github.com/gist/3250123/dtrace_ruby_193_head.diff > dtrace_probes_ruby193.diff
curl https://raw.github.com/gist/3250123/obj_new.rb > obj_new.rb
rvm reinstall --patch ./dtrace_probes_ruby193.diff ruby-1.9.3-head
rvm use 1.9.3-head

Usage

One-liner example with RUBY_OBJ_NEW:

sudo dtrace -n ruby*:::obj-new'{ printf("%s:%d:%d", copyinstr(arg0), arg1, arg2); }' -c 'ruby obj_new.rb'
diff --git a/Makefile.in b/Makefile.in
index b0f4434..14c87fa 100644
--- a/Makefile.in
+++ b/Makefile.in
@@ -152,7 +152,7 @@ MESSAGE_END = ; do echo "$$line"; done
configure_args = @configure_args@
#### End of variables
-all:
+all: probes.h
.DEFAULT: all
@@ -298,6 +298,10 @@ enc/unicode/name2ctype.h: enc/unicode/name2ctype.kwd
@$(ECHO) preprocessing $<
$(Q) $(CPP) $(XCFLAGS) $(CPPFLAGS) $(COUTFLAG)$@ -E $< > $@
+probes.h:
+ @$(ECHO) building probes.h $<
+ dtrace -o $@ -h -s probes.d
+
clean-local::
$(Q)$(RM) ext/extinit.c ext/extinit.$(OBJEXT) ext/ripper/y.output
-$(Q)$(RM) $(pkgconfig_DATA)
diff --git a/array.c b/array.c
index 64647c3..855f1a5 100644
--- a/array.c
+++ b/array.c
@@ -16,6 +16,7 @@
#include "ruby/st.h"
#include "ruby/encoding.h"
#include "internal.h"
+#include "probes.h"
#ifndef ARRAY_DEBUG
# define NDEBUG
@@ -302,6 +303,9 @@ ary_alloc(VALUE klass)
OBJSETUP(ary, klass, T_ARRAY);
FL_SET_EMBED((VALUE)ary);
ARY_SET_EMBED_LEN((VALUE)ary, 0);
+ if(RUBY_OBJ_NEW_ENABLED()) {
+ RUBY_OBJ_NEW(rb_sourcefile(), rb_sourceline(), T_ARRAY);
+ }
return (VALUE)ary;
}
diff --git a/bignum.c b/bignum.c
index 0439062..1aa3ff6 100644
--- a/bignum.c
+++ b/bignum.c
@@ -11,6 +11,7 @@
#include "ruby/ruby.h"
#include "ruby/util.h"
+#include "probes.h"
#include "internal.h"
#ifdef HAVE_STRINGS_H
@@ -177,6 +178,10 @@ bignew_1(VALUE klass, long len, int sign)
RBIGNUM(big)->as.heap.len = len;
}
+ if(RUBY_OBJ_NEW_ENABLED()) {
+ RUBY_OBJ_NEW(rb_sourcefile(), rb_sourceline(), T_BIGNUM);
+ }
+
return (VALUE)big;
}
diff --git a/class.c b/class.c
index df19812..c8db242 100644
--- a/class.c
+++ b/class.c
@@ -30,6 +30,7 @@
#include "vm_core.h"
#include "internal.h"
#include <ctype.h>
+#include "probes.h"
extern st_table *rb_class_tbl;
static ID id_attached;
@@ -58,6 +59,9 @@ class_alloc(VALUE flags, VALUE klass)
RCLASS_M_TBL(obj) = 0;
RCLASS_SUPER(obj) = 0;
RCLASS_IV_INDEX_TBL(obj) = 0;
+ if(RUBY_OBJ_NEW_ENABLED()) {
+ RUBY_OBJ_NEW(rb_sourcefile(), rb_sourceline(), flags);
+ }
return (VALUE)obj;
}
diff --git a/complex.c b/complex.c
index 5b1a510..996e4e9 100644
--- a/complex.c
+++ b/complex.c
@@ -7,6 +7,7 @@
#include "ruby.h"
#include "internal.h"
+#include "probes.h"
#include <math.h>
#define NDEBUG
@@ -318,6 +319,10 @@ nucomp_s_new_internal(VALUE klass, VALUE real, VALUE imag)
obj->real = real;
obj->imag = imag;
+ if(RUBY_OBJ_NEW_ENABLED()) {
+ RUBY_OBJ_NEW(rb_sourcefile(), rb_sourceline(), T_COMPLEX);
+ }
+
return (VALUE)obj;
}
diff --git a/gc.c b/gc.c
index e65d0ec..18fb0d9 100644
--- a/gc.c
+++ b/gc.c
@@ -19,6 +19,7 @@
#include "eval_intern.h"
#include "vm_core.h"
#include "internal.h"
+#include "probes.h"
#include "gc.h"
#include "constant.h"
#include <stdio.h>
@@ -1224,6 +1225,11 @@ rb_data_object_alloc(VALUE klass, void *datap, RUBY_DATA_FUNC dmark, RUBY_DATA_F
data->dfree = dfree;
data->dmark = dmark;
+ if(RUBY_OBJ_NEW_ENABLED()) {
+ /*const char *file = rb_sourcefile();*/
+ RUBY_OBJ_NEW(rb_sourcefile(), rb_sourceline(), T_DATA);
+ }
+
return (VALUE)data;
}
diff --git a/hash.c b/hash.c
index fbd8237..73a8d80 100644
--- a/hash.c
+++ b/hash.c
@@ -15,6 +15,7 @@
#include "ruby/st.h"
#include "ruby/util.h"
#include "ruby/encoding.h"
+#include "probes.h"
#include <errno.h>
#ifdef __APPLE__
@@ -222,6 +223,10 @@ hash_alloc(VALUE klass)
RHASH_IFNONE(hash) = Qnil;
+ if(RUBY_OBJ_NEW_ENABLED()) {
+ RUBY_OBJ_NEW(rb_sourcefile(), rb_sourceline(), T_HASH);
+ }
+
return (VALUE)hash;
}
diff --git a/io.c b/io.c
index bb75ece..14b7d4a 100644
--- a/io.c
+++ b/io.c
@@ -15,6 +15,7 @@
#include "ruby/io.h"
#include "dln.h"
#include "internal.h"
+#include "probes.h"
#include <ctype.h>
#include <errno.h>
@@ -682,6 +683,10 @@ io_alloc(VALUE klass)
io->fptr = 0;
+ if(RUBY_OBJ_NEW_ENABLED()) {
+ RUBY_OBJ_NEW(rb_sourcefile(), rb_sourceline(), T_FILE);
+ }
+
return (VALUE)io;
}
diff --git a/numeric.c b/numeric.c
index 497b93b..f0ac855 100644
--- a/numeric.c
+++ b/numeric.c
@@ -12,6 +12,7 @@
#include "ruby/ruby.h"
#include "ruby/encoding.h"
#include "ruby/util.h"
+#include "probes.h"
#include "internal.h"
#include <ctype.h>
#include <math.h>
@@ -585,6 +586,9 @@ rb_float_new(double d)
OBJSETUP(flt, rb_cFloat, T_FLOAT);
flt->float_value = d;
+ if(RUBY_OBJ_NEW_ENABLED()) {
+ RUBY_OBJ_NEW(rb_sourcefile(), rb_sourceline(), T_FLOAT);
+ }
return (VALUE)flt;
}
diff --git a/object.c b/object.c
index f45e013..7e1b1d7 100644
--- a/object.c
+++ b/object.c
@@ -21,6 +21,7 @@
#include <float.h>
#include "constant.h"
#include "internal.h"
+#include "probes.h"
VALUE rb_cBasicObject;
VALUE rb_mKernel;
@@ -1612,6 +1613,9 @@ rb_class_allocate_instance(VALUE klass)
{
NEWOBJ(obj, struct RObject);
OBJSETUP(obj, klass, T_OBJECT);
+ if(RUBY_OBJ_NEW_ENABLED()) {
+ RUBY_OBJ_NEW(rb_sourcefile(), rb_sourceline(), T_OBJECT);
+ }
return (VALUE)obj;
}
diff --git a/probes.d b/probes.d
new file mode 100644
index 0000000..ba0a616
--- /dev/null
+++ b/probes.d
@@ -0,0 +1,4 @@
+provider ruby {
+ probe obj__new(const char *, int, long);
+ probe call(const char *);
+};
\ No newline at end of file
diff --git a/rational.c b/rational.c
index 8aced2a..c5cffcb 100644
--- a/rational.c
+++ b/rational.c
@@ -7,6 +7,7 @@
#include "ruby.h"
#include "internal.h"
+#include "probes.h"
#include <math.h>
#include <float.h>
@@ -354,6 +355,9 @@ nurat_s_new_internal(VALUE klass, VALUE num, VALUE den)
obj->num = num;
obj->den = den;
+ if(RUBY_OBJ_NEW_ENABLED()) {
+ RUBY_OBJ_NEW(rb_sourcefile(), rb_sourceline(), T_RATIONAL);
+ }
return (VALUE)obj;
}
diff --git a/re.c b/re.c
index 9fdbf54..4b22b5e 100644
--- a/re.c
+++ b/re.c
@@ -15,6 +15,7 @@
#include "ruby/util.h"
#include "internal.h"
#include "regint.h"
+#include "probes.h"
#include <ctype.h>
VALUE rb_eRegexpError;
@@ -835,6 +836,9 @@ match_alloc(VALUE klass)
match->rmatch = ALLOC(struct rmatch);
MEMZERO(match->rmatch, struct rmatch, 1);
+ if(RUBY_OBJ_NEW_ENABLED()) {
+ RUBY_OBJ_NEW(rb_sourcefile(), rb_sourceline(), T_MATCH);
+ }
return (VALUE)match;
}
diff --git a/string.c b/string.c
index fd240bc..93f6d2f 100644
--- a/string.c
+++ b/string.c
@@ -14,6 +14,7 @@
#include "ruby/ruby.h"
#include "ruby/re.h"
#include "ruby/encoding.h"
+#include "probes.h"
#include "internal.h"
#include <assert.h>
@@ -377,6 +378,10 @@ str_alloc(VALUE klass)
str->as.heap.len = 0;
str->as.heap.aux.capa = 0;
+ if(RUBY_OBJ_NEW_ENABLED()) {
+ RUBY_OBJ_NEW(rb_sourcefile(), rb_sourceline(), T_STRING);
+ }
+
return (VALUE)str;
}
diff --git a/struct.c b/struct.c
index 136ba0a..cbd196f 100644
--- a/struct.c
+++ b/struct.c
@@ -11,6 +11,7 @@
#include "ruby/ruby.h"
#include "internal.h"
+#include "probes.h"
VALUE rb_cStruct;
static ID id_members;
@@ -408,6 +409,9 @@ struct_alloc(VALUE klass)
st->as.heap.len = n;
}
+ if(RUBY_OBJ_NEW_ENABLED()) {
+ RUBY_OBJ_NEW(rb_sourcefile(), rb_sourceline(), T_STRUCT);
+ }
return (VALUE)st;
}
diff --git a/vm.c b/vm.c
index 3d7b76e..f056305 100644
--- a/vm.c
+++ b/vm.c
@@ -13,6 +13,7 @@
#include "ruby/st.h"
#include "ruby/encoding.h"
#include "internal.h"
+#include "probes.h"
#include "gc.h"
#include "vm_core.h"
diff --git a/vm_eval.c b/vm_eval.c
index 6f2da3e..87c2e61 100644
--- a/vm_eval.c
+++ b/vm_eval.c
@@ -453,6 +453,11 @@ rb_method_call_status(rb_thread_t *th, const rb_method_entry_t *me, call_type sc
static inline VALUE
rb_call(VALUE recv, ID mid, int argc, const VALUE *argv, call_type scope)
{
+ if(RUBY_CALL_ENABLED()) {
+ const char *name = rb_id2name(mid);
+ RUBY_CALL(name);
+ }
+
return rb_call0(recv, mid, argc, argv, scope, Qundef);
}
output = {
:float => "Creating a Float",
:array => "Creating an Array",
:hash => "Creating a Hash",
:class => "Creating a Class",
:module => "Creating a Module",
:regexp => "Creating a Regexp"
}
puts "Demo'ing DTrace probes on Ruby"
sleep 2
puts output[:float]
1.to_f
sleep 2
puts output[:array]
Array.new
sleep 2
puts output[:hash]
Hash.new
sleep 2
puts output[:class]
Class.new
sleep 2
puts output[:module]
Module.new
sleep 2
puts output[:regexp]
Regexp.new("match this")
sleep 2
@tiegz
Copy link
Author

tiegz commented Aug 3, 2012

Installation w/rvm

curl https://raw.github.com/gist/3250123 > dtrace_probes_ruby193.diff
rvm reinstall --patch ./dtrace_probes_ruby193.diff

Usage

TODO

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment