xray 1.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (30) hide show
  1. data/README +65 -0
  2. data/bin/install_dtrace_on_ubuntu +30 -0
  3. data/bin/xray_profile_ruby_function_calls.d +54 -0
  4. data/bin/xray_top_10_busiest_code_path_for_process.d +12 -0
  5. data/bin/xray_top_10_busiest_code_path_on_system.d +35 -0
  6. data/bin/xray_trace_all_custom_ruby_probes.d +25 -0
  7. data/bin/xray_trace_all_ruby_probes.d +20 -0
  8. data/bin/xray_trace_memcached.d +20 -0
  9. data/bin/xray_trace_mysql.d +30 -0
  10. data/bin/xray_trace_rails_response_times.d +114 -0
  11. data/lib/xray.rb +2 -0
  12. data/lib/xray/dtrace/rails/action_controller_tracing_extension.rb +22 -0
  13. data/lib/xray/dtrace/rails/active_record_connection_tracing_extension.rb +15 -0
  14. data/lib/xray/dtrace/rails/enable_tracing.rb +25 -0
  15. data/lib/xray/dtrace/tracer.rb +86 -0
  16. data/lib/xray/dtrace/tracer/joyent.rb +25 -0
  17. data/lib/xray/dtrace/tracer/leopard.rb +28 -0
  18. data/lib/xray/dtrace/usdt/provider_extensions.rb +45 -0
  19. data/lib/xray/thread_dump_signal_handler.rb +31 -0
  20. data/patches_for_mri/caller_for_all_threads_patch_for_MRI_1.8.6.diff +229 -0
  21. data/patches_for_mri/caller_for_all_threads_patch_for_MRI_1.8.7.diff +229 -0
  22. data/patches_for_mri/patch-for-dtrace-instrumentation-of-matz-1.8.6-p114.diff +522 -0
  23. data/patches_for_mri/patch-for-joyent-mri-1.8.6-on-mac-os-x-leopard.diff +20645 -0
  24. data/rails/init.rb +2 -0
  25. data/test/all_tests.rb +1 -0
  26. data/test/functional/dtrace/tracer_test.rb +54 -0
  27. data/test/functional/tracer_script.rb +18 -0
  28. data/test/test_helper.rb +9 -0
  29. data/test/unit/xray/dtrace/tracer_test.rb +54 -0
  30. metadata +84 -0
