Skip to content

Instantly share code, notes, and snippets.

@tmm1
Created March 27, 2009 20:56
Show Gist options
  • Save tmm1/86895 to your computer and use it in GitHub Desktop.
Save tmm1/86895 to your computer and use it in GitHub Desktop.
commit 7fba8f5e4978b2ff990304f7150918f1cc0eea74
Author: Aman Gupta <aman@tmm1.net>
Date: Fri Mar 27 13:51:30 2009 -0700
dtrace patch for 1.8.7 (run autoconf, then ./configure --disable-pthread --enable-dtrace --prefix=/opt/ruby-dtrace)
diff --git a/Makefile.in b/Makefile.in
index a37bcf6..604bfed 100644
--- a/Makefile.in
+++ b/Makefile.in
@@ -89,6 +89,9 @@ ASFLAGS = @ASFLAGS@
OBJEXT = @OBJEXT@
MANTYPE = @MANTYPE@
+DTRACE_OBJS = @DTRACE_OBJS@
+DTRACE_HEADER = @DTRACE_HEADER@
+
INSTALLED_LIST= .installed.list
#### End of variables
@@ -101,11 +104,11 @@ all:
miniruby$(EXEEXT):
@$(RM) $@
- $(PURIFY) $(CC) $(LDFLAGS) $(XLDFLAGS) $(MAINLIBS) $(MAINOBJ) $(MINIOBJS) $(LIBRUBY_A) $(LIBS) $(OUTFLAG)$@
+ $(PURIFY) $(CC) $(LDFLAGS) $(XLDFLAGS) $(MAINLIBS) $(MAINOBJ) $(MINIOBJS) $(LIBRUBY_A) $(DTRACE_OBJS) $(LIBS) $(OUTFLAG)$@
$(PROGRAM):
@$(RM) $@
- $(PURIFY) $(CC) $(LDFLAGS) $(XLDFLAGS) $(MAINLIBS) $(MAINOBJ) $(EXTOBJS) $(LIBRUBYARG) $(LIBS) $(OUTFLAG)$@
+ $(PURIFY) $(CC) $(LDFLAGS) $(XLDFLAGS) $(MAINLIBS) $(MAINOBJ) $(EXTOBJS) $(LIBRUBYARG) $(DTRACE_OBJS) $(LIBS) $(OUTFLAG)$@
# We must `rm' the library each time this rule is invoked because "updating" a
# MAB library on Apple/NeXT (see --enable-fat-binary in configure) is not
@@ -117,7 +120,7 @@ $(LIBRUBY_A):
$(LIBRUBY_SO):
@-$(PRE_LIBRUBY_UPDATE)
- $(LDSHARED) $(DLDFLAGS) $(OBJS) $(DLDOBJS) $(SOLIBS) $(OUTFLAG)$@
+ $(LDSHARED) $(DLDFLAGS) $(OBJS) $(DLDOBJS) $(DTRACE_OBJS) $(SOLIBS) $(OUTFLAG)$@
@-$(MINIRUBY) -e 'ARGV.each{|link| File.delete link if File.exist? link; \
File.symlink "$(LIBRUBY_SO)", link}' \
$(LIBRUBY_ALIASES) || true
@@ -185,6 +188,9 @@ distclean-local::
ext/extinit.$(OBJEXT): ext/extinit.c $(SETUP)
$(CC) $(CFLAGS) $(XCFLAGS) $(CPPFLAGS) $(OUTFLAG)$@ -c ext/extinit.c
+$(DTRACE_HEADER): dtrace.d $(OBJS)
+ /usr/sbin/dtrace -h -s dtrace.d
+
update-rubyspec:
if [ -d $(srcdir)/rubyspec ]; then \
cd $(srcdir)/rubyspec/mspec; \
diff --git a/common.mk b/common.mk
index bf49aad..1ab3afc 100644
--- a/common.mk
+++ b/common.mk
@@ -55,6 +55,7 @@ OBJS = array.$(OBJEXT) \
string.$(OBJEXT) \
struct.$(OBJEXT) \
time.$(OBJEXT) \
+ tracer.$(OBJEXT) \
util.$(OBJEXT) \
variable.$(OBJEXT) \
version.$(OBJEXT) \
@@ -84,9 +85,11 @@ prog: $(PROGRAM) $(WPROGRAM)
miniruby$(EXEEXT): config.status $(LIBRUBY_A) $(MAINOBJ) $(MINIOBJS) $(OBJS) $(DMYEXT)
-$(PROGRAM): $(LIBRUBY) $(MAINOBJ) $(OBJS) $(EXTOBJS) $(SETUP) $(PREP)
+$(PROGRAM): $(LIBRUBY) $(MAINOBJ) $(OBJS) $(EXTOBJS) $(DTRACE_OBJS) $(SETUP) $(PREP)
-$(LIBRUBY_A): $(OBJS) $(DMYEXT) $(ARCHFILE)
+$(LIBRUBY_A): $(OBJS) $(DMYEXT) $(ARCHFILE) $(DTRACE_OBJS)
+
+$(OBJS): $(DTRACE_HEADER)
$(LIBRUBY_SO): $(OBJS) $(DLDOBJS) $(LIBRUBY_A) $(PREP) $(LIBRUBY_SO_UPDATE)
@@ -279,7 +282,7 @@ clear-installed-list:
clean: clean-ext clean-local
clean-local::
- @$(RM) $(OBJS) $(MINIOBJS) $(MAINOBJ) $(LIBRUBY_A) $(LIBRUBY_SO) $(LIBRUBY) $(LIBRUBY_ALIASES)
+ @$(RM) $(OBJS) $(DTRACE_HEADER) $(DTRACE_OBJS) $(MINIOBJS) $(MAINOBJ) $(LIBRUBY_A) $(LIBRUBY_SO) $(LIBRUBY) $(LIBRUBY_ALIASES)
@$(RM) $(PROGRAM) $(WPROGRAM) miniruby$(EXEEXT) dmyext.$(OBJEXT) $(ARCHFILE) .*.time
@$(RM) y.tab.c y.output
clean-ext:
diff --git a/configure.in b/configure.in
index fe63c0c..45949b0 100644
--- a/configure.in
+++ b/configure.in
@@ -519,6 +519,11 @@ AC_CHECK_HEADERS(stdlib.h string.h unistd.h limits.h sys/file.h sys/ioctl.h sys/
sys/mkdev.h sys/utime.h netinet/in_systm.h float.h ieeefp.h pthread.h \
ucontext.h intrinsics.h)
+AC_CHECK_HEADER(sys/sdt.h)
+if test "$ac_cv_header_sys_sdt_h" == "yes"; then
+ AC_DEFINE(HAVE_SDT_H)
+fi
+
dnl Check additional types.
AC_CHECK_SIZEOF(rlim_t, 0, [
#ifdef HAVE_SYS_TYPES_H
@@ -650,6 +655,21 @@ if test "$use_setreuid" = yes; then
AC_DEFINE(USE_SETREUID)
AC_DEFINE(USE_SETREGID)
fi
+
+AC_ARG_ENABLE(dtrace,
+ [ --enable-dtrace enable DTrace support.],
+ [enable_dtrace=$enableval])
+if test "$enable_dtrace" == "yes" -a "$ac_cv_header_sys_sdt_h" == "yes"; then
+ AC_DEFINE(ENABLE_DTRACE)
+ DTRACE_OBJS=""
+ DTRACE_HEADER="dtrace.h"
+else
+ DTRACE_OBJS=""
+ DTRACE_HEADER=""
+fi
+AC_SUBST(DTRACE_OBJS)
+AC_SUBST(DTRACE_HEADER)
+
AC_STRUCT_TIMEZONE
AC_CACHE_CHECK(for struct tm.tm_gmtoff, rb_cv_member_struct_tm_tm_gmtoff,
[AC_TRY_COMPILE([#include <time.h>],
diff --git a/dtrace.d b/dtrace.d
new file mode 100644
index 0000000..f44d10a
--- /dev/null
+++ b/dtrace.d
@@ -0,0 +1,26 @@
+/* -*- Mode: C -*- */
+
+provider ruby {
+ probe function__entry(char*, char*, char*, int);
+ probe function__return(char*, char*, char*, int);
+ probe raise(char*, char*, int);
+ probe rescue(char*, int);
+ probe line(char*, int);
+
+ /* gc probes */
+ probe gc__begin();
+ probe gc__end();
+
+ /* Some initial memory type probes */
+ probe object__create__start(char*, char*, int);
+ probe object__create__done(char*, char*, int);
+ probe object__free(char*);
+
+ probe ruby__probe(char*, char*);
+};
+
+#pragma D attributes Evolving/Evolving/Common provider ruby provider
+#pragma D attributes Private/Private/Common provider ruby module
+#pragma D attributes Private/Private/Common provider ruby function
+#pragma D attributes Evolving/Evolving/Common provider ruby name
+#pragma D attributes Evolving/Evolving/Common provider ruby args
diff --git a/eval.c b/eval.c
index 11264f7..1e90e25 100644
--- a/eval.c
+++ b/eval.c
@@ -215,6 +215,10 @@ int _setjmp(), _longjmp();
#include <sys/stat.h>
+#ifdef ENABLE_DTRACE
+#include "dtrace.h"
+#endif
+
VALUE rb_cProc;
VALUE rb_cBinding;
static VALUE proc_invoke _((VALUE,VALUE,VALUE,VALUE));
@@ -3044,6 +3048,11 @@ rb_eval(self, n)
RETURN(Qfalse);
case NODE_IF:
+ #ifdef ENABLE_DTRACE
+ if (RUBY_LINE_ENABLED())
+ if (ruby_current_node && ruby_current_node->nd_file)
+ RUBY_LINE(ruby_current_node->nd_file, nd_line(ruby_current_node));
+ #endif
if (RTEST(rb_eval(self, node->nd_cond))) {
EXEC_EVENT_HOOK(RUBY_EVENT_LINE, node, self,
ruby_frame->last_func,
@@ -3065,6 +3074,11 @@ rb_eval(self, n)
if (nd_type(node) != NODE_WHEN) goto again;
tag = node->nd_head;
while (tag) {
+ #ifdef ENABLE_DTRACE
+ if (RUBY_LINE_ENABLED())
+ if (ruby_current_node && ruby_current_node->nd_file)
+ RUBY_LINE(ruby_current_node->nd_file, nd_line(ruby_current_node));
+ #endif
EXEC_EVENT_HOOK(RUBY_EVENT_LINE, tag, self,
ruby_frame->last_func,
ruby_frame->last_class);
@@ -3106,6 +3120,11 @@ rb_eval(self, n)
}
tag = node->nd_head;
while (tag) {
+ #ifdef ENABLE_DTRACE
+ if (RUBY_LINE_ENABLED())
+ if (ruby_current_node && ruby_current_node->nd_file)
+ RUBY_LINE(ruby_current_node->nd_file, nd_line(ruby_current_node));
+ #endif
EXEC_EVENT_HOOK(RUBY_EVENT_LINE, tag, self,
ruby_frame->last_func,
ruby_frame->last_class);
@@ -3326,6 +3345,11 @@ rb_eval(self, n)
rescuing = -1;
while (resq) {
ruby_current_node = resq;
+ #ifdef ENABLE_DTRACE
+ if (RUBY_RESCUE_ENABLED())
+ if (ruby_current_node && ruby_current_node->nd_file)
+ RUBY_RESCUE(ruby_current_node->nd_file, nd_line(ruby_current_node));
+ #endif
if (handle_rescue(self, resq)) {
state = 0;
rescuing = 1;
@@ -4144,6 +4168,11 @@ rb_eval(self, n)
break;
case NODE_NEWLINE:
+ #ifdef ENABLE_DTRACE
+ if (RUBY_LINE_ENABLED())
+ if (ruby_current_node && ruby_current_node->nd_file)
+ RUBY_LINE(ruby_current_node->nd_file, nd_line(ruby_current_node));
+ #endif
EXEC_EVENT_HOOK(RUBY_EVENT_LINE, node, self,
ruby_frame->last_func,
ruby_frame->last_class);
@@ -4622,6 +4651,10 @@ rb_longjmp(tag, mesg)
rb_trap_restore_mask();
if (tag != TAG_FATAL) {
+ #ifdef ENABLE_DTRACE
+ if (RUBY_RAISE_ENABLED())
+ RUBY_RAISE(rb_obj_classname(ruby_errinfo), ruby_sourcefile, ruby_sourceline);
+ #endif
EXEC_EVENT_HOOK(RUBY_EVENT_RAISE, ruby_current_node,
ruby_frame->self,
ruby_frame->last_func,
@@ -5885,6 +5918,13 @@ rb_call0(klass, recv, id, oid, argc, argv, body, flags)
rb_bug("bad argc (%d) specified for `%s(%s)'",
len, rb_class2name(klass), rb_id2name(id));
}
+ #ifdef ENABLE_DTRACE
+ if (RUBY_FUNCTION_ENTRY_ENABLED()) {
+ char *classname = rb_class2name(klass), *methodname = rb_id2name(id);
+ if (ruby_current_node && ruby_current_node->nd_file && classname && methodname)
+ RUBY_FUNCTION_ENTRY(classname, methodname, ruby_current_node->nd_file, nd_line(ruby_current_node));
+ }
+ #endif
if (event_hooks) {
int state;
@@ -5903,6 +5943,13 @@ rb_call0(klass, recv, id, oid, argc, argv, body, flags)
else {
result = call_cfunc(body->nd_cfnc, recv, len, argc, argv);
}
+ #ifdef ENABLE_DTRACE
+ if (RUBY_FUNCTION_RETURN_ENABLED()) {
+ char *classname = rb_class2name(klass), *methodname = rb_id2name(id);
+ if (ruby_current_node && ruby_current_node->nd_file && classname && methodname)
+ RUBY_FUNCTION_RETURN(classname, methodname, ruby_current_node->nd_file, nd_line(ruby_current_node));
+ }
+ #endif
}
break;
@@ -5930,12 +5977,26 @@ rb_call0(klass, recv, id, oid, argc, argv, body, flags)
case NODE_BMETHOD:
ruby_frame->flags |= FRAME_DMETH;
+ #ifdef ENABLE_DTRACE
+ if (RUBY_FUNCTION_ENTRY_ENABLED()) {
+ char *classname = rb_class2name(klass), *methodname = rb_id2name(id);
+ if (ruby_current_node && ruby_current_node->nd_file && classname && methodname)
+ RUBY_FUNCTION_ENTRY(classname, methodname, ruby_current_node->nd_file, nd_line(ruby_current_node));
+ }
+ #endif
if (event_hooks) {
struct BLOCK *data;
Data_Get_Struct(body->nd_cval, struct BLOCK, data);
EXEC_EVENT_HOOK(RUBY_EVENT_CALL, data->body, recv, id, klass);
}
result = proc_invoke(body->nd_cval, rb_ary_new4(argc, argv), recv, klass);
+ #ifdef ENABLE_DTRACE
+ if (RUBY_FUNCTION_RETURN_ENABLED()) {
+ char *classname = rb_class2name(klass), *methodname = rb_id2name(id);
+ if (ruby_current_node && ruby_current_node->nd_file && classname && methodname)
+ RUBY_FUNCTION_RETURN(classname, methodname, ruby_current_node->nd_file, nd_line(ruby_current_node));
+ }
+ #endif
if (event_hooks) {
EXEC_EVENT_HOOK(RUBY_EVENT_RETURN, ruby_current_node, recv, id, klass);
}
@@ -6049,6 +6110,13 @@ rb_call0(klass, recv, id, oid, argc, argv, body, flags)
}
ruby_frame->argc = i;
}
+ #ifdef ENABLE_DTRACE
+ if (RUBY_FUNCTION_ENTRY_ENABLED()) {
+ char *classname = rb_class2name(klass), *methodname = rb_id2name(id);
+ if (ruby_current_node && ruby_current_node->nd_file && classname && methodname)
+ RUBY_FUNCTION_ENTRY(classname, methodname, ruby_current_node->nd_file, nd_line(ruby_current_node));
+ }
+ #endif
if (event_hooks) {
EXEC_EVENT_HOOK(RUBY_EVENT_CALL, b2, recv, id, klass);
}
@@ -6059,6 +6127,13 @@ rb_call0(klass, recv, id, oid, argc, argv, body, flags)
state = 0;
}
POP_TAG();
+ #ifdef ENABLE_DTRACE
+ if (RUBY_FUNCTION_RETURN_ENABLED()) {
+ char *classname = rb_class2name(klass), *methodname = rb_id2name(id);
+ if (ruby_current_node && ruby_current_node->nd_file && classname && methodname)
+ RUBY_FUNCTION_RETURN(classname, methodname, ruby_current_node->nd_file, nd_line(ruby_current_node));
+ }
+ #endif
if (event_hooks) {
EXEC_EVENT_HOOK(RUBY_EVENT_RETURN, ruby_current_node, recv, id, klass);
}
diff --git a/gc.c b/gc.c
index 45facf0..7568980 100644
--- a/gc.c
+++ b/gc.c
@@ -30,6 +30,12 @@
#include <sys/resource.h>
#endif
+#ifdef ENABLE_DTRACE
+#include <sys/sdt.h>
+#include "dtrace.h"
+#endif
+
+
#if defined _WIN32 || defined __CYGWIN__
#include <windows.h>
#endif
@@ -1214,6 +1220,11 @@ obj_free(obj)
break;
}
+ #ifdef ENABLE_DTRACE
+ if (RUBY_OBJECT_FREE_ENABLED())
+ RUBY_OBJECT_FREE(rb_class2name(CLASS_OF(obj)));
+ #endif
+
if (FL_TEST(obj, FL_EXIVAR)) {
rb_free_generic_ivar((VALUE)obj);
}
@@ -1374,6 +1385,12 @@ garbage_collect()
{
struct gc_list *list;
struct FRAME * volatile frame; /* gcc 2.7.2.3 -O2 bug?? */
+
+ #ifdef ENABLE_DTRACE
+ if (RUBY_GC_BEGIN_ENABLED())
+ RUBY_GC_BEGIN();
+ #endif
+
jmp_buf save_regs_gc_mark;
SET_STACK_END;
@@ -1466,6 +1483,11 @@ garbage_collect()
} while (!MARK_STACK_EMPTY);
gc_sweep();
+
+ #ifdef ENABLE_DTRACE
+ if (RUBY_GC_END_ENABLED())
+ RUBY_GC_END();
+ #endif
}
void
diff --git a/inits.c b/inits.c
index e8705e7..64a20af 100644
--- a/inits.c
+++ b/inits.c
@@ -46,6 +46,7 @@ void Init_Struct _((void));
void Init_Time _((void));
void Init_var_tables _((void));
void Init_version _((void));
+void Init_Tracer _((void));
void
rb_call_inits()
@@ -83,4 +84,5 @@ rb_call_inits()
Init_Enumerator();
Init_marshal();
Init_version();
+ Init_Tracer();
}
diff --git a/object.c b/object.c
index 9802d4d..e6b4fb7 100644
--- a/object.c
+++ b/object.c
@@ -20,6 +20,11 @@
#include <ctype.h>
#include <math.h>
+#ifdef ENABLE_DTRACE
+#include "dtrace.h"
+#include "node.h"
+#endif
+
VALUE rb_mKernel;
VALUE rb_cObject;
VALUE rb_cModule;
@@ -1603,7 +1608,25 @@ rb_obj_alloc(klass)
if (FL_TEST(klass, FL_SINGLETON)) {
rb_raise(rb_eTypeError, "can't create instance of virtual class");
}
+
+ #ifdef ENABLE_DTRACE
+ if (RUBY_OBJECT_CREATE_START_ENABLED()) {
+ char *file = ruby_current_node == NULL ? "" : ruby_current_node->nd_file;
+ int line = ruby_current_node == NULL ? 0 : nd_line(ruby_current_node);
+ RUBY_OBJECT_CREATE_START(rb_class2name(klass), file, line);
+ }
+ #endif
+
obj = rb_funcall(klass, ID_ALLOCATOR, 0, 0);
+
+ #ifdef ENABLE_DTRACE
+ if (RUBY_OBJECT_CREATE_DONE_ENABLED()) {
+ char *file = ruby_current_node == NULL ? "" : ruby_current_node->nd_file;
+ int line = ruby_current_node == NULL ? 0 : nd_line(ruby_current_node);
+ RUBY_OBJECT_CREATE_DONE(rb_class2name(klass), file, line);
+ }
+ #endif
+
if (rb_obj_class(obj) != rb_class_real(klass)) {
rb_raise(rb_eTypeError, "wrong instance allocation");
}
diff --git a/tracer.c b/tracer.c
new file mode 100644
index 0000000..2e9e091
--- /dev/null
+++ b/tracer.c
@@ -0,0 +1,64 @@
+#include "ruby.h"
+
+#ifdef ENABLE_DTRACE
+#include "dtrace.h"
+#endif
+
+VALUE rb_mDtrace;
+
+static VALUE
+ruby_dtrace_fire(argc, argv, klass)
+ int argc;
+ VALUE *argv;
+ VALUE klass;
+{
+ int args;
+ VALUE name, data, ret;
+ char *probe_data;
+ char *probe_name;
+ char *start_probe;
+ char *end_probe;
+
+ #ifdef ENABLE_DTRACE
+
+ args = rb_scan_args(argc, argv, "11", &name, &data);
+ probe_data = args == 2 ? StringValuePtr(data) : "";
+ probe_name = StringValuePtr(name);
+
+ if (rb_block_given_p()) {
+ start_probe = malloc(strlen(probe_name) + 7);
+ end_probe = malloc(strlen(probe_name) + 5);
+
+ sprintf(start_probe, "%s-start", probe_name);
+ sprintf(end_probe, "%s-end", probe_name);
+
+ /* Build -start and -end strings for probe names */
+ if (RUBY_RUBY_PROBE_ENABLED())
+ RUBY_RUBY_PROBE(start_probe, probe_data);
+ #endif
+
+ ret = rb_yield(Qnil);
+
+ #if ENABLE_DTRACE
+
+ if (RUBY_RUBY_PROBE_ENABLED())
+ RUBY_RUBY_PROBE(end_probe, probe_data);
+
+ free(start_probe);
+ free(end_probe);
+ } else {
+ if (RUBY_RUBY_PROBE_ENABLED())
+ RUBY_RUBY_PROBE(probe_name, probe_data);
+ ret = Qnil;
+ }
+ #endif
+ return ret;
+}
+
+
+void Init_Tracer()
+{
+ rb_mDtrace = rb_define_module("Tracer");
+ rb_define_module_function(rb_mDtrace, "fire", ruby_dtrace_fire, -1);
+}
+
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment