[前][次][番号順一覧][スレッド一覧]

ruby-changes:14406

From: yugui <ko1@a...>
Date: Mon, 4 Jan 2010 00:36:41 +0900 (JST)
Subject: [ruby-changes:14406] Ruby:r26235 (trunk): * trace.h: new file. wraps tracing mechanisms.

yugui	2010-01-04 00:36:17 +0900 (Mon, 04 Jan 2010)

  New Revision: 26235

  http://svn.ruby-lang.org/cgi-bin/viewvc.cgi?view=rev&revision=26235

  Log:
    * trace.h: new file. wraps tracing mechanisms.
    
    * defs/dtrace.d: new file. defined a dtrace provider "ruby".
    
    * include/ruby/ruby.h (LIKELY): moved from vm.c.
      (UNLIKELY): ditto.
      (OBJSETUP): probe "object-create".
      (RUBY_EVENT_RESCUE): new event.
    
    * vm_exec.c (DEBUG_ENTER_INSN): embeded a probe insn-entry into it.
      (DEBUG_END_INSN): insn-return.
    
    * vm.c (LIKELY): moved into ruby.h.
      (UNLIKELY): ditto.
      (Init_BareVM): embeded a probe "raise" into it.
    
    * variable.c (rb_class2name_without_alloc): new utility function.
    
    * tool/rbinstall.rb (install?(:ext, :arch, :'ext-arch')): installs 
      dtrace.d if necessary.
    
    * thread_pthread.c (add_signal_thread_list): probe "raise".
      (rb_thread_create_timer_thread): ditto.
    
    * thread.c (rb_thread_schedule_rec): probes "thread-enter" and
      "thread-leave",
      (thread_start_func_2): ditto.
      (thread_cleanup_func): probe "thread-term"
    
    * lib/mkmf.rb: supports dtrace postprocessor on making an extension.
    
    * iseq.c (rb_vm_insn_name): new utility function.
      (rb_vm_insn_len): ditto.
    
    * insns.def (hook): probes "method-etnry", "method-return", "line",
      and "rescue".
    
    * compile.c (iseq_compile_each): adds a trace op for "rescue" probe.
    
    * gc.c (garbage_collect): probes "gc-begin" and "gc-end".
      (obj_free): probe "object-free"
      (garbage_collect_with_gvl): probe "raise"
      (negative_size_allocation_error): ditto.
      (rb_memerror): ditto.
    
    * eval.c (rb_rescue2): probe "rescue"
      (rb_longjmp): probe "raise"
    
    * ext/probe/probe.c: new extension for application defined probes.
    
    * ext/probe/extconf.rb: ditto.
    
    * configure.in (--with-tracing-model): new option to choose a tracing
      mechanism.
      (DTRACE): new substitution. name of dtrace(1).
      (RUBY_TRACING_MODEL): new substitution.
      (DTRACE_OBJ): ditto.
      (MINIDTRACE_OBJ): ditto.
      (GOLFDTRACE_OBJ): ditto.
      (LIBRUBY_DTRACE_OBJ): ditto.
      (RUBY_DTRACE_POSTPROCESS): new macro. checks whether the dtrace on 
      the system needs postprocessing.
      (RUBY_DTRACE_BSD_BROKEN): new macro. checks whether the dtrace
      supports USDT.
    
    * Makefile.in: 
      (DTRACE): new variable. name of dtrace(1).
      (TRACING_MODEL): new variable. name of the chosen tracing mechanism.
      (DTRACE_OBJ): same as the one in configure.in.
      (MINIDTRACE_OBJ): ditto.
      (GOLFDTRACE_OBJ): ditto.
      (LIBRUBY_DTRACE_OBJ): ditto.
      (CPPOUTFILE): new substitution. necessary for generating dtrace.d
      (trace_none.h): new target for TRACING_MODEL=none
      (RUBY_H_INCLUDES): appended a header for tracing.
      (distclean-local): also removes preprocessed version of dtrace.d
      ($(LIBRUBY_A)): needs $(LIBRUBY_DTRACE_OBJ) if dtrace needs 
      postprocessing.
      ($(PROGRAM)): ditto.
      (golf): ditto.
      (miniruby): ditto.
      ($(arch_hdrdir)/ruby/dtrace.d): new target. preprocessed verson 
      of defs/dtrace.d. generated if necessary.
      ($(arch_hdrdir)/ruby/trace_dtrace.h): new target.
      definition of probes.
      ($(LIBRUBY_DTRACE_OBJ)): new target. generated if dtrace needs 
      postprocessing.
      ($(DTRACE_OBJ)): ditto.
      ($(MINIDTRACE_OBJ)): ditto.
      ($(GOLFDTRACE_OBJ)): ditto.

  Added directories:
    trunk/ext/probe/
  Added files:
    trunk/defs/dtrace.d
    trunk/ext/probe/extconf.rb
    trunk/ext/probe/probe.c
    trunk/include/ruby/trace.h
  Modified files:
    trunk/ChangeLog
    trunk/Makefile.in
    trunk/NEWS
    trunk/common.mk
    trunk/compile.c
    trunk/configure.in
    trunk/eval.c
    trunk/gc.c
    trunk/include/ruby/ruby.h
    trunk/insns.def
    trunk/iseq.c
    trunk/lib/mkmf.rb
    trunk/thread.c
    trunk/thread_pthread.c
    trunk/tool/rbinstall.rb
    trunk/variable.c
    trunk/vm.c
    trunk/vm_core.h
    trunk/vm_exec.h