@@ -0,0 +1,229 @@
1
+ Index: test/callerforallthreads/test_caller_for_each_thread.rb
2
+ ===================================================================
3
+ --- test/callerforallthreads/test_caller_for_each_thread.rb (revision 0)
4
+ +++ test/callerforallthreads/test_caller_for_each_thread.rb (revision 0)
5
+ @@ -0,0 +1,95 @@
6
+ +# -*- ruby-indent-level: 4 -*-
7
+ +require 'thread'
8
+ +require 'test/unit'
9
+ +
10
+ +class AClassWithNestedmethods
11
+ +
12
+ + def an_ultra_nested_method(skip)
13
+ + caller_for_all_threads skip
14
+ + end
15
+ +
16
+ + def a_nested_method(skip)
17
+ + an_ultra_nested_method skip
18
+ + end
19
+ +
20
+ + def a_method(skip=0)
21
+ + a_nested_method skip
22
+ + end
23
+ +
24
+ +end
25
+ +
26
+ +class CallerForEachThreadTest < Test::Unit::TestCase
27
+ +
28
+ + def testCollectMeaningfulBacktraceForASingleThread
29
+ + backtraces = AClassWithNestedmethods.new.a_method
30
+ + backtrace = backtraces[Thread.current]
31
+ + assert_not_nil backtrace
32
+ + assert_equal __FILE__ + ":8:in `an_ultra_nested_method'", backtrace[0]
33
+ + assert_equal __FILE__ + ":12:in `a_nested_method'", backtrace[1]
34
+ + assert_equal __FILE__ + ":16:in `a_method'", backtrace[2]
35
+ + assert_equal __FILE__ + ":24:in `testCollectMeaningfulBacktraceForASingleThread'",
36
+ + backtrace[3]
37
+ + end
38
+ +
39
+ + def testCanSkipFirstStackEntries
40
+ + backtraces = AClassWithNestedmethods.new.a_method 2
41
+ + backtrace = backtraces[Thread.current]
42
+ + assert_not_nil backtrace
43
+ + assert_equal __FILE__ + ":16:in `a_method'", backtrace[0]
44
+ + assert_equal __FILE__ + ":35:in `testCanSkipFirstStackEntries'",
45
+ + backtrace[1]
46
+ + end
47
+ +
48
+ + def testCollectMeaningfulBacktraceForMultipleThreads
49
+ + first_thread = Thread.new do
50
+ + loop do
51
+ + Thread.pass
52
+ + sleep 1
53
+ + end
54
+ + end
55
+ +
56
+ + second_thread = Thread.new do
57
+ + loop do
58
+ + Thread.pass
59
+ + sleep 1
60
+ + end
61
+ + end
62
+ +
63
+ + backtraces = AClassWithNestedmethods.new.a_method
64
+ +
65
+ + backtrace = backtraces[Thread.current]
66
+ + assert_not_nil backtrace
67
+ + assert_match __FILE__ + ":8:in `an_ultra_nested_method'", backtrace[0]
68
+ + assert_match __FILE__ + ":12:in `a_nested_method'", backtrace[1]
69
+ + assert_equal __FILE__ + ":16:in `a_method'", backtrace[2]
70
+ + assert_equal __FILE__ + ":58:in `testCollectMeaningfulBacktraceForMultipleThreads'",
71
+ + backtrace[3]
72
+ +
73
+ + backtrace = backtraces[first_thread]
74
+ + assert_not_nil backtrace
75
+ + assert_equal __FILE__ + ":47:in `testCollectMeaningfulBacktraceForMultipleThreads'",
76
+ + backtrace[0]
77
+ + assert_equal __FILE__ + ":45:in `loop'",
78
+ + backtrace[1]
79
+ + assert_equal __FILE__ + ":45:in `testCollectMeaningfulBacktraceForMultipleThreads'",
80
+ + backtrace[2]
81
+ + assert_equal __FILE__ + ":44:in `initialize'",backtrace[3]
82
+ + assert_equal __FILE__ + ":44:in `new'", backtrace[4]
83
+ + assert_equal __FILE__ + ":44:in `testCollectMeaningfulBacktraceForMultipleThreads'",
84
+ + backtrace[5]
85
+ +
86
+ + backtrace = backtraces[second_thread]
87
+ + assert_not_nil backtrace
88
+ + assert_equal __FILE__ + ":53:in `testCollectMeaningfulBacktraceForMultipleThreads'",
89
+ + backtrace[0]
90
+ + assert_equal __FILE__ + ":52:in `loop'", backtrace[1]
91
+ + assert_equal __FILE__ + ":52:in `testCollectMeaningfulBacktraceForMultipleThreads'",
92
+ + backtrace[2]
93
+ + assert_equal __FILE__ + ":51:in `initialize'",backtrace[3]
94
+ + assert_equal __FILE__ + ":51:in `new'", backtrace[4]
95
+ + assert_equal __FILE__ + ":51:in `testCollectMeaningfulBacktraceForMultipleThreads'",
96
+ + backtrace[5]
97
+ + end
98
+ +
99
+ +end
100
+ +
101
+ Index: eval.c
102
+ ===================================================================
103
+ --- eval.c (revision 16289)
104
+ +++ eval.c (working copy)
105
+ @@ -7969,6 +7969,17 @@
106
+ ruby_safe_level = safe;
107
+ }
108
+
109
+ +/* Hash (Thread => Backtrace) used to collect backtrace for each threads. */
110
+ +static VALUE backtrace_for_each_thread;
111
+ +
112
+ +static int backtrace_level_for_each_thread;
113
+ +
114
+ +static VALUE
115
+ +switch_thread_context_to_collect_backtrace(rb_thread_t next);
116
+ +
117
+ +static VALUE
118
+ +rb_f_caller_for_all_threads();
119
+ +
120
+ void
121
+ Init_eval()
122
+ {
123
+ @@ -8014,6 +8025,7 @@
124
+ rb_define_global_function("fail", rb_f_raise, -1);
125
+
126
+ rb_define_global_function("caller", rb_f_caller, -1);
127
+ + rb_define_global_function("caller_for_all_threads", rb_f_caller_for_all_threads, -1);
128
+
129
+ rb_define_global_function("exit", rb_f_exit, -1);
130
+ rb_define_global_function("abort", rb_f_abort, -1);
131
+ @@ -10206,6 +10218,7 @@
132
+ #define RESTORE_RAISE 5
133
+ #define RESTORE_SIGNAL 6
134
+ #define RESTORE_EXIT 7
135
+ +#define RESTORE_BACKTRACE 8
136
+
137
+ extern VALUE *rb_gc_stack_start;
138
+ #ifdef __ia64
139
+ @@ -10313,6 +10326,15 @@
140
+ }
141
+ rb_exc_raise(th_raise_exception);
142
+ break;
143
+ + case RESTORE_BACKTRACE:
144
+ + rb_hash_aset(backtrace_for_each_thread, curr_thread->thread,
145
+ + backtrace(backtrace_level_for_each_thread));
146
+ + if (curr_thread != main_thread) {
147
+ + switch_thread_context_to_collect_backtrace(curr_thread->next);
148
+ + } else {
149
+ + /* Circled back to main thread, cycle is complete. */
150
+ + }
151
+ + break;
152
+ case RESTORE_NORMAL:
153
+ default:
154
+ break;
155
+ @@ -13240,3 +13262,74 @@
156
+ argv[1] = val;
157
+ rb_f_throw(2, argv);
158
+ }
159
+ +
160
+ +static VALUE
161
+ +switch_thread_context_to_collect_backtrace(rb_thread_t next)
162
+ +{
163
+ + if (THREAD_SAVE_CONTEXT(curr_thread)) {
164
+ + return Qnil;
165
+ + }
166
+ + curr_thread = next;
167
+ + rb_thread_restore_context(next, RESTORE_BACKTRACE);
168
+ + return Qnil;
169
+ +}
170
+ +
171
+ +
172
+ +/*
173
+ + * call-seq:
174
+ + * caller_for_all_threads(start=1) => array
175
+ + *
176
+ + * Returns the current execution stack for all threads
177
+ + * ---a hash whose keys are thread instances and values
178
+ + * the thread caller backtrace.
179
+ + *
180
+ + * Backtraces are array of hashes indicating location on the
181
+ + * stack. Hash keys include ``<em>:line</em>'' or ``<em>:file</em>''
182
+ + * and ``<em>:method'</em>''.
183
+ + *
184
+ + * The optional _start_ parameter
185
+ + * determines the number of initial stack entries to omit from the
186
+ + * result.
187
+ + *
188
+ + * def a(skip)
189
+ + * caller_for_all_threads(skip)
190
+ + * end
191
+ + * def b(skip)
192
+ + * a(skip)
193
+ + * end
194
+ + * def c(skip)
195
+ + * b(skip)
196
+ + * end
197
+ + * c(0) #=> ["prog:2:in `a'", "prog:5:in `b'", "prog:8:in `c'", "prog:10"]
198
+ + * c(1) #=> ["prog:5:in `b'", "prog:8:in `c'", "prog:11"]
199
+ + * c(2) #=> ["prog:8:in `c'", "prog:12"]
200
+ + * c(3) #=> ["prog:13"]
201
+ + */
202
+ +static VALUE
203
+ +rb_f_caller_for_all_threads(argc, argv)
204
+ + int argc;
205
+ + VALUE *argv;
206
+ +{
207
+ + volatile int critical;
208
+ + VALUE level;
209
+ + VALUE result;
210
+ +
211
+ + rb_scan_args(argc, argv, "01", &level);
212
+ + backtrace_level_for_each_thread = NIL_P(level) ? 0 : NUM2INT(level);
213
+ + if (backtrace_level_for_each_thread < 0) {
214
+ + rb_raise(rb_eArgError, "negative level (%d)", backtrace_level_for_each_thread);
215
+ + }
216
+ +
217
+ + critical = rb_thread_critical;
218
+ + rb_thread_critical = Qtrue;
219
+ +
220
+ + backtrace_for_each_thread = rb_hash_new();
221
+ + switch_thread_context_to_collect_backtrace(main_thread->next);
222
+ +
223
+ + result = backtrace_for_each_thread;
224
+ + backtrace_for_each_thread = Qnil;
225
+ + backtrace_for_each_thread = 0;
226
+ +
227
+ + rb_thread_critical = critical;
228
+ + return result;
229
+ +}
@@ -0,0 +1,522 @@
1
+ Index: Makefile.in
2
+ ===================================================================
3
+ --- Makefile.in (revision 16089)
4
+ +++ Makefile.in (working copy)
5
+ @@ -86,6 +86,8 @@
6
+ OBJEXT = @OBJEXT@
7
+ MANTYPE = @MANTYPE@
8
+
9
+ +DTRACE_HEADER = @DTRACE_HEADER@
10
+ +
11
+ INSTALLED_LIST= .installed.list
12
+ #### End of variables
13
+
14
+ @@ -171,8 +173,11 @@
15
+ $(AS) $(ASFLAGS) -o $@ $<
16
+
17
+ clean-local::
18
+ - @$(RM) ext/extinit.c ext/extinit.$(OBJEXT)
19
+ + @$(RM) ext/extinit.c ext/extinit.$(OBJEXT) $(DTRACE_HEADER)
20
+
21
+ +dtrace.h: dtrace.d
22
+ + /usr/sbin/dtrace -h -s dtrace.d
23
+ +
24
+ distclean-local::
25
+ @$(RM) ext/config.cache $(RBCONFIG)
26
+
27
+ Index: configure.in
28
+ ===================================================================
29
+ --- configure.in (revision 16089)
30
+ +++ configure.in (working copy)
31
+ @@ -488,6 +488,11 @@
32
+ sys/mkdev.h sys/utime.h netinet/in_systm.h float.h ieeefp.h pthread.h \
33
+ ucontext.h intrinsics.h)
34
+
35
+ +AC_CHECK_HEADER(sys/sdt.h)
36
+ +if test "$ac_cv_header_sys_sdt_h" == "yes"; then
37
+ + AC_DEFINE(HAVE_SDT_H)
38
+ +fi
39
+ +
40
+ dnl Check additional types.
41
+ AC_CHECK_SIZEOF(rlim_t, 0, [
42
+ #ifdef HAVE_SYS_TYPES_H
43
+ @@ -547,6 +552,18 @@
44
+ AC_DEFINE(USE_SETREUID)
45
+ AC_DEFINE(USE_SETREGID)
46
+ fi
47
+ +
48
+ +AC_ARG_ENABLE(dtrace,
49
+ + [ --enable-dtrace enable DTrace support.],
50
+ + [enable_dtrace=$enableval])
51
+ +if test "$enable_dtrace" == "yes" -a "$ac_cv_header_sys_sdt_h" == "yes"; then
52
+ + AC_DEFINE(ENABLE_DTRACE)
53
+ + DTRACE_HEADER="dtrace.h"
54
+ +else
55
+ + DTRACE_HEADER=""
56
+ +fi
57
+ +AC_SUBST(DTRACE_HEADER)
58
+ +
59
+ AC_STRUCT_TIMEZONE
60
+ AC_CACHE_CHECK(for struct tm.tm_gmtoff, rb_cv_member_struct_tm_tm_gmtoff,
61
+ [AC_TRY_COMPILE([#include <time.h>],
62
+ Index: inits.c
63
+ ===================================================================
64
+ --- inits.c (revision 16089)
65
+ +++ inits.c (working copy)
66
+ @@ -45,6 +45,7 @@
67
+ void Init_Time _((void));
68
+ void Init_var_tables _((void));
69
+ void Init_version _((void));
70
+ +void Init_Tracer _((void));
71
+
72
+ void
73
+ rb_call_inits()
74
+ @@ -81,4 +82,5 @@
75
+ Init_GC();
76
+ Init_marshal();
77
+ Init_version();
78
+ + Init_Tracer();
79
+ }
80
+ Index: object.c
81
+ ===================================================================
82
+ --- object.c (revision 16089)
83
+ +++ object.c (working copy)
84
+ @@ -19,7 +19,35 @@
85
+ #include <errno.h>
86
+ #include <ctype.h>
87
+ #include <math.h>
88
+ +#ifdef ENABLE_DTRACE
89
+ +#include "dtrace.h"
90
+ +#include "node.h"
91
+ +#endif
92
+
93
+ +#ifdef ENABLE_DTRACE
94
+ +
95
+ +#define FIRE_OBJECT_CREATE_START_PROBE(ruby_current_node, klass) \
96
+ + if (RUBY_OBJECT_CREATE_START_ENABLED()) { \
97
+ + char *file = ruby_current_node == NULL ? "" : ruby_current_node->nd_file; \
98
+ + int line = ruby_current_node == NULL ? 0 : nd_line(ruby_current_node); \
99
+ + RUBY_OBJECT_CREATE_START(rb_class2name(klass), file, line); \
100
+ + }
101
+ +
102
+ +#define FIRE_OBJECT_CREATE_DONE_PROBE(ruby_current_node, klass) \
103
+ + if (RUBY_OBJECT_CREATE_DONE_ENABLED()) { \
104
+ + char *file = ruby_current_node == NULL ? "" : ruby_current_node->nd_file; \
105
+ + int line = ruby_current_node == NULL ? 0 : nd_line(ruby_current_node); \
106
+ + RUBY_OBJECT_CREATE_DONE(rb_class2name(klass), file, line); \
107
+ + }
108
+ +
109
+ +#else
110
+ +
111
+ +#define FIRE_OBJECT_CREATE_START_PROBE(ruby_current_node, klass) /* NOOP */
112
+ +#define FIRE_OBJECT_CREATE_DONE_PROBE(ruby_current_node, klass) /* NOOP */
113
+ +
114
+ +#endif
115
+ +
116
+ +
117
+ VALUE rb_mKernel;
118
+ VALUE rb_cObject;
119
+ VALUE rb_cModule;
120
+ @@ -1553,7 +1581,9 @@
121
+ if (FL_TEST(klass, FL_SINGLETON)) {
122
+ rb_raise(rb_eTypeError, "can't create instance of virtual class");
123
+ }
124
+ + FIRE_OBJECT_CREATE_START_PROBE(ruby_current_node, klass);
125
+ obj = rb_funcall(klass, ID_ALLOCATOR, 0, 0);
126
+ + FIRE_OBJECT_CREATE_DONE_PROBE(ruby_current_node, klass);
127
+ if (rb_obj_class(obj) != rb_class_real(klass)) {
128
+ rb_raise(rb_eTypeError, "wrong instance allocation");
129
+ }
130
+ Index: tracer.c
131
+ ===================================================================
132
+ --- tracer.c (revision 0)
133
+ +++ tracer.c (revision 0)
134
+ @@ -0,0 +1,73 @@
135
+ +#include "ruby.h"
136
+ +
137
+ +#ifdef ENABLE_DTRACE
138
+ +#include "dtrace.h"
139
+ +#endif
140
+ +
141
+ +VALUE rb_mDtrace;
142
+ +
143
+ +static VALUE
144
+ +ruby_dtrace_fire(argc, argv, klass)
145
+ + int argc;
146
+ + VALUE *argv;
147
+ + VALUE klass;
148
+ +{
149
+ + int args;
150
+ + VALUE name, data, ret;
151
+ + char *probe_data;
152
+ + char *probe_name;
153
+ + char *start_probe;
154
+ + char *end_probe;
155
+ +
156
+ +#ifdef ENABLE_DTRACE
157
+ +
158
+ + args = rb_scan_args(argc, argv, "11", &name, &data);
159
+ + probe_data = args == 2 ? StringValuePtr(data) : "";
160
+ + probe_name = StringValuePtr(name);
161
+ +
162
+ + if (rb_block_given_p()) {
163
+ + start_probe = malloc(strlen(probe_name) + 7);
164
+ + end_probe = malloc(strlen(probe_name) + 5);
165
+ +
166
+ + sprintf(start_probe, "%s-start", probe_name);
167
+ + sprintf(end_probe, "%s-end", probe_name);
168
+ +
169
+ + /* Build -start and -end strings for probe names */
170
+ + if (RUBY_RUBY_PROBE_ENABLED())
171
+ + RUBY_RUBY_PROBE(start_probe, probe_data);
172
+ +#endif
173
+ +
174
+ + ret = rb_yield(Qnil);
175
+ +
176
+ +#if ENABLE_DTRACE
177
+ + if (RUBY_RUBY_PROBE_ENABLED())
178
+ + RUBY_RUBY_PROBE(end_probe, probe_data);
179
+ +
180
+ + free(start_probe);
181
+ + free(end_probe);
182
+ + } else {
183
+ + if (RUBY_RUBY_PROBE_ENABLED())
184
+ + RUBY_RUBY_PROBE(probe_name, probe_data);
185
+ + ret = Qnil;
186
+ + }
187
+ +#endif
188
+ + return ret;
189
+ +}
190
+ +
191
+ +static VALUE
192
+ +ruby_dtrace_enabled(klass)
193
+ + VALUE klass;
194
+ +{
195
+ +#ifdef ENABLE_DTRACE
196
+ + return RUBY_RUBY_PROBE_ENABLED() ? Qtrue : Qfalse;
197
+ +#else
198
+ + return Qfalse;
199
+ +#endif
200
+ +}
201
+ +
202
+ +void Init_Tracer()
203
+ +{
204
+ + rb_mDtrace = rb_define_module("Tracer");
205
+ + rb_define_module_function(rb_mDtrace, "fire", ruby_dtrace_fire, -1);
206
+ + rb_define_module_function(rb_mDtrace, "enabled?", ruby_dtrace_enabled, 0);
207
+ +}
208
+ Index: dtrace.d
209
+ ===================================================================
210
+ --- dtrace.d (revision 0)
211
+ +++ dtrace.d (revision 0)
212
+ @@ -0,0 +1,26 @@
213
+ +/* -*- Mode: C -*- */
214
+ +
215
+ +provider ruby {
216
+ + probe function__entry(char*, char*, char*, int);
217
+ + probe function__return(char*, char*, char*, int);
218
+ + probe raise(char*, char*, int);
219
+ + probe rescue(char*, int);
220
+ + probe line(char*, int);
221
+ +
222
+ + /* gc probes */
223
+ + probe gc__begin();
224
+ + probe gc__end();
225
+ +
226
+ + /* Some initial memory type probes */
227
+ + probe object__create__start(char*, char*, int);
228
+ + probe object__create__done(char*, char*, int);
229
+ + probe object__free(char*);
230
+ +
231
+ + probe ruby__probe(char*, char*);
232
+ +};
233
+ +
234
+ +#pragma D attributes Evolving/Evolving/Common provider ruby provider
235
+ +#pragma D attributes Private/Private/Common provider ruby module
236
+ +#pragma D attributes Private/Private/Common provider ruby function
237
+ +#pragma D attributes Evolving/Evolving/Common provider ruby name
238
+ +#pragma D attributes Evolving/Evolving/Common provider ruby args
239
+ +
240
+ Index: common.mk
241
+ ===================================================================
242
+ --- common.mk (revision 16089)
243
+ +++ common.mk (working copy)
244
+ @@ -49,6 +49,7 @@
245
+ string.$(OBJEXT) \
246
+ struct.$(OBJEXT) \
247
+ time.$(OBJEXT) \
248
+ + tracer.$(OBJEXT) \
249
+ util.$(OBJEXT) \
250
+ variable.$(OBJEXT) \
251
+ version.$(OBJEXT) \
252
+ @@ -262,7 +263,7 @@
253
+
254
+ clean: clean-ext clean-local
255
+ clean-local::
256
+ - @$(RM) $(OBJS) $(MAINOBJ) $(WINMAINOBJ) $(LIBRUBY_A) $(LIBRUBY_SO) $(LIBRUBY) $(LIBRUBY_ALIASES)
257
+ + @$(RM) $(OBJS) $(MAINOBJ) $(WINMAINOBJ) $(LIBRUBY_A) $(LIBRUBY_SO) $(LIBRUBY) $(LIBRUBY_ALIASES) $(DTRACE_HEADER)
258
+ @$(RM) $(PROGRAM) $(WPROGRAM) miniruby$(EXEEXT) dmyext.$(OBJEXT) $(ARCHFILE) .*.time
259
+ clean-ext:
260
+ @-$(MINIRUBY) $(srcdir)/ext/extmk.rb $(EXTMK_ARGS) clean
261
+ @@ -363,7 +364,7 @@
262
+ error.$(OBJEXT): {$(VPATH)}error.c {$(VPATH)}ruby.h config.h \
263
+ {$(VPATH)}defines.h {$(VPATH)}intern.h {$(VPATH)}missing.h \
264
+ {$(VPATH)}env.h {$(VPATH)}st.h
265
+ -eval.$(OBJEXT): {$(VPATH)}eval.c {$(VPATH)}ruby.h config.h \
266
+ +eval.$(OBJEXT): $(DTRACE_HEADER) {$(VPATH)}eval.c {$(VPATH)}ruby.h config.h \
267
+ {$(VPATH)}defines.h {$(VPATH)}intern.h {$(VPATH)}missing.h \
268
+ {$(VPATH)}node.h {$(VPATH)}env.h {$(VPATH)}util.h \
269
+ {$(VPATH)}rubysig.h {$(VPATH)}st.h {$(VPATH)}dln.h
270
+ @@ -371,7 +372,7 @@
271
+ {$(VPATH)}defines.h {$(VPATH)}intern.h {$(VPATH)}missing.h \
272
+ {$(VPATH)}rubyio.h {$(VPATH)}rubysig.h {$(VPATH)}util.h \
273
+ {$(VPATH)}dln.h
274
+ -gc.$(OBJEXT): {$(VPATH)}gc.c {$(VPATH)}ruby.h config.h \
275
+ +gc.$(OBJEXT): $(DTRACE_HEADER) {$(VPATH)}gc.c {$(VPATH)}ruby.h config.h \
276
+ {$(VPATH)}defines.h {$(VPATH)}intern.h {$(VPATH)}missing.h \
277
+ {$(VPATH)}rubysig.h {$(VPATH)}st.h {$(VPATH)}node.h \
278
+ {$(VPATH)}env.h {$(VPATH)}re.h {$(VPATH)}regex.h
279
+ @@ -394,7 +395,7 @@
280
+ numeric.$(OBJEXT): {$(VPATH)}numeric.c {$(VPATH)}ruby.h config.h \
281
+ {$(VPATH)}env.h {$(VPATH)}defines.h {$(VPATH)}intern.h \
282
+ {$(VPATH)}missing.h
283
+ -object.$(OBJEXT): {$(VPATH)}object.c {$(VPATH)}ruby.h config.h \
284
+ +object.$(OBJEXT): $(DTRACE_HEADER) {$(VPATH)}object.c {$(VPATH)}ruby.h config.h \
285
+ {$(VPATH)}defines.h {$(VPATH)}intern.h {$(VPATH)}missing.h \
286
+ {$(VPATH)}st.h {$(VPATH)}util.h
287
+ pack.$(OBJEXT): {$(VPATH)}pack.c {$(VPATH)}ruby.h config.h \
288
+ Index: eval.c
289
+ ===================================================================
290
+ --- eval.c (revision 16089)
291
+ +++ eval.c (working copy)
292
+ @@ -217,6 +217,9 @@
293
+ #endif
294
+
295
+ #include <sys/stat.h>
296
+ +#ifdef ENABLE_DTRACE
297
+ +#include "dtrace.h"
298
+ +#endif
299
+
300
+ VALUE rb_cProc;
301
+ VALUE rb_cBinding;
302
+ @@ -1138,6 +1141,53 @@
303
+ } \
304
+ } while (0)
305
+
306
+ +#ifdef ENABLE_DTRACE
307
+ +
308
+ +#define FIRE_LINE_PROBE(ruby_current_node) \
309
+ + if (RUBY_LINE_ENABLED()) { \
310
+ + if (ruby_current_node && ruby_current_node->nd_file) { \
311
+ + RUBY_LINE(ruby_current_node->nd_file, nd_line(ruby_current_node)); \
312
+ + } \
313
+ + }
314
+ +
315
+ +#define FIRE_RESCUE_PROBE(ruby_current_node) \
316
+ + if (RUBY_RESCUE_ENABLED()) { \
317
+ + if (ruby_current_node && ruby_current_node->nd_file) { \
318
+ + RUBY_RESCUE(ruby_current_node->nd_file, nd_line(ruby_current_node)); \
319
+ + } \
320
+ + }
321
+ +
322
+ +#define FIRE_RAISE_PROBE(ruby_errinfo, ruby_sourcefile, ruby_sourceline) \
323
+ + if (RUBY_RAISE_ENABLED()) { \
324
+ + RUBY_RAISE(rb_obj_classname(ruby_errinfo), ruby_sourcefile, ruby_sourceline); \
325
+ + }
326
+ +
327
+ +#define FIRE_FUNCTION_ENTRY(ruby_current_node, klass, id) \
328
+ + if (RUBY_FUNCTION_ENTRY_ENABLED()) { \
329
+ + char *classname = rb_class2name(klass), *methodname = rb_id2name(id); \
330
+ + if (ruby_current_node && ruby_current_node->nd_file && classname && methodname) { \
331
+ + RUBY_FUNCTION_ENTRY(classname, methodname, ruby_current_node->nd_file, nd_line(ruby_current_node)); \
332
+ + } \
333
+ + }
334
+ +
335
+ +#define FIRE_FUNCTION_RETURN(ruby_current_node, klass, id) \
336
+ + if (RUBY_FUNCTION_RETURN_ENABLED()) { \
337
+ + char *classname = rb_class2name(klass), *methodname = rb_id2name(id); \
338
+ + if (ruby_current_node && ruby_current_node->nd_file && classname && methodname) { \
339
+ + RUBY_FUNCTION_RETURN(classname, methodname, ruby_current_node->nd_file, nd_line(ruby_current_node)); \
340
+ + } \
341
+ + }
342
+ +
343
+ +#else
344
+ +
345
+ +#define FIRE_LINE_PROBE(ruby_current_node) /* NOOP */
346
+ +#define FIRE_RESCUE_PROBE(ruby_current_node) /* NOOP */
347
+ +#define FIRE_RAISE_PROBE(ruby_errinfo, ruby_sourcefile, ruby_sourceline) /* NOOP */
348
+ +#define FIRE_FUNCTION_ENTRY(ruby_current_node, klass, id) /* NOOP */
349
+ +#define FIRE_FUNCTION_RETURN(ruby_current_node, klass, id) /* NOOP */
350
+ +
351
+ +#endif
352
+ +
353
+ static VALUE trace_func = 0;
354
+ static int tracing = 0;
355
+ static void call_trace_func _((rb_event_t,NODE*,VALUE,ID,VALUE));
356
+ @@ -3028,6 +3078,7 @@
357
+ RETURN(Qfalse);
358
+
359
+ case NODE_IF:
360
+ + FIRE_LINE_PROBE(ruby_current_node);
361
+ EXEC_EVENT_HOOK(RUBY_EVENT_LINE, node, self,
362
+ ruby_frame->last_func,
363
+ ruby_frame->last_class);
364
+ @@ -3046,6 +3097,7 @@
365
+ if (nd_type(node) != NODE_WHEN) goto again;
366
+ tag = node->nd_head;
367
+ while (tag) {
368
+ + FIRE_LINE_PROBE(ruby_current_node);
369
+ EXEC_EVENT_HOOK(RUBY_EVENT_LINE, tag, self,
370
+ ruby_frame->last_func,
371
+ ruby_frame->last_class);
372
+ @@ -3087,6 +3139,7 @@
373
+ }
374
+ tag = node->nd_head;
375
+ while (tag) {
376
+ + FIRE_LINE_PROBE(ruby_current_node);
377
+ EXEC_EVENT_HOOK(RUBY_EVENT_LINE, tag, self,
378
+ ruby_frame->last_func,
379
+ ruby_frame->last_class);
380
+ @@ -3307,6 +3360,7 @@
381
+ rescuing = -1;
382
+ while (resq) {
383
+ ruby_current_node = resq;
384
+ + FIRE_RESCUE_PROBE(ruby_current_node);
385
+ if (handle_rescue(self, resq)) {
386
+ state = 0;
387
+ rescuing = 1;
388
+ @@ -4124,6 +4178,7 @@
389
+ break;
390
+
391
+ case NODE_NEWLINE:
392
+ + FIRE_LINE_PROBE(ruby_current_node);
393
+ EXEC_EVENT_HOOK(RUBY_EVENT_LINE, node, self,
394
+ ruby_frame->last_func,
395
+ ruby_frame->last_class);
396
+ @@ -4598,6 +4653,7 @@
397
+
398
+ rb_trap_restore_mask();
399
+ if (tag != TAG_FATAL) {
400
+ + FIRE_RAISE_PROBE(ruby_errinfo, ruby_sourcefile, ruby_sourceline);
401
+ EXEC_EVENT_HOOK(RUBY_EVENT_RAISE, ruby_current_node,
402
+ ruby_frame->self,
403
+ ruby_frame->last_func,
404
+ @@ -5828,6 +5884,7 @@
405
+ rb_bug("bad argc (%d) specified for `%s(%s)'",
406
+ len, rb_class2name(klass), rb_id2name(id));
407
+ }
408
+ + FIRE_FUNCTION_ENTRY(ruby_current_node, klass, id);
409
+ if (event_hooks) {
410
+ int state;
411
+
412
+ @@ -5846,6 +5903,7 @@
413
+ else {
414
+ result = call_cfunc(body->nd_cfnc, recv, len, argc, argv);
415
+ }
416
+ + FIRE_FUNCTION_RETURN(ruby_current_node, klass, id);
417
+ }
418
+ break;
419
+
420
+ @@ -5873,12 +5931,14 @@
421
+
422
+ case NODE_BMETHOD:
423
+ ruby_frame->flags |= FRAME_DMETH;
424
+ + FIRE_FUNCTION_ENTRY(ruby_current_node, klass, id);
425
+ if (event_hooks) {
426
+ struct BLOCK *data;
427
+ Data_Get_Struct(body->nd_cval, struct BLOCK, data);
428
+ EXEC_EVENT_HOOK(RUBY_EVENT_CALL, data->body, recv, id, klass);
429
+ }
430
+ result = proc_invoke(body->nd_cval, rb_ary_new4(argc, argv), recv, klass);
431
+ + FIRE_FUNCTION_RETURN(ruby_current_node, klass, id);
432
+ if (event_hooks) {
433
+ EXEC_EVENT_HOOK(RUBY_EVENT_RETURN, body, recv, id, klass);
434
+ }
435
+ @@ -5992,6 +6052,7 @@
436
+ }
437
+ ruby_frame->argc = i;
438
+ }
439
+ + FIRE_FUNCTION_ENTRY(ruby_current_node, klass, id);
440
+ if (event_hooks) {
441
+ EXEC_EVENT_HOOK(RUBY_EVENT_CALL, b2, recv, id, klass);
442
+ }
443
+ @@ -6002,6 +6063,7 @@
444
+ state = 0;
445
+ }
446
+ POP_TAG();
447
+ + FIRE_FUNCTION_RETURN(ruby_current_node, klass, id);
448
+ if (event_hooks) {
449
+ EXEC_EVENT_HOOK(RUBY_EVENT_RETURN, body, recv, id, klass);
450
+ }
451
+ Index: gc.c
452
+ ===================================================================
453
+ --- gc.c (revision 16089)
454
+ +++ gc.c (working copy)
455
+ @@ -30,6 +30,11 @@
456
+ #include <sys/resource.h>
457
+ #endif
458
+
459
+ +#ifdef ENABLE_DTRACE
460
+ +#include <sys/sdt.h>
461
+ +#include "dtrace.h"
462
+ +#endif
463
+ +
464
+ #if defined _WIN32 || defined __CYGWIN__
465
+ #include <windows.h>
466
+ #endif
467
+ @@ -68,6 +73,31 @@
468
+ #endif
469
+ #endif
470
+
471
+ +#ifdef ENABLE_DTRACE
472
+ +
473
+ +#define FIRE_OBJECT_FREE_PROBE(obj) \
474
+ + if (RUBY_OBJECT_FREE_ENABLED()) { \
475
+ + RUBY_OBJECT_FREE(rb_class2name(CLASS_OF(obj))); \
476
+ + } \
477
+ +
478
+ +#define FIRE_GC_BEGIN_PROBE() \
479
+ + if (RUBY_GC_BEGIN_ENABLED()) { \
480
+ + RUBY_GC_BEGIN(); \
481
+ + }
482
+ +
483
+ +#define FIRE_GC_END_PROBE() \
484
+ + if (RUBY_GC_END_ENABLED()) { \
485
+ + RUBY_GC_END(); \
486
+ + }
487
+ +
488
+ +#else
489
+ +
490
+ +#define FIRE_OBJECT_FREE_PROBE(obj) /* NOOP */
491
+ +#define FIRE_GC_BEGIN_PROBE() /* NOOP */
492
+ +#define FIRE_GC_END_PROBE() /* NOOP */
493
+ +
494
+ +#endif
495
+ +
496
+ static unsigned long malloc_increase = 0;
497
+ static unsigned long malloc_limit = GC_MALLOC_LIMIT;
498
+ static void run_final();
499
+ @@ -1159,6 +1189,7 @@
500
+ break;
501
+ }
502
+
503
+ + FIRE_OBJECT_FREE_PROBE(obj);
504
+ if (FL_TEST(obj, FL_EXIVAR)) {
505
+ rb_free_generic_ivar((VALUE)obj);
506
+ }
507
+ @@ -1322,6 +1353,7 @@
508
+ {
509
+ struct gc_list *list;
510
+ struct FRAME * volatile frame; /* gcc 2.7.2.3 -O2 bug?? */
511
+ + FIRE_GC_BEGIN_PROBE();
512
+ jmp_buf save_regs_gc_mark;
513
+ SET_STACK_END;
514
+
515
+ @@ -1414,6 +1446,7 @@
516
+ } while (!MARK_STACK_EMPTY);
517
+
518
+ gc_sweep();
519
+ + FIRE_GC_END_PROBE();
520
+ }
521
+
522
+ void