xray 1.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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