Index: defs/dtrace.d
===================================================================
--- defs/dtrace.d	(revision 0)
+++ defs/dtrace.d	(revision 26235)
@@ -0,0 +1,41 @@
+#ifdef BITSIZE_OF_VALUE
+#define DO_DEFINE_VALUE(sz) typedef uint ## sz ## _t VALUE
+#define DEFINE_VALUE(sz) DO_DEFINE_VALUE(sz)
+DEFINE_VALUE(BITSIZE_OF_VALUE);
+#else
+# error BITSIZE_OF_VALUE is not defined.
+#endif
+provider ruby {
+    probe method__entry(VALUE receiver, char *classname, char *methodname, char *sourcefile, int sourceline);
+    probe method__return(VALUE receiver, char *classname, char *methodname, char *sourcefile, int sourceline);
+    probe raise(VALUE exception, char *classname, char *sourcefile, int sourceline);
+    probe rescue(VALUE exception, char *classname, char *sourcefile, int sourceline);
+    probe line(char* sourcefile, int sourceline);
+
+    /* gc probes */
+    probe gc__begin();
+    probe gc__end();
+
+    /* threads and fibers */
+    probe thread__init(VALUE thread, char *sourcefile, int sourceline);
+    probe thread__term(VALUE thread, char *sourcefile, int sourceline);
+    probe thread__enter(VALUE thread, char *sourcefile, int sourceline);
+    probe thread__leave(VALUE thread, char *sourcefile, int sourceline);
+
+    /* Some initial memory type probes */
+    probe object__create(VALUE obj, char *classname, char *sourcefile, int sourceline);
+    probe object__free(VALUE obj);
+
+    /* VM proves */
+    probe insn__entry(char *insnname, VALUE *operands, char *sourcefile, int sourceline);
+    probe insn__return(char *insnname, VALUE *operands, char *sourcefile, int sourceline);
+
+    probe ruby__probe(char *name, char *data);
+};
+
+#pragma D attributes Evolving/Evolving/Common provider ruby provider 
+#pragma D attributes Private/Private/Unknown provider ruby module 
+#pragma D attributes Private/Private/Unknown provider ruby function 
+#pragma D attributes Evolving/Evolving/Unknown provider ruby name 
+#pragma D attributes Evolving/Evolving/Unknown provider ruby args 
+
Index: include/ruby/trace.h
===================================================================
--- include/ruby/trace.h	(revision 0)
+++ include/ruby/trace.h	(revision 26235)
@@ -0,0 +1,105 @@
+/**********************************************************************
+
+  trace.h -
+
+  $Author$
+
+  Copyright (C) 2009 Yuki Sonoda (Yugui)
+
+**********************************************************************/
+
+#ifndef RUBY_TRACE_H
+#define RUBY_TRACE_H
+
+#define RUBY_TRACING_MODEL_NONE 0
+#define RUBY_TRACING_MODEL_DTRACE 1
+
+#if RUBY_TRACING_MODEL == RUBY_TRACING_MODEL_NONE
+# define TRACE_METHOD_ENTRY_ENABLED() 0
+# define TRACE_METHOD_RETURN_ENABLED() 0
+# define TRACE_RAISE_ENABLED() 0
+# define TRACE_RESCUE_ENABLED() 0
+# define TRACE_LINE_ENABLED() 0
+# define TRACE_GC_BEGIN_ENABLED() 0
+# define TRACE_GC_END_ENABLED() 0
+# define TRACE_THREAD_INIT_ENABLED()  0
+# define TRACE_THREAD_TERM_ENABLED()  0
+# define TRACE_THREAD_LEAVE_ENABLED() 0
+# define TRACE_THREAD_ENTER_ENABLED() 0
+# define TRACE_OBJECT_CREATE_ENABLED() 0
+# define TRACE_OBJECT_FREE_ENABLED() 0
+# define TRACE_INSN_ENTRY_ENABLED() 0
+# define TRACE_INSN_RETURN_ENABLED() 0
+# define TRACE_RUBY_PROBE_ENABLED() 0
+
+# define FIRE_METHOD_ENTRY(receiver, classname, methodname, sourcefile, sourceline) ((void)0)
+# define FIRE_METHOD_RETURN(receiver, classname, methodname, sourcefile, sourceline) ((void)0)
+# define FIRE_RAISE(exception, classname, sourcename, sourceline) ((void)0)
+# define FIRE_RESCUE(exception, classname, sourcename, sourceline) ((void)0)
+# define FIRE_LINE(sourcename, sourceline) ((void)0)
+# define FIRE_GC_BEGIN() ((void)0)
+# define FIRE_GC_END() ((void)0)
+# define FIRE_THREAD_INIT(th, sourcefile, sourceline) ((void)0)
+# define FIRE_THREAD_TERM(th, sourcefile, sourceline) ((void)0)
+# define FIRE_THREAD_LEAVE(th, sourcefile, sourceline) ((void)0)
+# define FIRE_THREAD_ENTER(th, sourcefile, sourceline) ((void)0)
+# define FIRE_OBJECT_CREATE(obj, classname, sourcefile, sourceline) ((void)0)
+# define FIRE_OBJECT_FREE(obj) ((void)0)
+# define FIRE_INSN_ENTRY(insnname, operands, sourcename, sourceline) ((void)0)
+# define FIRE_INSN_RETURN(insnname, operands, sourcename, sourceline) ((void)0)
+# define FIRE_RUBY_PROBE(name, data) ((void)0)
+
+#elif RUBY_TRACING_MODEL == RUBY_TRACING_MODEL_DTRACE
+# include "ruby/trace_dtrace.h"
+# define TRACE_METHOD_ENTRY_ENABLED()  RUBY_METHOD_ENTRY_ENABLED()
+# define TRACE_METHOD_RETURN_ENABLED() RUBY_METHOD_RETURN_ENABLED()
+# define TRACE_RAISE_ENABLED()         RUBY_RAISE_ENABLED()
+# define TRACE_RESCUE_ENABLED()        RUBY_RESCUE_ENABLED()
+# define TRACE_LINE_ENABLED()          RUBY_LINE_ENABLED()
+# define TRACE_GC_BEGIN_ENABLED()      RUBY_GC_BEGIN_ENABLED()
+# define TRACE_GC_END_ENABLED()        RUBY_GC_END_ENABLED()
+# define TRACE_THREAD_INIT_ENABLED()  RUBY_THREAD_INIT_ENABLED()
+# define TRACE_THREAD_TERM_ENABLED()  RUBY_THREAD_TERM_ENABLED()
+# define TRACE_THREAD_LEAVE_ENABLED()  RUBY_THREAD_LEAVE_ENABLED()
+# define TRACE_THREAD_ENTER_ENABLED()  RUBY_THREAD_ENTER_ENABLED()
+# define TRACE_OBJECT_CREATE_ENABLED() RUBY_OBJECT_CREATE_ENABLED()
+# define TRACE_OBJECT_FREE_ENABLED()   RUBY_OBJECT_FREE_ENABLED()
+# define TRACE_INSN_ENTRY_ENABLED()    RUBY_INSN_ENTRY_ENABLED()
+# define TRACE_INSN_RETURN_ENABLED()   RUBY_INSN_RETURN_ENABLED()
+# define TRACE_RUBY_PROBE_ENABLED()    RUBY_RUBY_PROBE_ENABLED()
+
+# define FIRE_METHOD_ENTRY(receiver, classname, methodname, sourcefile, sourceline) \
+   RUBY_METHOD_ENTRY(receiver, classname, methodname, sourcefile, sourceline)
+# define FIRE_METHOD_RETURN(receiver, classname, methodname, sourcefile, sourceline) \
+   RUBY_METHOD_RETURN(receiver, classname, methodname, sourcefile, sourceline)
+# define FIRE_RAISE(exception, classname, sourcename, sourceline) \
+   RUBY_RAISE(exception, classname, sourcename, sourceline)
+# define FIRE_RESCUE(exception, classname, sourcename, sourceline) \
+   RUBY_RESCUE(exception, classname, sourcename, sourceline)
+# define FIRE_LINE(sourcename, sourceline) \
+   RUBY_LINE(sourcename, sourceline)
+# define FIRE_GC_BEGIN()     RUBY_GC_BEGIN()
+# define FIRE_GC_END()       RUBY_GC_END()
+# define FIRE_THREAD_INIT(th, sourcefile, sourceline) \
+   RUBY_THREAD_INIT(th, (char*)sourcefile, sourceline)
+# define FIRE_THREAD_TERM(th, sourcefile, sourceline) \
+   RUBY_THREAD_TERM(th, (char*)sourcefile, sourceline)
+# define FIRE_THREAD_LEAVE(th, sourcefile, sourceline) \
+   RUBY_THREAD_LEAVE(th, (char*)sourcefile, sourceline)
+# define FIRE_THREAD_ENTER(th, sourcefile, sourceline) \
+   RUBY_THREAD_ENTER(th, (char*)sourcefile, sourceline)
+# define FIRE_OBJECT_CREATE(obj, classname, sourcefile, sourceline) \
+   RUBY_OBJECT_CREATE(obj, (char*)classname, (char*)sourcefile, sourceline)
+# define FIRE_OBJECT_FREE(obj) \
+   RUBY_OBJECT_FREE(obj)
+# define FIRE_INSN_ENTRY(insnname, operands, sourcename, sourceline) \
+   RUBY_INSN_ENTRY(insnname, operands, sourcename, sourceline)
+# define FIRE_INSN_RETURN(insnname, operands, sourcename, sourceline) \
+   RUBY_INSN_RETURN(insnname, operands, sourcename, sourceline)
+# define FIRE_RUBY_PROBE(name, data) \
+   RUBY_RUBY_PROBE(name, data)
+#endif
+
+#define FIRE_RAISE_FATAL() FIRE_RAISE(0, (char*)"fatal", (char*)"<unknown>", 0)
+
+#endif
Index: include/ruby/ruby.h
===================================================================
--- include/ruby/ruby.h	(revision 26234)
+++ include/ruby/ruby.h	(revision 26235)
@@ -40,10 +40,19 @@
 #endif
 
 #ifdef __GNUC__
-#define PRINTF_ARGS(decl, string_index, first_to_check) \
-  decl __attribute__((format(printf, string_index, first_to_check)))
+# define PRINTF_ARGS(decl, string_index, first_to_check) \
+   decl __attribute__((format(printf, string_index, first_to_check)))
+# if __GNUC__ >= 3
+#  define LIKELY(x)   (__builtin_expect((x), 1))
+#  define UNLIKELY(x) (__builtin_expect((x), 0))
+# else
+#  define LIKELY(x)   (x)
+#  define UNLIKELY(x) (x)
+# endif
 #else
