[PATCH] Ruby 1.8.2 DTrace Support, Round Two
From:
Paul Duncan <pabs@...>
Date:
2005-08-20 02:58:33 UTC
List:
ruby-core #5575
Hello again, Richard is having problems subscribing to the list (ruby-talk.org appears to be down), but he asked me to send this follow-up patch to his DTrace provider patch. This patch supercedes the previous patch, and fixes a couple of bugs. As before, I know nothing about DTrace or this patch, so you should forward on any questions to him (at richlowe@richlowe.net), or post them here and I can forward them on to him (or he can either read the archive). The latest patch is attached, and it's also available online at the following URL: http://richlowe.net/~richlowe/patches/ruby-1.8.2-dtrace.diff -- Paul Duncan <pabs@pablotron.org> OpenPGP Key ID: 0x82C29562 http://www.pablotron.org/ http://www.paulduncan.org/
Attachments (2)
ruby-1.8.2-dtrace-2.diff
(16.5 KB, text/x-diff)
Index: Makefile.in
===================================================================
--- Makefile.in (.../clean) (revision 53)
+++ Makefile.in (.../diff-tree) (revision 53)
@@ -103,6 +103,8 @@
version.@OBJEXT@ \
$(MISSING)
+DTRACE_OBJS = @DTRACE_OBJS@
+
MANTYPE = @MANTYPE@
SCRIPT_ARGS = --dest-dir="$(DESTDIR)" \
@@ -124,13 +126,22 @@
# 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
# supported.
-$(LIBRUBY_A): $(OBJS) $(DMYEXT)
+#
+# When dtrace support is enabled, we need to link $(OBJS) and $(DTRACE_OBJS)
+# together into a single glommed object, to avoid ld not noticing the
+# dependency on dtrace.o and failing to link it.
+$(LIBRUBY_A): $(OBJS) $(DMYEXT) $(DTRACE_OBJS)
@rm -f $@
- @AR@ rcu $@ $(OBJS) $(DMYEXT)
+ if test "$(DTRACE_OBJS)" != ""; then \
+ ld -r -o librubyglom.o $(OBJS) $(DTRACE_OBJS); \
+ @AR@ rcu $@ librubyglom.o $(DMYEXT); \
+ else \
+ @AR@ rcu $@ $(OBJS) $(DMYEXT); \
+ fi
@-@RANLIB@ $@ 2> /dev/null || true
-$(LIBRUBY_SO): $(OBJS) $(DLDOBJS) miniruby$(EXEEXT) $(PREP)
- $(LDSHARED) $(DLDFLAGS) $(OBJS) $(DLDOBJS) $(SOLIBS) -o $@
+$(LIBRUBY_SO): $(OBJS) $(DLDOBJS) miniruby$(EXEEXT) $(PREP) $(DTRACE_OBJS)
+ $(LDSHARED) $(DLDFLAGS) $(DTRACE_OBJS) $(OBJS) $(DLDOBJS) $(SOLIBS) -o $@
@-$(MINIRUBY) -e 'ARGV.each{|link| File.delete link if File.exist? link; \
File.symlink "$(LIBRUBY_SO)", link}' \
$(LIBRUBY_ALIASES) || true
@@ -378,3 +389,6 @@
missing.h env.h node.h st.h util.h
version.@OBJEXT@: version.c ruby.h config.h defines.h intern.h missing.h \
version.h
+
+dtrace.@OBJEXT@: dtrace.d $(OBJS) $(MAINOBJ)
+ /usr/sbin/dtrace -G -32 -o $@ -s dtrace.d $(OBJS)
Index: configure.in
===================================================================
--- configure.in (.../clean) (revision 53)
+++ configure.in (.../diff-tree) (revision 53)
@@ -383,6 +383,12 @@
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 Checks for typedefs, structures, and compiler characteristics.
AC_TYPE_UID_T
AC_TYPE_SIZE_T
@@ -415,6 +421,18 @@
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.o"
+else
+ DTRACE_OBJS=""
+fi
+AC_SUBST(DTRACE_OBJS)
+
AC_STRUCT_TIMEZONE
AC_CACHE_CHECK(for struct tm.tm_gmtoff, rb_cv_member_struct_tm_tm_gmtoff,
[AC_TRY_COMPILE([#include <time.h>],
Index: configure
===================================================================
--- configure (.../clean) (revision 53)
+++ configure (.../diff-tree) (revision 53)
@@ -308,7 +308,7 @@
# include <unistd.h>
#endif"
-ac_subst_vars='SHELL PATH_SEPARATOR PACKAGE_NAME PACKAGE_TARNAME PACKAGE_VERSION PACKAGE_STRING PACKAGE_BUGREPORT exec_prefix prefix program_transform_name bindir sbindir libexecdir datadir sysconfdir sharedstatedir localstatedir libdir includedir oldincludedir infodir mandir build_alias host_alias target_alias DEFS ECHO_C ECHO_N ECHO_T LIBS MAJOR MINOR TEENY build build_cpu build_vendor build_os host host_cpu host_vendor host_os target target_cpu target_vendor target_os CC ac_ct_CC CFLAGS LDFLAGS CPPFLAGS EXEEXT OBJEXT CPP EGREP GNU_LD CPPOUTFILE OUTFLAG YACC RANLIB ac_ct_RANLIB AR ac_ct_AR NM ac_ct_NM WINDRES ac_ct_WINDRES DLLWRAP ac_ct_DLLWRAP LN_S SET_MAKE LIBOBJS ALLOCA DLDFLAGS ARCH_FLAG STATIC CCDLFLAGS LDSHARED DLEXT DLEXT2 LIBEXT LINK_SO LIBPATHFLAG RPATHFLAG TRY_LINK STRIP EXTSTATIC setup MINIRUBY PREP ARCHFILE RDOCTARGET XCFLAGS XLDFLAGS LIBRUBY_LDSHARED LIBRUBY_DLDFLAGS RUBY_INSTALL_NAME rubyw_install_name RUBYW_INSTALL_NAME RUBY_SO_NAME LIBRUBY_A LIBRUBY_SO LIBRUBY_ALIASES LIBRUBY LIBRUBYARG LIBRUBYARG_STATIC LIBRUBYARG_SHARED SOLIBS DLDLIBS ENABLE_SHARED MAINLIBS COMMON_LIBS COMMON_MACROS COMMON_HEADERS EXPORT_PREFIX MAKEFILES arch sitearch sitedir configure_args NROFF MANTYPE LTLIBOBJS'
+ac_subst_vars='SHELL PATH_SEPARATOR PACKAGE_NAME PACKAGE_TARNAME PACKAGE_VERSION PACKAGE_STRING PACKAGE_BUGREPORT exec_prefix prefix program_transform_name bindir sbindir libexecdir datadir sysconfdir sharedstatedir localstatedir libdir includedir oldincludedir infodir mandir build_alias host_alias target_alias DEFS ECHO_C ECHO_N ECHO_T LIBS MAJOR MINOR TEENY build build_cpu build_vendor build_os host host_cpu host_vendor host_os target target_cpu target_vendor target_os CC ac_ct_CC CFLAGS LDFLAGS CPPFLAGS EXEEXT OBJEXT CPP EGREP GNU_LD CPPOUTFILE OUTFLAG YACC RANLIB ac_ct_RANLIB AR ac_ct_AR NM ac_ct_NM WINDRES ac_ct_WINDRES DLLWRAP ac_ct_DLLWRAP LN_S SET_MAKE LIBOBJS ALLOCA DTRACE_OBJS DLDFLAGS ARCH_FLAG STATIC CCDLFLAGS LDSHARED DLEXT DLEXT2 LIBEXT LINK_SO LIBPATHFLAG RPATHFLAG TRY_LINK STRIP EXTSTATIC setup MINIRUBY PREP ARCHFILE RDOCTARGET XCFLAGS XLDFLAGS LIBRUBY_LDSHARED LIBRUBY_DLDFLAGS RUBY_INSTALL_NAME rubyw_install_name RUBYW_INSTALL_NAME RUBY_SO_NAME LIBRUBY_A LIBRUBY_SO LIBRUBY_ALIASES LIBRUBY LIBRUBYARG LIBRUBYARG_STATIC LIBRUBYARG_SHARED SOLIBS DLDLIBS ENABLE_SHARED MAINLIBS COMMON_LIBS COMMON_MACROS COMMON_HEADERS EXPORT_PREFIX MAKEFILES arch sitearch sitedir configure_args NROFF MANTYPE LTLIBOBJS'
ac_subst_files=''
# Initialize some variables set by options.
@@ -863,6 +863,7 @@
--disable-largefile omit support for large files
--enable-pthread use pthread library.
--enable-setreuid use setreuid()/setregid() according to need even if obsolete.
+ --enable-dtrace enable DTrace support.
--disable-rpath embed run path into extension libraries.
--enable-shared build a shared library for Ruby.
--enable-install-doc build and install rdoc indexes during install
@@ -10146,6 +10147,152 @@
done
+
+if test "${ac_cv_header_sys_sdt_h+set}" = set; then
+ echo "$as_me:$LINENO: checking for sys/sdt.h" >&5
+echo $ECHO_N "checking for sys/sdt.h... $ECHO_C" >&6
+if test "${ac_cv_header_sys_sdt_h+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+fi
+echo "$as_me:$LINENO: result: $ac_cv_header_sys_sdt_h" >&5
+echo "${ECHO_T}$ac_cv_header_sys_sdt_h" >&6
+else
+ # Is the header compilable?
+echo "$as_me:$LINENO: checking sys/sdt.h usability" >&5
+echo $ECHO_N "checking sys/sdt.h usability... $ECHO_C" >&6
+cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+$ac_includes_default
+#include <sys/sdt.h>
+_ACEOF
+rm -f conftest.$ac_objext
+if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5
+ (eval $ac_compile) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } &&
+ { ac_try='test -z "$ac_c_werror_flag" || test ! -s conftest.err'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; } &&
+ { ac_try='test -s conftest.$ac_objext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ ac_header_compiler=yes
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ac_header_compiler=no
+fi
+rm -f conftest.err conftest.$ac_objext conftest.$ac_ext
+echo "$as_me:$LINENO: result: $ac_header_compiler" >&5
+echo "${ECHO_T}$ac_header_compiler" >&6
+
+# Is the header present?
+echo "$as_me:$LINENO: checking sys/sdt.h presence" >&5
+echo $ECHO_N "checking sys/sdt.h presence... $ECHO_C" >&6
+cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+#include <sys/sdt.h>
+_ACEOF
+if { (eval echo "$as_me:$LINENO: \"$ac_cpp conftest.$ac_ext\"") >&5
+ (eval $ac_cpp conftest.$ac_ext) 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } >/dev/null; then
+ if test -s conftest.err; then
+ ac_cpp_err=$ac_c_preproc_warn_flag
+ ac_cpp_err=$ac_cpp_err$ac_c_werror_flag
+ else
+ ac_cpp_err=
+ fi
+else
+ ac_cpp_err=yes
+fi
+if test -z "$ac_cpp_err"; then
+ ac_header_preproc=yes
+else
+ echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ ac_header_preproc=no
+fi
+rm -f conftest.err conftest.$ac_ext
+echo "$as_me:$LINENO: result: $ac_header_preproc" >&5
+echo "${ECHO_T}$ac_header_preproc" >&6
+
+# So? What about this header?
+case $ac_header_compiler:$ac_header_preproc:$ac_c_preproc_warn_flag in
+ yes:no: )
+ { echo "$as_me:$LINENO: WARNING: sys/sdt.h: accepted by the compiler, rejected by the preprocessor!" >&5
+echo "$as_me: WARNING: sys/sdt.h: accepted by the compiler, rejected by the preprocessor!" >&2;}
+ { echo "$as_me:$LINENO: WARNING: sys/sdt.h: proceeding with the compiler's result" >&5
+echo "$as_me: WARNING: sys/sdt.h: proceeding with the compiler's result" >&2;}
+ ac_header_preproc=yes
+ ;;
+ no:yes:* )
+ { echo "$as_me:$LINENO: WARNING: sys/sdt.h: present but cannot be compiled" >&5
+echo "$as_me: WARNING: sys/sdt.h: present but cannot be compiled" >&2;}
+ { echo "$as_me:$LINENO: WARNING: sys/sdt.h: check for missing prerequisite headers?" >&5
+echo "$as_me: WARNING: sys/sdt.h: check for missing prerequisite headers?" >&2;}
+ { echo "$as_me:$LINENO: WARNING: sys/sdt.h: see the Autoconf documentation" >&5
+echo "$as_me: WARNING: sys/sdt.h: see the Autoconf documentation" >&2;}
+ { echo "$as_me:$LINENO: WARNING: sys/sdt.h: section \"Present But Cannot Be Compiled\"" >&5
+echo "$as_me: WARNING: sys/sdt.h: section \"Present But Cannot Be Compiled\"" >&2;}
+ { echo "$as_me:$LINENO: WARNING: sys/sdt.h: proceeding with the preprocessor's result" >&5
+echo "$as_me: WARNING: sys/sdt.h: proceeding with the preprocessor's result" >&2;}
+ { echo "$as_me:$LINENO: WARNING: sys/sdt.h: in the future, the compiler will take precedence" >&5
+echo "$as_me: WARNING: sys/sdt.h: in the future, the compiler will take precedence" >&2;}
+ (
+ cat <<\_ASBOX
+## ------------------------------------------ ##
+## Report this to the AC_PACKAGE_NAME lists. ##
+## ------------------------------------------ ##
+_ASBOX
+ ) |
+ sed "s/^/$as_me: WARNING: /" >&2
+ ;;
+esac
+echo "$as_me:$LINENO: checking for sys/sdt.h" >&5
+echo $ECHO_N "checking for sys/sdt.h... $ECHO_C" >&6
+if test "${ac_cv_header_sys_sdt_h+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ ac_cv_header_sys_sdt_h=$ac_header_preproc
+fi
+echo "$as_me:$LINENO: result: $ac_cv_header_sys_sdt_h" >&5
+echo "${ECHO_T}$ac_cv_header_sys_sdt_h" >&6
+
+fi
+
+
+if test "$ac_cv_header_sys_sdt_h" == "yes"; then
+ cat >>confdefs.h <<\_ACEOF
+#define HAVE_SDT_H 1
+_ACEOF
+
+fi
+
echo "$as_me:$LINENO: checking for uid_t in sys/types.h" >&5
echo $ECHO_N "checking for uid_t in sys/types.h... $ECHO_C" >&6
if test "${ac_cv_type_uid_t+set}" = set; then
@@ -11773,6 +11920,23 @@
_ACEOF
fi
+
+# Check whether --enable-dtrace or --disable-dtrace was given.
+if test "${enable_dtrace+set}" = set; then
+ enableval="$enable_dtrace"
+ enable_dtrace=$enableval
+fi;
+if test "$enable_dtrace" == "yes" -a "$ac_cv_header_sys_sdt_h" == "yes"; then
+ cat >>confdefs.h <<\_ACEOF
+#define ENABLE_DTRACE 1
+_ACEOF
+
+ DTRACE_OBJS="dtrace.o"
+else
+ DTRACE_OBJS=""
+fi
+
+
echo "$as_me:$LINENO: checking whether struct tm is in sys/time.h or time.h" >&5
echo $ECHO_N "checking whether struct tm is in sys/time.h or time.h... $ECHO_C" >&6
if test "${ac_cv_struct_tm+set}" = set; then
@@ -15810,6 +15974,7 @@
s,@SET_MAKE@,$SET_MAKE,;t t
s,@LIBOBJS@,$LIBOBJS,;t t
s,@ALLOCA@,$ALLOCA,;t t
+s,@DTRACE_OBJS@,$DTRACE_OBJS,;t t
s,@DLDFLAGS@,$DLDFLAGS,;t t
s,@ARCH_FLAG@,$ARCH_FLAG,;t t
s,@STATIC@,$STATIC,;t t
Index: dtrace.d
===================================================================
--- dtrace.d (.../clean) (revision 0)
+++ dtrace.d (.../diff-tree) (revision 53)
@@ -0,0 +1,12 @@
+/* -*- Mode: C -*- */
+
+provider ruby {
+ probe function__entry(string, string, string, int);
+ probe function__return(string, string, string, int);
+};
+
+#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
Index: eval.c
===================================================================
--- eval.c (.../clean) (revision 53)
+++ eval.c (.../diff-tree) (revision 53)
@@ -136,6 +136,10 @@
#include <sys/stat.h>
+#ifdef ENABLE_DTRACE
+#include <sys/sdt.h>
+#endif /* ENABLE_DTRACE */
+
VALUE rb_cProc;
static VALUE rb_cBinding;
static VALUE proc_invoke _((VALUE,VALUE,VALUE,VALUE));
@@ -1012,6 +1016,7 @@
#define YIELD_FUNC_SVALUE 2
static VALUE rb_call _((VALUE,VALUE,ID,int,const VALUE*,int));
+
static VALUE module_setup _((VALUE,NODE*));
static VALUE massign _((VALUE,NODE*,VALUE,int));
@@ -5455,7 +5460,21 @@
return Qnil; /* not reached */
}
-static VALUE
+#ifdef ENABLE_DTRACE
+#define RB_DTRACE_PROBE_CALL(probe, klass, method, node) \
+ if (node && node->nd_file) { \
+ char *classname = rb_class2name(klass); \
+ char *methodname = rb_id2name(method); \
+ if (classname && methodname) \
+ DTRACE_PROBE4(ruby, probe, rb_class2name(klass), \
+ rb_id2name(method), node->nd_file, \
+ nd_line(node)); \
+ }
+#else
+#define RB_DTRACE_PROBE_CALL(probe, klass, method, node) ((void)0)
+#endif /* ENABLE_DTRACE */
+
+VALUE
rb_call0(klass, recv, id, oid, argc, argv, body, nosuper)
VALUE klass, recv;
ID id;
@@ -5507,19 +5526,40 @@
}
if (trace_func) {
int state;
-
+
call_trace_func("c-call", ruby_current_node, recv, id, klass);
+ RB_DTRACE_PROBE_CALL(function__entry, klass, id,
+ ruby_current_node);
PUSH_TAG(PROT_FUNC);
if ((state = EXEC_TAG()) == 0) {
result = call_cfunc(body->nd_cfnc, recv, len, argc, argv);
}
POP_TAG();
ruby_current_node = ruby_frame->node;
+ RB_DTRACE_PROBE_CALL(function__return, klass, id,
+ ruby_current_node);
call_trace_func("c-return", ruby_current_node, recv, id, klass);
+
if (state) JUMP_TAG(state);
}
else {
+#ifdef ENABLE_DTRACE
+ int state;
+
+ RB_DTRACE_PROBE_CALL(function__entry, klass, id,
+ ruby_current_node);
+ PUSH_TAG(PROT_FUNC);
+ if ((state = EXEC_TAG()) == 0) {
+ result = call_cfunc(body->nd_cfnc, recv, len, argc, argv);
+ }
+ POP_TAG();
+ RB_DTRACE_PROBE_CALL(function__return, klass, id,
+ ruby_current_node);
+
+ if (state) JUMP_TAG(state);
+#else
result = call_cfunc(body->nd_cfnc, recv, len, argc, argv);
+#endif /* ENABLE_DTRACE */
}
}
break;
@@ -5644,6 +5684,9 @@
}
}
+ RB_DTRACE_PROBE_CALL(function__entry, klass, id,
+ ruby_frame->prev->node);
+
if (trace_func) {
call_trace_func("call", b2, recv, id, klass);
}
@@ -5658,6 +5701,10 @@
POP_CLASS();
POP_SCOPE();
ruby_cref = saved_cref;
+
+ RB_DTRACE_PROBE_CALL(function__return, klass, id,
+ ruby_frame->prev->node);
+
if (trace_func) {
call_trace_func("return", ruby_frame->prev->node, recv, id, klass);
}
@@ -5706,6 +5753,7 @@
rb_raise(rb_eNotImpError, "method `%s' called on terminated object (0x%lx)",
rb_id2name(mid), recv);
}
+
/* is it in the method cache? */
ent = cache + EXPR1(klass, mid);
if (ent->mid == mid && ent->klass == klass) {
@@ -5740,7 +5788,7 @@
}
}
- return rb_call0(klass, recv, mid, id, argc, argv, body, noex & NOEX_NOSUPER);
+ return (rb_call0(klass, recv, mid, id, argc, argv, body, noex & NOEX_NOSUPER));
}
VALUE
signature.asc
(189 Bytes, application/pgp-signature)