-#define PRINTF_ARGS(decl, string_index, first_to_check) decl
+# define PRINTF_ARGS(decl, string_index, first_to_check) decl
+# define LIKELY(x)   (x)
+# define UNLIKELY(x) (x)
 #endif
 
 #ifdef HAVE_STDLIB_H
@@ -516,12 +525,17 @@
 VALUE rb_uint2big(VALUE);
 VALUE rb_int2big(SIGNED_VALUE);
 
+#include "ruby/trace.h"
+
 VALUE rb_newobj(void);
 #define NEWOBJ(obj,type) type *obj = (type*)rb_newobj()
 #define OBJSETUP(obj,c,t) do {\
     RBASIC(obj)->flags = (t);\
     RBASIC(obj)->klass = (c);\
     if (rb_safe_level() >= 3) FL_SET(obj, FL_TAINT | FL_UNTRUSTED);\
+    if (UNLIKELY(TRACE_OBJECT_CREATE_ENABLED())) { \
+        FIRE_OBJECT_CREATE((VALUE)(obj), rb_class2name((c)), rb_sourcefile(), rb_sourceline()); \
+    } \
 } while (0)
 #define CLONESETUP(clone,obj) do {\
     OBJSETUP(clone,rb_singleton_class_clone((VALUE)obj),RBASIC(obj)->flags);\
@@ -1325,6 +1339,7 @@
 #define RUBY_EVENT_C_CALL    0x0020
 #define RUBY_EVENT_C_RETURN  0x0040
 #define RUBY_EVENT_RAISE     0x0080
+#define RUBY_EVENT_RESCUE    0x0100
 #define RUBY_EVENT_ALL       0xffff
 #define RUBY_EVENT_VM       0x10000
 #define RUBY_EVENT_SWITCH   0x20000
Index: configure.in
===================================================================
--- configure.in	(revision 26234)
+++ configure.in	(revision 26235)
@@ -357,6 +357,51 @@
 MAKEDIRS="$MKDIR_P"
 AC_SUBST(MAKEDIRS)
 
+AC_DEFUN([RUBY_DTRACE_POSTPROCESS],
+[AC_CACHE_CHECK(whether $DTRACE needs post processing, rb_cv_prog_dtrace_g,
+[
+ echo "int main(void){ return 0; }" > conftest.c
+ echo "provider conftest{};" > conftest_provider.d
+ $CC $CFLAGS -c -o conftest.o conftest.c
+ if $DTRACE -G -s conftest_provider.d conftest.o 2>/dev/null; then
+   rb_cv_prog_dtrace_g=yes
+   $1
+ else
+   rb_cv_prog_dtrace_g=no
+   $2
+ fi
+ rm -f conftest.o conftest.c conftest_provider.d conftest_provider.o
+])
+])
+
+AC_DEFUN([RUBY_DTRACE_BSD_BROKEN],
+[AC_CACHE_CHECK(whether dtrace USDT is broken, rb_cv_dtrace_bsd_broken,
+[
+    cat <<EOF > conftest.c
+#define _DTRACE_VERSION 1
+#include "conftest_provider.h"
+int main(void)
+{
+    if (CONFTEST_FIRE_ENABLED()) CONFTEST_FIRE();
+    return 0;
+}
+EOF
+    echo "provider conftest{ probe fire(); };" > conftest_provider.d
+    $DTRACE -h -o conftest_provider.h -s conftest_provider.d
+    $CC $CFLAGS -c -o conftest.o conftest.c
+    if $DTRACE -G -o conftest_provider.o -s conftest_provider.d conftest.o >/dev/null 2>/dev/null; then
+        rb_cv_dtrace_bsd_broken=no
+        $2
+    else
+        rb_cv_dtrace_bsd_broken=yes
+        $1
+    fi
+    rm -f conftest.[co] conftest_provider.[dho]
+])
+])
+
+AC_CHECK_TOOL(DTRACE, dtrace)
+
 AC_CHECK_TOOL(DOT, dot)
 AC_CHECK_TOOL(DOXYGEN, doxygen)
 if test x"$DOXYGEN" = x; then
@@ -1023,6 +1068,7 @@
 		 ucontext.h intrinsics.h langinfo.h locale.h sys/sendfile.h time.h \
 		 net/socket.h sys/socket.h)
 
+
 dnl Check additional types.
 RUBY_CHECK_SIZEOF(rlim_t, [int long "long long"], [], [
   #ifdef HAVE_SYS_TYPES_H
@@ -2065,6 +2111,54 @@
     ;;
 esac
 
+AC_ARG_WITH(tracing-model,
+            AS_HELP_STRING([--with-tracing-model=MODEL], [use MODEL for tracing ruby's internal. [[auto]] (none|dtrace|auto)]),
+            [TRACING_MODEL=$withval], [TRACING_MODEL=auto])
+
+if test "${TRACING_MODEL}" = "auto"; then
+    if test x"$DTRACE" != x -a x"$cross_compiling" != xyes; then
+        RUBY_DTRACE_POSTPROCESS()
+        if test "$rb_cv_prog_dtrace_g" = 'yes'; then 
+            RUBY_DTRACE_BSD_BROKEN([TRACING_MODEL=none], [TRACING_MODEL=dtrace]) 
+        else
+            TRACING_MODEL=dtrace
+        fi
+    else
+        TRACING_MODEL=none
+    fi
+fi
+
+case "${TRACING_MODEL}" in
+    when(none)
+        AC_DEFINE(RUBY_TRACING_MODEL, RUBY_TRACING_MODEL_NONE, [none])
+        ;;
+    when(dtrace)
+        if test -z "$DTRACE"; then
+            AC_MSG_ERROR([dtrace(1) is missing])
+        elif test "$cross_compiling" = yes; then
+            AC_MSG_ERROR([--with-tracing-model=dtrace, however, cross compiling])
+        else
+            RUBY_DTRACE_POSTPROCESS()
+            if test "$rb_cv_prog_dtrace_g" = 'yes'; then 
+                RUBY_DTRACE_BSD_BROKEN([AC_MSG_ERROR([--with-tracing-model=dtrace, however, USDT is broken])], [])
+                DTRACE_OBJ='dtrace.$(OBJEXT)'
+                MINIDTRACE_OBJ='minidtrace.$(OBJEXT)'
+                GOLFDTRACE_OBJ='golfdtrace.$(OBJEXT)'
+                LIBRUBY_DTRACE_OBJ='libruby_dtrace.$(OBJEXT)'
+            fi
+        fi
+        AC_DEFINE(RUBY_TRACING_MODEL, RUBY_TRACING_MODEL_DTRACE, [dtrace])
+        AC_SUBST(DTRACE_OBJ)
+        AC_SUBST(MINIDTRACE_OBJ)
+        AC_SUBST(GOLFDTRACE_OBJ)
+        AC_SUBST(LIBRUBY_DTRACE_OBJ)
+        ;;
+    when(*)
+        AC_MSG_ERROR([unknown tracing model: ${TRACING_MODEL}])
+        ;;
+esac
+AC_SUBST(TRACING_MODEL)
+
 AC_ARG_WITH(soname,
 	AS_HELP_STRING([--with-soname=SONAME], [base name of shared library]),
 	[RUBY_SO_NAME=$withval], [RUBY_SO_NAME='$(RUBY_BASE_NAME)'])
@@ -2712,4 +2806,5 @@
 [EXEEXT=$EXEEXT gnumake=$gnumake])
 AC_OUTPUT
 dnl }
+
 dnl }
Index: insns.def
===================================================================
--- insns.def	(revision 26234)
+++ insns.def	(revision 26235)
@@ -859,6 +859,30 @@
     rb_event_flag_t flag = (rb_event_flag_t)nf;
 
     EXEC_EVENT_HOOK(th, flag, GET_SELF(), 0, 0 /* TODO: id, klass */);
+    if (UNLIKELY(TRACE_METHOD_ENTRY_ENABLED()
+                | TRACE_METHOD_RETURN_ENABLED()
+                | TRACE_LINE_ENABLED()
+                | TRACE_RESCUE_ENABLED())) {
+	if (UNLIKELY(TRACE_METHOD_ENTRY_ENABLED()) && (flag & RUBY_EVENT_CALL) ) {
+	    VALUE self = GET_SELF(), klass;
+	    ID id;
+	    rb_thread_method_id_and_class(GET_THREAD(), &id, &klass);
+	    FIRE_METHOD_ENTRY(self, (char*)rb_class2name(klass), (char*)rb_id2name(id), (char*)rb_sourcefile(), rb_sourceline());
+	}
+	if (UNLIKELY(TRACE_METHOD_RETURN_ENABLED()) && (flag & RUBY_EVENT_RETURN) ) {
+	    VALUE self = GET_SELF(), klass;
+	    ID id;
+	    rb_thread_method_id_and_class(GET_THREAD(), &id, &klass);
+	    FIRE_METHOD_RETURN(self, (char*)rb_class2name(klass), (char*)rb_id2name(id), (char*)rb_sourcefile(), rb_sourceline());
+	}
+	if (UNLIKELY(TRACE_RESCUE_ENABLED()) && (flag & RUBY_EVENT_RESCUE) ) {
+            VALUE ex = GET_DFP()[-2];
+	    FIRE_RESCUE(ex, (char*)rb_class2name(CLASS_OF(ex)), (char*)rb_sourcefile(), rb_sourceline());
+	}
+	if (UNLIKELY(TRACE_LINE_ENABLED()) && (flag & RUBY_EVENT_LINE) ) {
+	    FIRE_LINE((char*)rb_sourcefile(), rb_sourceline());
+	}
+    }
 }
 
 /**********************************************************/
Index: ChangeLog
===================================================================
--- ChangeLog	(revision 26234)
+++ ChangeLog	(revision 26235)
@@ -1,3 +1,96 @@
+Sun Jan  3 23:54:51 2010  Yuki Sonoda (Yugui)  <yugui@y...>
+
+	* trace.h: new file. wraps tracing mechanisms.
+
+	* defs/dtrace.d: new file. defined a dtrace provider "ruby".
+
+	* include/ruby/ruby.h (LIKELY): moved from vm.c.
+	  (UNLIKELY): ditto.
+	  (OBJSETUP): probe "object-create".
+	  (RUBY_EVENT_RESCUE): new event.
+
+	* vm_exec.c (DEBUG_ENTER_INSN): embeded a probe insn-entry into it.
+	  (DEBUG_END_INSN): insn-return.
+
+	* vm.c (LIKELY): moved into ruby.h.
+	  (UNLIKELY): ditto.
+	  (Init_BareVM): embeded a probe "raise" into it.
+
+	* variable.c (rb_class2name_without_alloc): new utility function.
+
+	* tool/rbinstall.rb (install?(:ext, :arch, :'ext-arch')): installs 
+	  dtrace.d if necessary.
+
+	* thread_pthread.c (add_signal_thread_list): probe "raise".
+	  (rb_thread_create_timer_thread): ditto.
+
+	* thread.c (rb_thread_schedule_rec): probes "thread-enter" and
+	  "thread-leave",
+	  (thread_start_func_2): ditto.
+	  (thread_cleanup_func): probe "thread-term"
+
+	* lib/mkmf.rb: supports dtrace postprocessor on making an extension.
+
+	* iseq.c (rb_vm_insn_name): new utility function.
+	  (rb_vm_insn_len): ditto.
+
+	* insns.def (hook): probes "method-etnry", "method-return", "line",
+	  and "rescue".
+
+	* compile.c (iseq_compile_each): adds a trace op for "rescue" probe.
+
+	* gc.c (garbage_collect): probes "gc-begin" and "gc-end".
+	  (obj_free): probe "object-free"
+	  (garbage_collect_with_gvl): probe "raise"
+	  (negative_size_allocation_error): ditto.
+	  (rb_memerror): ditto.
+
+	* eval.c (rb_rescue2): probe "rescue"
+	  (rb_longjmp): probe "raise"
+
+	* ext/probe/probe.c: new extension for application defined probes.
+
+	* ext/probe/extconf.rb: ditto.
+
+	* configure.in (--with-tracing-model): new option to choose a tracing
+	  mechanism.
+	  (DTRACE): new substitution. name of dtrace(1).
+	  (RUBY_TRACING_MODEL): new substitution.
+	  (DTRACE_OBJ): ditto.
+	  (MINIDTRACE_OBJ): ditto.
+	  (GOLFDTRACE_OBJ): ditto.
+	  (LIBRUBY_DTRACE_OBJ): ditto.
+	  (RUBY_DTRACE_POSTPROCESS): new macro. checks whether the dtrace on 
+	  the system needs postprocessing.
+	  (RUBY_DTRACE_BSD_BROKEN): new macro. checks whether the dtrace
+	  supports USDT.
+
+	* Makefile.in: 
+	  (DTRACE): new variable. name of dtrace(1).
+	  (TRACING_MODEL): new variable. name of the chosen tracing mechanism.
+	  (DTRACE_OBJ): same as the one in configure.in.
+	  (MINIDTRACE_OBJ): ditto.
+	  (GOLFDTRACE_OBJ): ditto.
+	  (LIBRUBY_DTRACE_OBJ): ditto.
+	  (CPPOUTFILE): new substitution. necessary for generating dtrace.d
+	  (trace_none.h): new target for TRACING_MODEL=none
+	  (RUBY_H_INCLUDES): appended a header for tracing.
+	  (distclean-local): also removes preprocessed version of dtrace.d
+	  ($(LIBRUBY_A)): needs $(LIBRUBY_DTRACE_OBJ) if dtrace needs 
+	  postprocessing.
+	  ($(PROGRAM)): ditto.
+	  (golf): ditto.
+	  (miniruby): ditto.
+	  ($(arch_hdrdir)/ruby/dtrace.d): new target. preprocessed verson 
+	  of defs/dtrace.d. generated if necessary.
+	  ($(arch_hdrdir)/ruby/trace_dtrace.h): new target.
+	  definition of probes.
+	  ($(LIBRUBY_DTRACE_OBJ)): new target. generated if dtrace needs 
+	  postprocessing.
+	  ($(DTRACE_OBJ)): ditto.
+	  ($(MINIDTRACE_OBJ)): ditto.
+	  ($(GOLFDTRACE_OBJ)): ditto.
+
 Sun Jan  3 15:34:19 2010  Yuki Sonoda (Yugui)  <yugui@y...>
 
 	* lib/rexml/text.rb: String no longer has #each.
Index: thread_pthread.c
===================================================================
--- thread_pthread.c	(revision 26234)
+++ thread_pthread.c	(revision 26235)
@@ -694,6 +694,7 @@
 
 	    if (list == 0) {
 		fprintf(stderr, "[FATAL] failed to allocate memory\n");
+                if (UNLIKELY(TRACE_RAISE_ENABLED())) FIRE_RAISE_FATAL();
 		exit(1);
 	    }
 
@@ -805,6 +806,7 @@
 	if (err != 0) {
 	    native_mutex_unlock(&timer_thread_lock);
 	    fprintf(stderr, "[FATAL] Failed to create timer thread (errno: %d)\n", err);
+            if (UNLIKELY(TRACE_RAISE_ENABLED())) FIRE_RAISE_FATAL();
 	    exit(EXIT_FAILURE);
 	}
 	native_cond_wait(&timer_thread_cond, &timer_thread_lock);
Index: variable.c
===================================================================
--- variable.c	(revision 26234)
+++ variable.c	(revision 26235)
@@ -313,7 +313,28 @@
     return RSTRING_PTR(rb_class_name(klass));
 }
 
+/*!
+ * \internal
+ * Same as rb_class2name but safe if during GC
+ *
+ * \post the returned pointer points a string. not NULL.
+ */
 const char *
+rb_class2name_without_alloc(VALUE klass)
+{
+    if (RCLASS_IV_TBL(klass)) {
+	st_data_t n;
+	if (st_lookup(RCLASS_IV_TBL(klass), (st_data_t)classpath, &n) ||
+	    st_lookup(RCLASS_IV_TBL(klass), (st_data_t)classid, &n) ||
+	    st_lookup(RCLASS_IV_TBL(klass), (st_data_t)tmp_classpath, &n)) {
+	    if (TYPE(n) != T_STRING) rb_bug("class path is not set properly");
+	    return RSTRING_PTR(n);
+	}
+    }
+    return "(anonymous)";
+}
+
+const char *
 rb_obj_classname(VALUE obj)
 {
     return rb_class2name(CLASS_OF(obj));
Index: vm_core.h
===================================================================
--- vm_core.h	(revision 26234)
+++ vm_core.h	(revision 26235)
@@ -97,15 +97,6 @@
 #endif /* OPT_STACK_CACHING */
 #endif /* OPT_CALL_THREADED_CODE */
 
-/* likely */
-#if __GNUC__ >= 3
-#define LIKELY(x)   (__builtin_expect((x), 1))
-#define UNLIKELY(x) (__builtin_expect((x), 0))
-#else /* __GNUC__ >= 3 */
-#define LIKELY(x)   (x)
-#define UNLIKELY(x) (x)
-#endif /* __GNUC__ >= 3 */
-
 typedef unsigned long rb_num_t;
 
 /* iseq data type */
Index: iseq.c
===================================================================
--- iseq.c	(revision 26234)
+++ iseq.c	(revision 26235)
@@ -1473,6 +1473,27 @@
     return iseqval;
 }
 
+const char *
+rb_vm_insn_name(int insn)
+{
+    if (insn < VM_INSTRUCTION_SIZE) {
+        return insn_name(insn);
+    } else {
+        return 0;
+    }
+}
+
+int
+rb_vm_insn_len(int insn)
+{
+    if (insn < VM_INSTRUCTION_SIZE) {
+        return insn_len(insn);
+    } else {
+        return 0;
+    }
+}
+
+
 void
 Init_ISeq(void)
 {
Index: lib/mkmf.rb
===================================================================
--- lib/mkmf.rb	(revision 26234)
+++ lib/mkmf.rb	(revision 26235)
@@ -69,6 +69,8 @@
 $universal = /universal/ =~ RUBY_PLATFORM
 $dest_prefix_pattern = (File::PATH_SEPARATOR == ';' ? /\A([[:alpha:]]:)?/ : /\A/)
 
+$dtrace_postprocess = (CONFIG['DTRACE_OBJ'] and /^\s*$/ !~ CONFIG['DTRACE_OBJ'])
+
 # :stopdoc:
 
 def config_string(key, config = CONFIG)
@@ -1450,6 +1452,7 @@
   mk << %{
 CC = #{CONFIG['CC']}
 CXX = #{CONFIG['CXX']}
+DTRACE = #{CONFIG['DTRACE']}
 LIBRUBY = #{CONFIG['LIBRUBY']}
 LIBRUBY_A = #{CONFIG['LIBRUBY_A']}
 LIBRUBYARG_SHARED = #$LIBRUBYARG_SHARED
@@ -1719,6 +1722,7 @@
 LIBS = #{$LIBRUBYARG} #{$libs} #{$LIBS}
 SRCS = #{srcs.collect(&File.method(:basename)).join(' ')}
 OBJS = #{$objs.join(" ")}
+DTRACE_OBJ = #{$dtrace_postprocess ? "$(TARGET)_dtrace.#{$OBJEXT}" : ''}
 TARGET = #{target}
 DLLIB = #{dllib}
 EXTSTATIC = #{$static || ""}
@@ -1739,6 +1743,12 @@
 .PHONY: clean clean-so clean-rb
 "
   mfile.print CLEANINGS
+
+  if $dtrace_postprocess 
+    mfile.print "$(DTRACE_OBJ): $(OBJS)\n"
+    mfile.print "\t$(DTRACE) -G -o $@ -s $(arch_hdrdir)/ruby/dtrace.d $(OBJS)\n"
+  end
+
   fsep = config_string('BUILD_FILE_SEPARATOR') {|s| s unless s == "/"}
   if fsep
     sep = ":/=#{fsep}"
@@ -1841,7 +1851,7 @@
   mfile.print "$(RUBYARCHDIR)/" if $extout
   mfile.print "$(DLLIB): "
   mfile.print "$(DEFFILE) " if makedef
-  mfile.print "$(OBJS) Makefile\n"
+  mfile.print "$(OBJS) $(DTRACE_OBJ) Makefile\n"
   mfile.print "\t@-$(RM) $(@#{sep})\n"
   mfile.print "\t@-$(MAKEDIRS) $(@D)\n" if $extout
   link_so = LINK_SO.gsub(/^/, "\t")
@@ -1850,8 +1860,8 @@
   end
   mfile.print link_so, "\n\n"
   unless $static.nil?
-    mfile.print "$(STATIC_LIB): $(OBJS)\n\t@-$(RM) $(@#{sep})\n\t"
-    mfile.print "$(AR) #{config_string('ARFLAGS') || 'cru '}$@ $(OBJS)"
+    mfile.print "$(STATIC_LIB): $(OBJS) $(DTRACE_OBJ)\n\t@-$(RM) $(@#{sep})\n\t"
+    mfile.print "$(AR) #{config_string('ARFLAGS') || 'cru '}$@ $(OBJS) $(DTRACE_OBJ)"
     config_string('RANLIB') do |ranlib|
       mfile.print "\n\t@-#{ranlib} $(DLLIB) 2> /dev/null || true"
     end
@@ -1872,6 +1882,7 @@
     end
     headers << $config_h
     headers << '$(RUBY_EXTCONF_H)' if $extconf_h
+    headers << '$(arch_hdrdir)/ruby/dtrace.d' if $dtrace_postprocess
     mfile.print "$(OBJS): ", headers.join(' '), "\n"
   end
 
@@ -2004,9 +2015,9 @@
   "$(CFLAGS) $(src) $(LIBPATH) $(LDFLAGS) $(ARCH_FLAG) $(LOCAL_LIBS) $(LIBS)"
 LINK_SO = config_string('LINK_SO') ||
   if CONFIG["DLEXT"] == $OBJEXT
-    "ld $(DLDFLAGS) -r -o $@ $(OBJS)\n"
+    "ld $(DLDFLAGS) -r -o $@ $(OBJS) $(DTRACE_OBJ)\n"
   else
-    "$(LDSHARED) #{OUTFLAG}$@ $(OBJS) " \
+    "$(LDSHARED) #{OUTFLAG}$@ $(OBJS) $(DTRACE_OBJ) " \
     "$(LIBPATH) $(DLDFLAGS) $(LOCAL_LIBS) $(LIBS)"
   end
 LIBPATHFLAG = config_string('LIBPATHFLAG') || ' -L"%s"'
Index: compile.c
===================================================================
--- compile.c	(revision 26234)
+++ compile.c	(revision 26235)
@@ -3569,6 +3569,7 @@
 	    }
 	    ADD_INSNL(ret, nd_line(node), jump, label_miss);
 	    ADD_LABEL(ret, label_hit);
+	    ADD_TRACE(ret, nd_line(node), RUBY_EVENT_RESCUE);
 	    COMPILE(ret, "resbody body", resq->nd_body);
 	    if (iseq->compile_data->option->tailcall_optimization) {
 		ADD_INSN(ret, nd_line(node), nop);
Index: thread.c
===================================================================
--- thread.c	(revision 26234)
+++ thread.c	(revision 26235)
@@ -376,6 +376,8 @@
 {
     rb_thread_t *th = th_ptr;
 
+    if (TRACE_THREAD_TERM_ENABLED()) FIRE_THREAD_TERM(th->self, rb_sourcefile(), rb_sourceline());
+
     /* unlock all locking mutexes */
     if (th->keeping_mutexes) {
 	rb_mutex_unlock_all(th->keeping_mutexes, th);
@@ -427,10 +429,16 @@
 		    th->errinfo = Qnil;
 		    th->local_lfp = proc->block.lfp;
 		    th->local_svar = Qnil;
+		    if (TRACE_THREAD_ENTER_ENABLED()) {
+			VALUE filename = proc->block.iseq->filename;
+			int lineno = proc->block.iseq->line_no;
+			FIRE_THREAD_ENTER(th->self, (TYPE(filename) == T_STRING ? RSTRING_PTR(filename) : 0), lineno);
+		    }
 		    th->value = rb_vm_invoke_proc(th, proc, proc->block.self,
 						  (int)RARRAY_LEN(args), RARRAY_PTR(args), 0);
 		}
 		else {
+		    if (TRACE_THREAD_ENTER_ENABLED()) FIRE_THREAD_ENTER(th->self, 0, 0);
 		    th->value = (*th->first_func)((void *)args);
 		}
 	    });
@@ -461,6 +469,7 @@
 
 	th->status = THREAD_KILLED;
 	thread_debug("thread end: %p\n", (void *)th);
+	if (TRACE_THREAD_LEAVE_ENABLED()) FIRE_THREAD_LEAVE(th->self, 0, 0);
 
 	main_th = th->vm->main_thread;
 	if (th != main_th) {
@@ -533,6 +542,7 @@
     native_mutex_initialize(&th->interrupt_lock);
     /* kick thread */
     st_insert(th->vm->living_threads, thval, (st_data_t) th->thread_id);
+    if (TRACE_THREAD_INIT_ENABLED()) FIRE_THREAD_INIT(th->self, rb_sourcefile(), rb_sourceline());
     err = native_thread_create(th);
     if (err) {
 	st_delete_wrap(th->vm->living_threads, th->self);
@@ -982,6 +992,7 @@
 	rb_thread_t *th = GET_THREAD();
 
 	thread_debug("rb_thread_schedule/switch start\n");
+        if (TRACE_THREAD_LEAVE_ENABLED()) FIRE_THREAD_LEAVE(th->self, rb_sourcefile(), rb_sourceline());
 
 	RB_GC_SAVE_MACHINE_CONTEXT(th);
 	native_mutex_unlock(&th->vm->global_vm_lock);
@@ -992,6 +1003,7 @@
 
 	rb_thread_set_current(th);
 	thread_debug("rb_thread_schedule/switch done\n");
+        if (TRACE_THREAD_ENTER_ENABLED()) FIRE_THREAD_ENTER(th->self, rb_sourcefile(), rb_sourceline());
 
         if (!sched_depth && UNLIKELY(GET_THREAD()->interrupt_flag)) {
             rb_threadptr_execute_interrupts_rec(GET_THREAD(), sched_depth+1);
Index: common.mk
===================================================================
--- common.mk	(revision 26234)
+++ common.mk	(revision 26235)
@@ -142,11 +142,11 @@
 
 $(PREP): $(MKFILES)
 
-miniruby$(EXEEXT): config.status $(NORMALMAINOBJ) $(MINIOBJS) $(COMMONOBJS) $(DMYEXT) $(ARCHFILE)
+miniruby$(EXEEXT): config.status $(NORMALMAINOBJ) $(MINIOBJS) $(COMMONOBJS) $(DMYEXT) $(ARCHFILE) $(MINIDTRACE_OBJ)
 
 GORUBY = go$(RUBY_INSTALL_NAME)
-golf: $(LIBRUBY) $(GOLFOBJS) PHONY
-	$(MAKE) $(MFLAGS) MAINOBJ="$(GOLFOBJS)" PROGRAM=$(GORUBY)$(EXEEXT) program
+golf: $(LIBRUBY) $(GOLFOBJS) $(GOLFDTRACE_OBJ) PHONY
+	$(MAKE) $(MFLAGS) MAINOBJ="$(GOLFOBJS)" DTRACE_OBJ="$(GOLFDTRACE_OBJ)" PROGRAM=$(GORUBY)$(EXEEXT) program
 capi: Doxyfile PHONY $(PREP)
 	@$(MAKEDIRS) doc/capi
 	@$(DOXYGEN)
@@ -157,9 +157,9 @@
 
 program: $(PROGRAM)
 
-$(PROGRAM): $(LIBRUBY) $(MAINOBJ) $(OBJS) $(EXTOBJS) $(SETUP) $(PREP)
+$(PROGRAM): $(LIBRUBY) $(MAINOBJ) $(OBJS) $(EXTOBJS) $(DTRACE_OBJ) $(SETUP) $(PREP)
 
-$(LIBRUBY_A):	$(OBJS) $(DMYEXT) $(ARCHFILE)
+$(LIBRUBY_A):	$(OBJS) $(DMYEXT) $(LIBRUBY_DTRACE_OBJ) $(ARCHFILE)
 
 $(LIBRUBY_SO):	$(OBJS) $(DLDOBJS) $(LIBRUBY_A) $(PREP) $(LIBRUBY_SO_UPDATE) $(BUILTIN_ENCOBJS)
 
@@ -385,6 +385,7 @@
 distclean-local:: clean-local
 	@$(RM) $(MKFILES) rbconfig.rb yasmdata.rb encdb.h
 	@$(RM) config.cache config.log config.status config.status.lineno $(PRELUDES)
+	@$(RM) $(arch_hdrdir)/ruby/dtrace.d
 	@$(RM) *~ *.bak *.stackdump core *.core gmon.out $(PREP)
 distclean-ext:: PHONY
 distclean-golf: clean-golf
@@ -511,7 +512,8 @@
 ###
 
 RUBY_H_INCLUDES    = {$(VPATH)}ruby.h {$(VPATH)}config.h {$(VPATH)}defines.h \
-		     {$(VPATH)}intern.h {$(VPATH)}missing.h {$(VPATH)}st.h
+		     {$(VPATH)}intern.h {$(VPATH)}missing.h {$(VPATH)}st.h \
+		     {$(VPATH)}trace.h {$(VPATH)}trace_$(TRACING_MODEL).h
 ENCODING_H_INCLUDES= {$(VPATH)}encoding.h {$(VPATH)}oniguruma.h
 ID_H_INCLUDES      = {$(VPATH)}id.h
 VM_CORE_H_INCLUDES = {$(VPATH)}vm_core.h {$(VPATH)}vm_opts.h \
@@ -678,6 +680,9 @@
   {$(VPATH)}intern.h {$(VPATH)}missing.h {$(VPATH)}st.h \
   {$(VPATH)}transcode_data.h {$(VPATH)}ruby.h {$(VPATH)}config.h
 
+trace_none.h:
+	echo > $@
+
 INSNS2VMOPT = --srcdir="$(srcdir)"
 
 {$(VPATH)}minsns.inc: $(srcdir)/template/minsns.inc.tmpl
Index: eval.c
===================================================================
--- eval.c	(revision 26234)
+++ eval.c	(revision 26235)
@@ -424,9 +424,13 @@
 
     rb_trap_restore_mask();
 
-    if (tag != TAG_FATAL) {
+    if (tag == TAG_FATAL) {
+        if (UNLIKELY(TRACE_RAISE_ENABLED())) FIRE_RAISE(0, (char*)"fatal", (char*)file, line);
+    }
+    else {
 	EXEC_EVENT_HOOK(th, RUBY_EVENT_RAISE, th->cfp->self,
 			0 /* TODO: id */, 0 /* TODO: klass */);
+        if (UNLIKELY(TRACE_RAISE_ENABLED())) FIRE_RAISE(mesg, (char*)rb_class2name(CLASS_OF(mesg)), (char*)file, line);
     }
 
     rb_thread_raised_clear(th);
@@ -633,6 +637,9 @@
 	    va_end(args);
 
 	    if (handle) {
+		if (UNLIKELY(TRACE_RESCUE_ENABLED())) {
+		    FIRE_RESCUE(th->errinfo, (char*)rb_class2name(CLASS_OF(th->errinfo)), (char*)"<unknown>", 0);
+		}
 		if (r_proc) {
 		    PUSH_TAG();
 		    if ((state = EXEC_TAG()) == 0) {
Index: gc.c
===================================================================
--- gc.c	(revision 26234)
+++ gc.c	(revision 26235)
@@ -460,6 +460,7 @@
 	else {
 	    /* no ruby thread */
 	    fprintf(stderr, "[FATAL] failed to allocate memory\n");
+            if (UNLIKELY(TRACE_RAISE_ENABLED())) FIRE_RAISE_FATAL();
 	    exit(EXIT_FAILURE);
 	}
     }
@@ -472,6 +473,7 @@
     if (!nomem_error ||
 	(rb_thread_raised_p(th, RAISED_NOMEMORY) && rb_safe_level() < 4)) {
 	fprintf(stderr, "[FATAL] failed to allocate memory\n");
+        if (UNLIKELY(TRACE_RAISE_ENABLED())) FIRE_RAISE_FATAL();
 	exit(EXIT_FAILURE);
     }
     if (rb_thread_raised_p(th, RAISED_NOMEMORY)) {
@@ -604,6 +606,7 @@
 	}
 	else {
 	    fprintf(stderr, "[FATAL] %s\n", msg);
+            if (UNLIKELY(TRACE_RAISE_ENABLED())) FIRE_RAISE_FATAL();
 	    exit(EXIT_FAILURE);
 	}
     }
@@ -629,6 +632,7 @@
 	else {
 	    /* no ruby thread */
 	    fprintf(stderr, "[FATAL] failed to allocate memory\n");
+            if (UNLIKELY(TRACE_RAISE_ENABLED())) FIRE_RAISE_FATAL();
 	    exit(EXIT_FAILURE);
 	}
     }
@@ -1973,6 +1977,8 @@
 	break;
     }
 
+    if (TRACE_OBJECT_FREE_ENABLED()) FIRE_OBJECT_FREE(rb_obj_id(obj));
+
     if (FL_TEST(obj, FL_EXIVAR)) {
 	rb_free_generic_ivar((VALUE)obj);
 	FL_UNSET(obj, FL_EXIVAR);
@@ -2153,6 +2159,7 @@
     during_gc++;
     objspace->count++;
 
+    if (TRACE_GC_BEGIN_ENABLED()) FIRE_GC_BEGIN();
     GC_PROF_TIMER_START;
     GC_PROF_MARK_TIMER_START;
     SET_STACK_END;
@@ -2201,6 +2208,7 @@
     GC_PROF_SWEEP_TIMER_STOP;
 
     GC_PROF_TIMER_STOP;
+    if (TRACE_GC_END_ENABLED()) FIRE_GC_END();
     if (GC_NOTIFY) printf("end garbage_collect()\n");
     return TRUE;
 }
Index: Makefile.in
===================================================================
--- Makefile.in	(revision 26234)
+++ Makefile.in	(revision 26235)
@@ -52,6 +52,7 @@
 warnflags = @warnflags@
 XCFLAGS = -I. -I$(arch_hdrdir) -I$(hdrdir) -I$(srcdir) @XCFLAGS@
 CPPFLAGS = @CPPFLAGS@
+CPPOUTFILE = @CPPOUTFILE@
 LDFLAGS = @STATIC@ $(CFLAGS) @LDFLAGS@
 EXTLDFLAGS = 
 XLDFLAGS = @XLDFLAGS@ $(EXTLDFLAGS)
@@ -66,6 +67,10 @@
 BUILTIN_ENCOBJS = @BUILTIN_ENCOBJS@
 BUILTIN_TRANSSRCS = @BUILTIN_TRANSSRCS@
 BUILTIN_TRANSOBJS = @BUILTIN_TRANSOBJS@
+DTRACE_OBJ      = @DTRACE_OBJ@
+MINIDTRACE_OBJ  = @MINIDTRACE_OBJ@
+GOLFDTRACE_OBJ  = @GOLFDTRACE_OBJ@
+LIBRUBY_DTRACE_OBJ  = @LIBRUBY_DTRACE_OBJ@
 
 RUBY_BASE_NAME=@RUBY_BASE_NAME@
 RUBY_INSTALL_NAME=@RUBY_INSTALL_NAME@
@@ -92,6 +97,7 @@
 LIBRUBYARG_SHARED = @LIBRUBYARG_SHARED@
 
 THREAD_MODEL  = @THREAD_MODEL@
+TRACING_MODEL = @TRACING_MODEL@
 
 PREP          = @PREP@
 ARCHFILE      = @ARCHFILE@
@@ -115,8 +121,10 @@
 SET_LC_MESSAGES = env LC_MESSAGES=C
 OBJDUMP       = @OBJDUMP@
 OBJCOPY       = @OBJCOPY@
+DTRACE        = @DTRACE@
 VCS           = @VCS@
 VCSUP         = @VCSUP@
+DOXYGEN	      = @DOXYGEN@
 
 OBJEXT        = @OBJEXT@
 ASMEXT        = S
@@ -139,28 +147,37 @@
 
 miniruby$(EXEEXT):
 		@-if test -f $@; then $(MV) -f $@ $@.old; $(RM) $@.old; fi
-		$(PURIFY) $(CC) $(LDFLAGS) $(XLDFLAGS) $(MAINLIBS) $(MAINOBJ) $(MINIOBJS) $(COMMONOBJS) $(DMYEXT) $(LIBS) $(OUTFLAG)$@
+		$(PURIFY) $(CC) $(LDFLAGS) $(XLDFLAGS) $(MAINLIBS) $(MAINOBJ) $(MINIOBJS) $(COMMONOBJS) $(DMYEXT) $(MINIDTRACE_OBJ) $(LIBS) $(OUTFLAG)$@
+$(MINIDTRACE_OBJ): $(arch_hdrdir)/ruby/dtrace.d $(NORMALMAINOBJ) $(MINIOBJS) $(COMMONOBJS) $(DMYEXT)
+		$(DTRACE) -G -o $@ -s $(arch_hdrdir)/ruby/dtrace.d $(NORMALMAINOBJ) $(MINIOBJS) $(COMMONOBJS) $(DMYEXT)
 
 $(PROGRAM):
 		@$(RM) $@
-		$(PURIFY) $(CC) $(LDFLAGS) $(XLDFLAGS) $(MAINLIBS) $(MAINOBJ) $(EXTOBJS) $(LIBRUBYARG) $(LIBS) $(OUTFLAG)$@
+		$(PURIFY) $(CC) $(LDFLAGS) $(XLDFLAGS) $(MAINLIBS) $(MAINOBJ) $(EXTOBJS) $(DTRACE_OBJ) $(LIBRUBYARG) $(LIBS) $(OUTFLAG)$@
+$(DTRACE_OBJ): $(arch_hdrdir)/ruby/dtrace.d $(MAINOBJ) $(EXTOBJS)
+		$(DTRACE) -G -o $@ -s $(arch_hdrdir)/ruby/dtrace.d $(MAINOBJ) $(EXTOBJS)
+$(GOLFDTRACE_OBJ): $(arch_hdrdir)/ruby/dtrace.d $(GOLFOBJS) $(EXTOBJS)
+		$(DTRACE) -G -o $@ -s $(arch_hdrdir)/ruby/dtrace.d $(GOLFOBJS) $(EXTOBJS)
 
 # 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):
 		@$(RM) $@
-		$(AR) $(ARFLAGS) $@ $(OBJS) $(DMYEXT)
+		$(AR) $(ARFLAGS) $@ $(OBJS) $(DMYEXT) $(LIBRUBY_DTRACE_OBJ)
 		@-$(RANLIB) $@ 2> /dev/null || true
 
 $(LIBRUBY_SO):
 		@-$(PRE_LIBRUBY_UPDATE)
-		$(LDSHARED) $(DLDFLAGS) $(OBJS) $(DLDOBJS) $(SOLIBS) $(OUTFLAG)$@
+		$(LDSHARED) $(DLDFLAGS) $(OBJS) $(DLDOBJS) $(LIBRUBY_DTRACE_OBJ) $(SOLIBS) $(OUTFLAG)$@
 		-$(OBJCOPY) -w -L '@EXPORT_PREFIX@Init_*' -L '@EXPORT_PREFIX@*_threadptr_*' $@
 		@-$(MINIRUBY) -e 'ARGV.each{|link| File.delete link if File.exist? link; \
 						  File.symlink "$(LIBRUBY_SO)", link}' \
 				$(LIBRUBY_ALIASES) || true
 
+$(LIBRUBY_DTRACE_OBJ): $(arch_hdrdir)/ruby/dtrace.d $(OBJS) $(DMYEXT)
+		$(DTRACE) -G -o $@ -s $(arch_hdrdir)/ruby/dtrace.d $(OBJS) $(DMYEXT)
+
 fake: $(arch)-fake.rb
 $(arch)-fake.rb: config.status
 		@./config.status --file=$@:$(srcdir)/template/fake.rb.in
@@ -188,6 +205,22 @@
 
 incs: id.h
 
+$(arch_hdrdir)/ruby/trace_dtrace.h: $(arch_hdrdir)/ruby/dtrace.d
+	$(DTRACE) -h -o $@ -s $(arch_hdrdir)/ruby/dtrace.d
+
+# NOTE: dtrace is not used on cross compiling
+$(arch_hdrdir)/ruby/dtrace.d: $(srcdir)/defs/dtrace.d
+	@echo '#include <limits.h>' > conftest.c
+	@echo '#define RUBY_TRACE_H' >> conftest.c
+	@echo '#include "ruby/ruby.h"' >> conftest.c
+	@echo 'int main(){ printf("%d", SIZEOF_VALUE * CHAR_BIT); return 0; }' >> conftest.c
+	@$(CC) $(CFLAGS) $(XCFLAGS) $(CPPFLAGS) -c $(COUTFLAG)conftest.o conftest.c 
+	$(CC) $(LDFLAGS) $(XLDFLAGS) conftest.o $(LIBS) $(OUTFLAG)conftest
+	@$(CP) $(srcdir)/defs/dtrace.d dtrace.c
+	$(CPP) $(CPPFLAGS) -DBITSIZE_OF_VALUE=`./conftest` dtrace.c $(CPPOUTFILE)
+	$(MV) conftest.i $@
+	@$(RM) conftest conftest.[co] dtrace.c
+
 # Things which should be considered:
 # * with gperf v.s. without gperf
 # * committers may have various versions of gperf
Index: ext/probe/extconf.rb
===================================================================
--- ext/probe/extconf.rb	(revision 0)
+++ ext/probe/extconf.rb	(revision 26235)
@@ -0,0 +1,3 @@
+require 'mkmf'
+create_makefile('probe')
+
Index: ext/probe/probe.c
===================================================================
--- ext/probe/probe.c	(revision 0)
+++ ext/probe/probe.c	(revision 26235)
@@ -0,0 +1,47 @@
+/**
+ * probe.c - 
+ *
+ * $Author$
+ *
+ * Based on the patch for Ruby 1.8.6 by Joyent Inc.
+ *
+ * Copyright 2007 Joyent Inc.
+ * Copyright 2009 Yuki Sonoda (Yugui).
+ */
+#include "ruby/ruby.h"
+
+#define FIRE_WITH_SUFFIXED_MSG(probe_name, probe_data, suffix) \
+    if (TRACE_RUBY_PROBE_ENABLED()) { \
+        char *msg = ALLOCA_N(char, strlen(probe_name) + strlen("-" #suffix) ); \
+        sprintf(msg, "%s%s", probe_name, "-" #suffix); \
+        FIRE_RUBY_PROBE(msg, (char*)probe_data); \
+    }
+
+static VALUE
+probe_fire(int argc, VALUE *argv, VALUE klass)
+{
+    int args;
+    VALUE name, data, ret;
+    const char *probe_data;
+    char *probe_name;
+
+    args = rb_scan_args(argc, argv, "11", &name, &data);
+    probe_data = args == 2 ? StringValuePtr(data) : "";
+    probe_name = StringValuePtr(name);
+
+    if (rb_block_given_p()) {
+        FIRE_WITH_SUFFIXED_MSG(probe_name, probe_data, start);
+	ret = rb_yield(Qnil);
+        FIRE_WITH_SUFFIXED_MSG(probe_name, probe_data, end);
+    } else {
+	if (TRACE_RUBY_PROBE_ENABLED())
+	    FIRE_RUBY_PROBE(probe_name, (char*)probe_data);
+	ret = Qnil;
+    }
+    return ret;
+}
+
+void Init_probe()
+{
+    rb_define_global_function("fire_probe", probe_fire, -1);
+}
Index: vm_exec.h
===================================================================
--- vm_exec.h	(revision 26234)
+++ vm_exec.h	(revision 26235)
@@ -52,8 +52,39 @@
 #else
 
 #define debugs
-#define DEBUG_ENTER_INSN(insn)
-#define DEBUG_END_INSN()
+extern const char *rb_vm_insn_name(int);
+#define DEBUG_ENTER_INSN(insn) \
+    do { \
+	if (UNLIKELY(TRACE_INSN_ENTRY_ENABLED())) { \
+	    rb_control_frame_t *cfp = GET_CFP(); \
+	    rb_iseq_t *iseq = cfp->iseq; \
+	    if (iseq != NULL && VM_FRAME_TYPE(cfp) != VM_FRAME_MAGIC_FINISH) { \
+		VALUE *seq = iseq->iseq; \
+		int pc = cfp->pc - iseq->iseq_encoded; \
+		FIRE_INSN_ENTRY((char *)rb_vm_insn_name(seq[pc]), \
+                        seq+1, \
+			(char *)rb_sourcefile(), \
+			rb_sourceline()); \
+	    } \
+	} \
+    } \
+    while (0)
+#define DEBUG_END_INSN() \
+    do { \
+	if (UNLIKELY(TRACE_INSN_RETURN_ENABLED())) { \
+	    rb_control_frame_t *cfp = GET_CFP(); \
+	    rb_iseq_t *iseq = cfp->iseq; \
+	    if (iseq != NULL && VM_FRAME_TYPE(cfp) != VM_FRAME_MAGIC_FINISH) { \
+		VALUE *seq = iseq->iseq; \
+		int pc = cfp->pc - iseq->iseq_encoded; \
+		FIRE_INSN_RETURN((char *)rb_vm_insn_name(seq[pc]), \
+                        seq+1, \
+			(char *)rb_sourcefile(), \
+			rb_sourceline()); \
+	    } \
+	} \
+    } \
+    while (0)
 #endif
 
 #define throwdebug if(0)printf
Index: NEWS
===================================================================
--- NEWS	(revision 26234)
+++ NEWS	(revision 26235)
@@ -217,6 +217,10 @@
     * Pathname#realdirpath
     * Pathname#each_child
 
+* probe
+  new library.
+  * Kernel#fire_probe
+
 * Readline
   * new methods:
     * Readline.set_screen_size
@@ -261,6 +265,14 @@
   Unicode semantics
 * $: no longer includes the current directory, use require_relative
 
+=== Tracing (experimental)
+
+* Runtime tracing is supported. Currently implemented on top of dtrace.
+  You can trace a ruby program without any modification if your platform
+  supports dtrace USDT.
+
+  This feature is experimental. The semantics of probes will possibly change.
+
 === Compilation options
 
 * --program-prefix and --program-suffix no longer act on the shared object
@@ -272,6 +284,8 @@
 * --with-arch is added for universal binary, instead of
   --enable-fat-binary option.
 
+* --with-tracing-model is added for choosing a particular tracing mechanism.
+
 === Compatibility issues (excluding feature bug fixes)
 
   * Enumerator#rewind
Index: vm.c
===================================================================
--- vm.c	(revision 26234)
+++ vm.c	(revision 26235)
@@ -2072,6 +2072,7 @@
     rb_thread_t * th = malloc(sizeof(*th));
     if (!vm || !th) {
 	fprintf(stderr, "[FATAL] failed to allocate memory\n");
+        if (TRACE_RAISE_ENABLED()) FIRE_RAISE_FATAL();
 	exit(EXIT_FAILURE);
     }
     MEMZERO(th, rb_thread_t, 1);
Index: tool/rbinstall.rb
===================================================================
--- tool/rbinstall.rb	(revision 26234)
+++ tool/rbinstall.rb	(revision 26235)
@@ -346,7 +346,7 @@
 end
 install?(:ext, :arch, :'ext-arch') do
   prepare "extension headers", archhdrdir
-  install_recursive("#{$extout}/include/#{CONFIG['arch']}", archhdrdir, :glob => "*.h", :mode => $data_mode)
+  install_recursive("#{$extout}/include/#{CONFIG['arch']}", archhdrdir, :glob => "*.[dh]", :mode => $data_mode)
 end
 install?(:ext, :comm, :'ext-comm') do
   prepare "extension scripts", rubylibdir

--
ML: ruby-changes@q...
Info: http://www.atdot.net/~ko1/quickml/

[前][次][番号順一覧][スレッド一覧]