Feature #2565 ยป dtrace.patch
.gitignore | ||
---|---|---|
55 | 55 |
/exts.mk |
56 | 56 |
/goruby |
57 | 57 |
/id.h |
58 |
/probes.h |
|
58 | 59 |
/largefile.h |
59 | 60 |
/lex.c |
60 | 61 |
/libruby*.* |
Makefile.in | ||
---|---|---|
145 | 145 |
OBJCOPY = @OBJCOPY@ |
146 | 146 |
VCS = @VCS@ |
147 | 147 |
VCSUP = @VCSUP@ |
148 |
DTRACE = @DTRACE@ |
|
148 | 149 | |
149 | 150 |
OBJEXT = @OBJEXT@ |
150 | 151 |
ASMEXT = S |
... | ... | |
261 | 262 |
$(srcdir)/configure: $(srcdir)/configure.in |
262 | 263 |
$(CHDIR) $(srcdir) && exec $(AUTOCONF) |
263 | 264 | |
264 |
incs: id.h |
|
265 |
incs: id.h probes.h
|
|
265 | 266 | |
266 | 267 |
# Things which should be considered: |
267 | 268 |
# * with gperf v.s. without gperf |
... | ... | |
318 | 319 |
@$(ECHO) preprocessing $< |
319 | 320 |
$(Q) $(CPP) $(warnflags) $(XCFLAGS) $(CPPFLAGS) $(COUTFLAG)$@ -E $< > $@ |
320 | 321 | |
322 |
.d.h: |
|
323 |
@$(ECHO) translating probes $< |
|
324 |
$(Q)if test -n '$(DTRACE)'; then\ |
|
325 |
$(DTRACE) -o $@.tmp -h -s $<; \ |
|
326 |
sed -e 's/RUBY_/RUBY_DTRACE_/g' $@.tmp | sed -e 's/PROBES_H_TMP/PROBES_H/g' >$@; \ |
|
327 |
rm $@.tmp; \ |
|
328 |
else \ |
|
329 |
sed -f $(srcdir)/tool/gen_dummy_probes.sed $< > $@; \ |
|
330 |
fi |
|
331 | ||
321 | 332 |
clean-local:: |
322 | 333 |
$(Q)$(RM) ext/extinit.c ext/extinit.$(OBJEXT) ext/ripper/y.output \ |
323 | 334 |
enc/encinit.c enc/encinit.$(OBJEXT) |
common.mk | ||
---|---|---|
2 | 2 |
lib: $(LIBRUBY) |
3 | 3 |
dll: $(LIBRUBY_SO) |
4 | 4 | |
5 |
.SUFFIXES: .inc .h .c .y .i |
|
5 |
.SUFFIXES: .inc .h .c .y .i .d
|
|
6 | 6 | |
7 | 7 |
# V=0 quiet, V=1 verbose. other values don't work. |
8 | 8 |
V = 0 |
... | ... | |
608 | 608 |
{$(VPATH)}subst.h |
609 | 609 |
ENCODING_H_INCLUDES= {$(VPATH)}encoding.h {$(VPATH)}oniguruma.h |
610 | 610 |
ID_H_INCLUDES = {$(VPATH)}id.h {$(VPATH)}vm_opts.h |
611 |
PROBES_H_INCLUDES = {$(VPATH)}probes.h |
|
611 | 612 |
VM_CORE_H_INCLUDES = {$(VPATH)}vm_core.h {$(VPATH)}thread_$(THREAD_MODEL).h \ |
612 | 613 |
{$(VPATH)}node.h {$(VPATH)}method.h {$(VPATH)}atomic.h \ |
613 | 614 |
$(ID_H_INCLUDES) |
... | ... | |
647 | 648 |
eval.$(OBJEXT): {$(VPATH)}eval.c {$(VPATH)}eval_intern.h {$(VPATH)}vm.h \ |
648 | 649 |
$(RUBY_H_INCLUDES) $(VM_CORE_H_INCLUDES) {$(VPATH)}eval_error.c \ |
649 | 650 |
{$(VPATH)}eval_jump.c {$(VPATH)}debug.h {$(VPATH)}gc.h {$(VPATH)}iseq.h \ |
650 |
$(ENCODING_H_INCLUDES) {$(VPATH)}internal.h |
|
651 |
$(ENCODING_H_INCLUDES) {$(VPATH)}internal.h $(PROBES_H_INCLUDES)
|
|
651 | 652 |
load.$(OBJEXT): {$(VPATH)}load.c {$(VPATH)}eval_intern.h \ |
652 | 653 |
{$(VPATH)}util.h $(RUBY_H_INCLUDES) $(VM_CORE_H_INCLUDES) \ |
653 | 654 |
{$(VPATH)}dln.h {$(VPATH)}debug.h \ |
654 |
{$(VPATH)}internal.h |
|
655 |
{$(VPATH)}internal.h $(PROBES_H_INCLUDES)
|
|
655 | 656 |
file.$(OBJEXT): {$(VPATH)}file.c $(RUBY_H_INCLUDES) {$(VPATH)}io.h \ |
656 | 657 |
$(ENCODING_H_INCLUDES) {$(VPATH)}util.h {$(VPATH)}dln.h \ |
657 | 658 |
{$(VPATH)}internal.h |
... | ... | |
659 | 660 |
{$(VPATH)}regex.h $(ENCODING_H_INCLUDES) $(VM_CORE_H_INCLUDES) \ |
660 | 661 |
{$(VPATH)}gc.h {$(VPATH)}io.h {$(VPATH)}eval_intern.h {$(VPATH)}util.h \ |
661 | 662 |
{$(VPATH)}debug.h {$(VPATH)}internal.h {$(VPATH)}constant.h \ |
662 |
{$(VPATH)}thread.h |
|
663 |
{$(VPATH)}thread.h $(PROBES_H_INCLUDES)
|
|
663 | 664 |
hash.$(OBJEXT): {$(VPATH)}hash.c $(RUBY_H_INCLUDES) {$(VPATH)}util.h \ |
664 | 665 |
$(ENCODING_H_INCLUDES) |
665 | 666 |
inits.$(OBJEXT): {$(VPATH)}inits.c $(RUBY_H_INCLUDES) \ |
... | ... | |
678 | 679 |
numeric.$(OBJEXT): {$(VPATH)}numeric.c $(RUBY_H_INCLUDES) \ |
679 | 680 |
{$(VPATH)}util.h $(ENCODING_H_INCLUDES) {$(VPATH)}internal.h |
680 | 681 |
object.$(OBJEXT): {$(VPATH)}object.c $(RUBY_H_INCLUDES) {$(VPATH)}util.h \ |
681 |
{$(VPATH)}internal.h {$(VPATH)}constant.h $(ENCODING_H_INCLUDES) |
|
682 |
{$(VPATH)}internal.h {$(VPATH)}constant.h $(ENCODING_H_INCLUDES) $(PROBES_H_INCLUDES)
|
|
682 | 683 |
pack.$(OBJEXT): {$(VPATH)}pack.c $(RUBY_H_INCLUDES) {$(VPATH)}encoding.h \ |
683 | 684 |
{$(VPATH)}oniguruma.h |
684 | 685 |
parse.$(OBJEXT): {$(VPATH)}parse.c $(RUBY_H_INCLUDES) {$(VPATH)}node.h \ |
... | ... | |
759 | 760 |
iseq.$(OBJEXT): {$(VPATH)}iseq.c {$(VPATH)}gc.h {$(VPATH)}iseq.h \ |
760 | 761 |
$(RUBY_H_INCLUDES) $(VM_CORE_H_INCLUDES) {$(VPATH)}insns.inc \ |
761 | 762 |
{$(VPATH)}insns_info.inc {$(VPATH)}node_name.inc {$(VPATH)}debug.h {$(VPATH)}internal.h |
763 |
{$(VPATH)}vm_insnhelper.c:$(PROBES_H_INCLUDES) |
|
762 | 764 |
vm.$(OBJEXT): {$(VPATH)}vm.c {$(VPATH)}gc.h {$(VPATH)}iseq.h \ |
763 | 765 |
{$(VPATH)}eval_intern.h $(RUBY_H_INCLUDES) $(ENCODING_H_INCLUDES) \ |
764 | 766 |
$(VM_CORE_H_INCLUDES) {$(VPATH)}vm_method.c {$(VPATH)}vm_eval.c \ |
configure.in | ||
---|---|---|
372 | 372 |
if test x"${build}" != x"${host}"; then |
373 | 373 |
AC_CHECK_TOOL(CC, gcc) |
374 | 374 |
fi |
375 | ||
376 |
AC_CHECK_TOOL(DTRACE, dtrace) |
|
377 | ||
375 | 378 |
RUBY_MINGW32 |
376 | 379 |
AC_PROG_CC |
377 | 380 |
AC_PROG_CXX |
eval.c | ||
---|---|---|
18 | 18 |
#include "ruby/encoding.h" |
19 | 19 |
#include "internal.h" |
20 | 20 |
#include "vm_core.h" |
21 |
#include "probes.h" |
|
21 | 22 | |
22 | 23 |
#define numberof(array) (int)(sizeof(array) / sizeof((array)[0])) |
23 | 24 | |
... | ... | |
497 | 498 |
} |
498 | 499 | |
499 | 500 |
if (tag != TAG_FATAL) { |
501 |
if(RUBY_DTRACE_RAISE_ENABLED()) { |
|
502 |
RUBY_DTRACE_RAISE(rb_obj_classname(th->errinfo), |
|
503 |
rb_sourcefile(), |
|
504 |
rb_sourceline()); |
|
505 |
} |
|
500 | 506 |
EXEC_EVENT_HOOK(th, RUBY_EVENT_RAISE, th->cfp->self, 0, 0); |
501 | 507 |
} |
502 | 508 |
} |
gc.c | ||
---|---|---|
23 | 23 |
#include "gc.h" |
24 | 24 |
#include "constant.h" |
25 | 25 |
#include "atomic.h" |
26 |
#include "probes.h" |
|
26 | 27 |
#include <stdio.h> |
27 | 28 |
#include <setjmp.h> |
28 | 29 |
#include <sys/types.h> |
... | ... | |
178 | 179 |
} |
179 | 180 | |
180 | 181 |
#define GC_PROF_TIMER_START do {\ |
182 |
if (RUBY_DTRACE_GC_BEGIN_ENABLED()) { \ |
|
183 |
RUBY_DTRACE_GC_BEGIN(); \ |
|
184 |
} \ |
|
181 | 185 |
if (objspace->profile.run) {\ |
182 | 186 |
if (!objspace->profile.record) {\ |
183 | 187 |
objspace->profile.size = 1000;\ |
... | ... | |
197 | 201 |
} while(0) |
198 | 202 | |
199 | 203 |
#define GC_PROF_TIMER_STOP(marked) do {\ |
204 |
if (RUBY_DTRACE_GC_END_ENABLED()) { \ |
|
205 |
RUBY_DTRACE_GC_END(); \ |
|
206 |
} \ |
|
200 | 207 |
if (objspace->profile.run) {\ |
201 | 208 |
gc_time = getrusage_time() - gc_time;\ |
202 | 209 |
if (gc_time < 0) gc_time = 0;\ |
... | ... | |
2389 | 2396 | |
2390 | 2397 |
during_gc++; |
2391 | 2398 |
GC_PROF_TIMER_START; |
2399 |
if (RUBY_DTRACE_GC_SWEEP_BEGIN_ENABLED()) { |
|
2400 |
RUBY_DTRACE_GC_SWEEP_BEGIN(); |
|
2401 |
} |
|
2392 | 2402 |
GC_PROF_SWEEP_TIMER_START; |
2393 | 2403 | |
2394 | 2404 |
if (objspace->heap.sweep_slots) { |
2395 | 2405 |
res = lazy_sweep(objspace); |
2396 | 2406 |
if (res) { |
2407 |
if (RUBY_DTRACE_GC_SWEEP_END_ENABLED()) { |
|
2408 |
RUBY_DTRACE_GC_SWEEP_END(); |
|
2409 |
} |
|
2397 | 2410 |
GC_PROF_SWEEP_TIMER_STOP; |
2398 | 2411 |
GC_PROF_SET_MALLOC_INFO; |
2399 | 2412 |
GC_PROF_TIMER_STOP(Qfalse); |
... | ... | |
2415 | 2428 |
set_heaps_increment(objspace); |
2416 | 2429 |
} |
2417 | 2430 | |
2431 |
if (RUBY_DTRACE_GC_SWEEP_BEGIN_ENABLED()) { |
|
2432 |
RUBY_DTRACE_GC_SWEEP_BEGIN(); |
|
2433 |
} |
|
2418 | 2434 |
GC_PROF_SWEEP_TIMER_START; |
2419 | 2435 |
if (!(res = lazy_sweep(objspace))) { |
2420 | 2436 |
after_gc_sweep(objspace); |
... | ... | |
2423 | 2439 |
during_gc = 0; |
2424 | 2440 |
} |
2425 | 2441 |
} |
2442 |
if (RUBY_DTRACE_GC_SWEEP_END_ENABLED()) { |
|
2443 |
RUBY_DTRACE_GC_SWEEP_END(); |
|
2444 |
} |
|
2426 | 2445 |
GC_PROF_SWEEP_TIMER_STOP; |
2427 | 2446 | |
2428 | 2447 |
GC_PROF_TIMER_STOP(Qtrue); |
... | ... | |
2662 | 2681 |
{ |
2663 | 2682 |
struct gc_list *list; |
2664 | 2683 |
rb_thread_t *th = GET_THREAD(); |
2684 |
if (RUBY_DTRACE_GC_MARK_BEGIN_ENABLED()) { |
|
2685 |
RUBY_DTRACE_GC_MARK_BEGIN(); |
|
2686 |
} |
|
2665 | 2687 |
GC_PROF_MARK_TIMER_START; |
2666 | 2688 | |
2667 | 2689 |
objspace->heap.live_num = 0; |
... | ... | |
2705 | 2727 |
gc_mark_rest(objspace); |
2706 | 2728 |
} |
2707 | 2729 |
} |
2730 |
if (RUBY_DTRACE_GC_MARK_END_ENABLED()) { |
|
2731 |
RUBY_DTRACE_GC_MARK_END(); |
|
2732 |
} |
|
2708 | 2733 |
GC_PROF_MARK_TIMER_STOP; |
2709 | 2734 |
} |
2710 | 2735 | |
... | ... | |
2729 | 2754 |
during_gc++; |
2730 | 2755 |
gc_marks(objspace); |
2731 | 2756 | |
2757 |
if (RUBY_DTRACE_GC_SWEEP_BEGIN_ENABLED()) { |
|
2758 |
RUBY_DTRACE_GC_SWEEP_BEGIN(); |
|
2759 |
} |
|
2732 | 2760 |
GC_PROF_SWEEP_TIMER_START; |
2733 | 2761 |
gc_sweep(objspace); |
2762 |
if (RUBY_DTRACE_GC_SWEEP_END_ENABLED()) { |
|
2763 |
RUBY_DTRACE_GC_SWEEP_END(); |
|
2764 |
} |
|
2734 | 2765 |
GC_PROF_SWEEP_TIMER_STOP; |
2735 | 2766 | |
2736 | 2767 |
GC_PROF_TIMER_STOP(Qtrue); |
insns.def | ||
---|---|---|
378 | 378 |
() |
379 | 379 |
(VALUE val) |
380 | 380 |
{ |
381 |
if(RUBY_DTRACE_OBJECT_CREATE_START_ENABLED()) { |
|
382 |
RUBY_DTRACE_OBJECT_CREATE_START("String", rb_sourcefile(), rb_sourceline()); |
|
383 |
} |
|
384 | ||
381 | 385 |
val = rb_str_resurrect(str); |
386 | ||
387 |
if(RUBY_DTRACE_OBJECT_CREATE_DONE_ENABLED()) { |
|
388 |
RUBY_DTRACE_OBJECT_CREATE_DONE("String", rb_sourcefile(), rb_sourceline()); |
|
389 |
} |
|
382 | 390 |
} |
383 | 391 | |
384 | 392 |
/** |
... | ... | |
450 | 458 |
(...) |
451 | 459 |
(VALUE val) // inc += 1 - num; |
452 | 460 |
{ |
461 |
if(RUBY_DTRACE_OBJECT_CREATE_START_ENABLED()) { |
|
462 |
RUBY_DTRACE_OBJECT_CREATE_START("Array", rb_sourcefile(), rb_sourceline()); |
|
463 |
} |
|
464 | ||
453 | 465 |
val = rb_ary_new4((long)num, STACK_ADDR_FROM_TOP(num)); |
466 | ||
467 |
if(RUBY_DTRACE_OBJECT_CREATE_DONE_ENABLED()) { |
|
468 |
RUBY_DTRACE_OBJECT_CREATE_DONE("Array", rb_sourcefile(), rb_sourceline()); |
|
469 |
} |
|
454 | 470 |
POPN(num); |
455 | 471 |
} |
456 | 472 | |
... | ... | |
592 | 608 |
(VALUE val) // inc += 1 - num; |
593 | 609 |
{ |
594 | 610 |
rb_num_t i; |
611 | ||
612 |
if(RUBY_DTRACE_OBJECT_CREATE_START_ENABLED()) { |
|
613 |
RUBY_DTRACE_OBJECT_CREATE_START("Hash", rb_sourcefile(), rb_sourceline()); |
|
614 |
} |
|
615 | ||
595 | 616 |
val = rb_hash_new(); |
596 | 617 | |
618 |
if(RUBY_DTRACE_OBJECT_CREATE_DONE_ENABLED()) { |
|
619 |
RUBY_DTRACE_OBJECT_CREATE_DONE("Hash", rb_sourcefile(), rb_sourceline()); |
|
620 |
} |
|
621 | ||
597 | 622 |
for (i = num; i > 0; i -= 2) { |
598 | 623 |
const VALUE v = TOPN(i - 2); |
599 | 624 |
const VALUE k = TOPN(i - 1); |
... | ... | |
870 | 895 |
{ |
871 | 896 |
rb_event_flag_t flag = (rb_event_flag_t)nf; |
872 | 897 | |
898 |
if (RUBY_DTRACE_LINE_ENABLED()) { |
|
899 |
if (flag == RUBY_EVENT_LINE) { |
|
900 |
RUBY_DTRACE_LINE(rb_sourcefile(), rb_sourceline()); |
|
901 |
} |
|
902 |
} |
|
903 | ||
904 |
if (RUBY_DTRACE_FUNCTION_ENTRY_ENABLED()) { |
|
905 |
if (flag == RUBY_EVENT_CALL || flag == RUBY_EVENT_C_CALL) { |
|
906 |
VALUE klass; |
|
907 |
ID called_id; |
|
908 | ||
909 |
rb_thread_method_id_and_class(th, &called_id, &klass); |
|
910 | ||
911 |
RUBY_DTRACE_FUNCTION_ENTRY( |
|
912 |
RSTRING_PTR(rb_inspect(klass)), |
|
913 |
rb_id2name(called_id), |
|
914 |
rb_sourcefile(), |
|
915 |
rb_sourceline()); |
|
916 |
} |
|
917 |
} |
|
918 |
if (RUBY_DTRACE_FUNCTION_RETURN_ENABLED()) { |
|
919 |
if (flag == RUBY_EVENT_RETURN || flag == RUBY_EVENT_C_RETURN) { |
|
920 |
VALUE klass; |
|
921 |
ID called_id; |
|
922 | ||
923 |
rb_thread_method_id_and_class(th, &called_id, &klass); |
|
924 | ||
925 |
RUBY_DTRACE_FUNCTION_RETURN( |
|
926 |
RSTRING_PTR(rb_inspect(klass)), |
|
927 |
rb_id2name(called_id), |
|
928 |
rb_sourcefile(), |
|
929 |
rb_sourceline()); |
|
930 |
} |
|
931 |
} |
|
873 | 932 |
EXEC_EVENT_HOOK(th, flag, GET_SELF(), 0, 0 /* TODO: id, klass */); |
874 | 933 |
} |
875 | 934 |
load.c | ||
---|---|---|
7 | 7 |
#include "internal.h" |
8 | 8 |
#include "dln.h" |
9 | 9 |
#include "eval_intern.h" |
10 |
#include "probes.h" |
|
10 | 11 | |
11 | 12 |
VALUE ruby_dln_librefs; |
12 | 13 | |
... | ... | |
375 | 376 |
VALUE fname, wrap, path; |
376 | 377 | |
377 | 378 |
rb_scan_args(argc, argv, "11", &fname, &wrap); |
379 | ||
380 |
if(RUBY_DTRACE_LOAD_ENTRY_ENABLED()) { |
|
381 |
RUBY_DTRACE_LOAD_ENTRY( |
|
382 |
StringValuePtr(fname), |
|
383 |
rb_sourcefile(), |
|
384 |
rb_sourceline()); |
|
385 |
} |
|
386 | ||
378 | 387 |
path = rb_find_file(FilePathValue(fname)); |
379 | 388 |
if (!path) { |
380 | 389 |
if (!rb_file_load_ok(RSTRING_PTR(fname))) |
... | ... | |
382 | 391 |
path = fname; |
383 | 392 |
} |
384 | 393 |
rb_load_internal(path, RTEST(wrap)); |
394 | ||
395 |
if(RUBY_DTRACE_LOAD_RETURN_ENABLED()) { |
|
396 |
RUBY_DTRACE_LOAD_RETURN(StringValuePtr(fname)); |
|
397 |
} |
|
398 | ||
385 | 399 |
return Qtrue; |
386 | 400 |
} |
387 | 401 | |
... | ... | |
615 | 629 |
} volatile saved; |
616 | 630 |
char *volatile ftptr = 0; |
617 | 631 | |
632 |
if(RUBY_DTRACE_REQUIRE_ENTRY_ENABLED()) { |
|
633 |
RUBY_DTRACE_REQUIRE_ENTRY( |
|
634 |
StringValuePtr(fname), |
|
635 |
rb_sourcefile(), |
|
636 |
rb_sourceline()); |
|
637 |
} |
|
638 | ||
618 | 639 |
PUSH_TAG(); |
619 | 640 |
saved.safe = rb_safe_level(); |
620 | 641 |
if ((state = EXEC_TAG()) == 0) { |
... | ... | |
661 | 682 | |
662 | 683 |
th->errinfo = errinfo; |
663 | 684 | |
685 |
if(RUBY_DTRACE_REQUIRE_RETURN_ENABLED()) { |
|
686 |
RUBY_DTRACE_REQUIRE_RETURN(StringValuePtr(fname)); |
|
687 |
} |
|
688 | ||
664 | 689 |
return result; |
665 | 690 |
} |
666 | 691 |
object.c | ||
---|---|---|
22 | 22 |
#include <float.h> |
23 | 23 |
#include "constant.h" |
24 | 24 |
#include "internal.h" |
25 |
#include "probes.h" |
|
25 | 26 | |
26 | 27 |
VALUE rb_cBasicObject; |
27 | 28 |
VALUE rb_mKernel; |
... | ... | |
1675 | 1676 |
if (FL_TEST(klass, FL_SINGLETON)) { |
1676 | 1677 |
rb_raise(rb_eTypeError, "can't create instance of singleton class"); |
1677 | 1678 |
} |
1679 | ||
1680 |
if (RUBY_DTRACE_OBJECT_CREATE_START_ENABLED()) { |
|
1681 |
const char * file = rb_sourcefile(); |
|
1682 |
RUBY_DTRACE_OBJECT_CREATE_START(rb_class2name(klass), |
|
1683 |
file ? file : "", |
|
1684 |
rb_sourceline()); |
|
1685 |
} |
|
1686 | ||
1678 | 1687 |
obj = rb_funcall(klass, ID_ALLOCATOR, 0, 0); |
1688 | ||
1689 |
if (RUBY_DTRACE_OBJECT_CREATE_DONE_ENABLED()) { |
|
1690 |
const char * file = rb_sourcefile(); |
|
1691 |
RUBY_DTRACE_OBJECT_CREATE_DONE(rb_class2name(klass), |
|
1692 |
file ? file : "", |
|
1693 |
rb_sourceline()); |
|
1694 |
} |
|
1695 | ||
1679 | 1696 |
if (rb_obj_class(obj) != rb_class_real(klass)) { |
1680 | 1697 |
rb_raise(rb_eTypeError, "wrong instance allocation"); |
1681 | 1698 |
} |
probes.d | ||
---|---|---|
1 |
provider ruby { |
|
2 |
probe function__entry(const char *, const char *, const char *, int); |
|
3 |
probe function__return(const char *, const char *, const char *, int); |
|
4 | ||
5 |
probe require__entry(const char *, const char *, int); |
|
6 |
probe require__return(const char *); |
|
7 | ||
8 |
probe load__entry(const char *, const char *, int); |
|
9 |
probe load__return(const char *); |
|
10 | ||
11 |
probe raise(const char *, const char *, int); |
|
12 | ||
13 |
probe object__create__start(const char *, const char *, int); |
|
14 |
probe object__create__done(const char *, const char *, int); |
|
15 | ||
16 |
probe gc__begin(); |
|
17 |
probe gc__end(); |
|
18 |
probe gc__mark__begin(); |
|
19 |
probe gc__mark__end(); |
|
20 |
probe gc__sweep__begin(); |
|
21 |
probe gc__sweep__end(); |
|
22 | ||
23 |
probe line(const char *, int); |
|
24 |
}; |
|
25 | ||
26 |
#pragma D attributes Stable/Evolving/Common provider ruby provider |
|
27 |
#pragma D attributes Stable/Evolving/Common provider ruby module |
|
28 |
#pragma D attributes Stable/Evolving/Common provider ruby function |
|
29 |
#pragma D attributes Evolving/Evolving/Common provider ruby name |
|
30 |
#pragma D attributes Evolving/Evolving/Common provider ruby args |
test/dtrace/dummy.rb | ||
---|---|---|
1 |
# this is a dummy file used by test/dtrace/test_require.rb |
test/dtrace/helper.rb | ||
---|---|---|
1 |
require 'minitest/autorun' |
|
2 |
require 'tempfile' |
|
3 | ||
4 |
module DTrace |
|
5 |
class TestCase < MiniTest::Unit::TestCase |
|
6 |
INCLUDE = File.expand_path(File.join(File.dirname(__FILE__), '..')) |
|
7 | ||
8 |
def setup |
|
9 |
skip "must be setuid 0 to run dtrace tests" unless Process.euid == 0 |
|
10 |
end |
|
11 | ||
12 |
def trap_probe d_program, ruby_program |
|
13 |
d = Tempfile.new('probe.d') |
|
14 |
d.write d_program |
|
15 |
d.flush |
|
16 | ||
17 |
rb = Tempfile.new('probed.rb') |
|
18 |
rb.write ruby_program |
|
19 |
rb.flush |
|
20 | ||
21 |
d_path = d.path |
|
22 |
rb_path = rb.path |
|
23 | ||
24 |
cmd = "dtrace -q -s #{d_path} -c '#{Gem.ruby} -I#{INCLUDE} #{rb_path}'" |
|
25 |
probes = IO.popen(cmd) do |io| |
|
26 |
io.readlines |
|
27 |
end |
|
28 |
d.close(true) |
|
29 |
rb.close(true) |
|
30 |
yield(d_path, rb_path, probes) |
|
31 |
end |
|
32 |
end |
|
33 |
end |
test/dtrace/test_function_entry.rb | ||
---|---|---|
1 |
require 'dtrace/helper' |
|
2 | ||
3 |
module DTrace |
|
4 |
class TestFunctionEntry < TestCase |
|
5 |
def test_function_entry |
|
6 |
probe = <<-eoprobe |
|
7 |
ruby$target:::function-entry |
|
8 |
{ |
|
9 |
printf("%s %s %s %d\\n", copyinstr(arg0), copyinstr(arg1), copyinstr(arg2), arg3); |
|
10 |
} |
|
11 |
eoprobe |
|
12 | ||
13 |
trap_probe(probe, ruby_program) { |d_file, rb_file, probes| |
|
14 |
foo_calls = probes.map { |line| line.split }.find_all { |row| |
|
15 |
row.first == 'Foo' && row[1] == 'foo' |
|
16 |
} |
|
17 | ||
18 |
assert_equal 10, foo_calls.length |
|
19 |
line = '2' |
|
20 |
foo_calls.each { |f| assert_equal line, f[3] } |
|
21 |
foo_calls.each { |f| assert_equal rb_file, f[2] } |
|
22 |
} |
|
23 |
end |
|
24 | ||
25 |
def test_function_return |
|
26 |
probe = <<-eoprobe |
|
27 |
ruby$target:::function-return |
|
28 |
{ |
|
29 |
printf("%s %s %s %d\\n", copyinstr(arg0), copyinstr(arg1), copyinstr(arg2), arg3); |
|
30 |
} |
|
31 |
eoprobe |
|
32 | ||
33 |
trap_probe(probe, ruby_program) { |d_file, rb_file, probes| |
|
34 |
foo_calls = probes.map { |line| line.split }.find_all { |row| |
|
35 |
row.first == 'Foo' && row[1] == 'foo' |
|
36 |
} |
|
37 | ||
38 |
assert_equal 10, foo_calls.length |
|
39 |
line = '2' |
|
40 |
foo_calls.each { |f| assert_equal line, f[3] } |
|
41 |
foo_calls.each { |f| assert_equal rb_file, f[2] } |
|
42 |
} |
|
43 |
end |
|
44 | ||
45 |
private |
|
46 |
def ruby_program |
|
47 |
<<-eoruby |
|
48 |
class Foo |
|
49 |
def foo; end |
|
50 |
end |
|
51 |
x = Foo.new |
|
52 |
10.times { x.foo } |
|
53 |
eoruby |
|
54 |
end |
|
55 |
end |
|
56 |
end |
test/dtrace/test_gc.rb | ||
---|---|---|
1 |
require 'dtrace/helper' |
|
2 | ||
3 |
module DTrace |
|
4 |
class TestGC < TestCase |
|
5 |
%w{ |
|
6 |
gc-begin |
|
7 |
gc-end |
|
8 |
gc-mark-begin |
|
9 |
gc-mark-end |
|
10 |
gc-sweep-begin |
|
11 |
gc-sweep-end |
|
12 |
}.each do |probe_name| |
|
13 |
define_method(:"test_#{probe_name.gsub(/-/, '_')}") do |
|
14 |
probe = "ruby$target:::#{probe_name} { printf(\"#{probe_name}\\n\"); }" |
|
15 | ||
16 |
trap_probe(probe, ruby_program) { |_, _, saw| |
|
17 |
assert_operator saw.length, :>, 0 |
|
18 |
} |
|
19 | ||
20 |
end |
|
21 |
end |
|
22 | ||
23 |
private |
|
24 |
def ruby_program |
|
25 |
"100000.times { Object.new }" |
|
26 |
end |
|
27 |
end |
|
28 |
end |
test/dtrace/test_line.rb | ||
---|---|---|
1 |
require 'dtrace/helper' |
|
2 | ||
3 |
module DTrace |
|
4 |
class TestLine < TestCase |
|
5 |
def test_line |
|
6 |
probe = "ruby$target:::line { printf(\"%s %d\\n\", copyinstr(arg0), arg1); }" |
|
7 |
program = 'x = 2; 10.times { x = x ** 2 }' |
|
8 | ||
9 |
trap_probe(probe, program) { |_, rbpath, saw| |
|
10 |
saw = saw.map(&:split).find_all { |file, _| |
|
11 |
file == rbpath |
|
12 |
} |
|
13 |
assert_operator saw.length, :>=, 10 |
|
14 |
saw.each { |f,l| assert_equal '1', l } |
|
15 |
} |
|
16 |
end |
|
17 |
end |
|
18 |
end |
test/dtrace/test_load.rb | ||
---|---|---|
1 |
require 'dtrace/helper' |
|
2 |
require 'tempfile' |
|
3 | ||
4 |
module DTrace |
|
5 |
class TestLoad < TestCase |
|
6 |
def setup |
|
7 |
super |
|
8 |
@rbfile = Tempfile.new(['omg', 'rb']) |
|
9 |
@rbfile.write 'x = 10' |
|
10 |
end |
|
11 | ||
12 |
def teardown |
|
13 |
super |
|
14 |
@rbfile.close(true) if @rbfile |
|
15 |
end |
|
16 | ||
17 |
def test_load_entry |
|
18 |
probe = <<-eoprobe |
|
19 |
ruby$target:::load-entry |
|
20 |
{ |
|
21 |
printf("%s %s %d\\n", copyinstr(arg0), copyinstr(arg1), arg2); |
|
22 |
} |
|
23 |
eoprobe |
|
24 |
trap_probe(probe, program) { |dpath, rbpath, saw| |
|
25 |
saw = saw.map(&:split).find_all { |loaded, _, _| |
|
26 |
loaded == @rbfile.path |
|
27 |
} |
|
28 |
assert_equal 10, saw.length |
|
29 |
} |
|
30 |
end |
|
31 | ||
32 |
def test_load_return |
|
33 |
probe = <<-eoprobe |
|
34 |
ruby$target:::load-return |
|
35 |
{ |
|
36 |
printf("%s\\n", copyinstr(arg0)); |
|
37 |
} |
|
38 |
eoprobe |
|
39 |
trap_probe(probe, program) { |dpath, rbpath, saw| |
|
40 |
saw = saw.map(&:split).find_all { |loaded, _, _| |
|
41 |
loaded == @rbfile.path |
|
42 |
} |
|
43 |
assert_equal 10, saw.length |
|
44 |
} |
|
45 |
end |
|
46 | ||
47 |
private |
|
48 |
def program |
|
49 |
"10.times { load '#{@rbfile.path}' }" |
|
50 |
end |
|
51 |
end |
|
52 |
end |
test/dtrace/test_object_create_done.rb | ||
---|---|---|
1 |
require 'dtrace/helper' |
|
2 | ||
3 |
module DTrace |
|
4 |
class TestObjectCreateDone < TestCase |
|
5 |
def test_object |
|
6 |
trap_probe(probe, '10.times { Object.new }') { |_,rbfile,saw| |
|
7 |
saw = saw.map(&:split).find_all { |_, file, _| |
|
8 |
file == rbfile |
|
9 |
} |
|
10 |
assert_equal 10, saw.length |
|
11 |
} |
|
12 |
end |
|
13 | ||
14 |
def test_object_name |
|
15 |
trap_probe(probe, 'Hash.new') { |_,rbfile,saw| |
|
16 |
saw = saw.map(&:split).find_all { |klass, file, line| |
|
17 |
file == rbfile |
|
18 |
} |
|
19 |
assert_equal(%w{ Hash }, saw.map(&:first)) |
|
20 |
assert_equal([rbfile], saw.map { |line| line[1] }) |
|
21 |
assert_equal(['1'], saw.map { |line| line[2] }) |
|
22 |
} |
|
23 |
end |
|
24 | ||
25 |
def test_hash_lit |
|
26 |
trap_probe(probe, '{}') { |_,rbfile,saw| |
|
27 |
saw = saw.map(&:split).find_all { |klass, file, line| |
|
28 |
file == rbfile |
|
29 |
} |
|
30 |
assert_equal(%w{ Hash }, saw.map(&:first)) |
|
31 |
assert_equal([rbfile], saw.map { |line| line[1] }) |
|
32 |
assert_equal(['1'], saw.map { |line| line[2] }) |
|
33 |
} |
|
34 |
end |
|
35 | ||
36 |
def test_array_lit |
|
37 |
trap_probe(probe, '[]') { |_,rbfile,saw| |
|
38 |
saw = saw.map(&:split).find_all { |klass, file, line| |
|
39 |
file == rbfile |
|
40 |
} |
|
41 |
assert_equal(%w{ Array }, saw.map(&:first)) |
|
42 |
assert_equal([rbfile], saw.map { |line| line[1] }) |
|
43 |
assert_equal(['1'], saw.map { |line| line[2] }) |
|
44 |
} |
|
45 |
end |
|
46 | ||
47 |
def test_string_lit |
|
48 |
trap_probe(probe, '"omg"') { |_,rbfile,saw| |
|
49 |
saw = saw.map(&:split).find_all { |klass, file, line| |
|
50 |
file == rbfile |
|
51 |
} |
|
52 |
assert_equal(%w{ String }, saw.map(&:first)) |
|
53 |
assert_equal([rbfile], saw.map { |line| line[1] }) |
|
54 |
assert_equal(['1'], saw.map { |line| line[2] }) |
|
55 |
} |
|
56 |
end |
|
57 | ||
58 |
private |
|
59 |
def probe |
|
60 |
<<-eoprobe |
|
61 |
ruby$target:::object-create-done |
|
62 |
{ |
|
63 |
printf("%s %s %d\\n", copyinstr(arg0), copyinstr(arg1), arg2); |
|
64 |
} |
|
65 |
eoprobe |
|
66 |
end |
|
67 |
end |
|
68 |
end |
test/dtrace/test_object_create_start.rb | ||
---|---|---|
1 |
require 'dtrace/helper' |
|
2 | ||
3 |
module DTrace |
|
4 |
class TestObjectCreateStart < TestCase |
|
5 |
def test_object_create_start |
|
6 |
trap_probe(probe, '10.times { Object.new }') { |_,rbfile,saw| |
|
7 |
saw = saw.map(&:split).find_all { |_, file, _| |
|
8 |
file == rbfile |
|
9 |
} |
|
10 |
assert_equal 10, saw.length |
|
11 |
} |
|
12 |
end |
|
13 | ||
14 |
def test_object_create_start_name |
|
15 |
trap_probe(probe, 'Hash.new') { |_,rbfile,saw| |
|
16 |
saw = saw.map(&:split).find_all { |klass, file, line| |
|
17 |
file == rbfile |
|
18 |
} |
|
19 |
assert_equal(%w{ Hash }, saw.map(&:first)) |
|
20 |
assert_equal([rbfile], saw.map { |line| line[1] }) |
|
21 |
assert_equal(['1'], saw.map { |line| line[2] }) |
|
22 |
} |
|
23 |
end |
|
24 | ||
25 |
def test_object_create_start_hash_lit |
|
26 |
trap_probe(probe, '{}') { |_,rbfile,saw| |
|
27 |
saw = saw.map(&:split).find_all { |klass, file, line| |
|
28 |
file == rbfile |
|
29 |
} |
|
30 |
assert_equal(%w{ Hash }, saw.map(&:first)) |
|
31 |
assert_equal([rbfile], saw.map { |line| line[1] }) |
|
32 |
assert_equal(['1'], saw.map { |line| line[2] }) |
|
33 |
} |
|
34 |
end |
|
35 | ||
36 |
def test_object_create_start_array_lit |
|
37 |
trap_probe(probe, '[]') { |_,rbfile,saw| |
|
38 |
saw = saw.map(&:split).find_all { |klass, file, line| |
|
39 |
file == rbfile |
|
40 |
} |
|
41 |
assert_equal(%w{ Array }, saw.map(&:first)) |
|
42 |
assert_equal([rbfile], saw.map { |line| line[1] }) |
|
43 |
assert_equal(['1'], saw.map { |line| line[2] }) |
|
44 |
} |
|
45 |
end |
|
46 | ||
47 |
def test_object_create_start_string_lit |
|
48 |
trap_probe(probe, '"omg"') { |_,rbfile,saw| |
|
49 |
saw = saw.map(&:split).find_all { |klass, file, line| |
|
50 |
file == rbfile |
|
51 |
} |
|
52 |
assert_equal(%w{ String }, saw.map(&:first)) |
|
53 |
assert_equal([rbfile], saw.map { |line| line[1] }) |
|
54 |
assert_equal(['1'], saw.map { |line| line[2] }) |
|
55 |
} |
|
56 |
end |
|
57 | ||
58 |
private |
|
59 |
def probe |
|
60 |
<<-eoprobe |
|
61 |
ruby$target:::object-create-start |
|
62 |
{ |
|
63 |
printf("%s %s %d\\n", copyinstr(arg0), copyinstr(arg1), arg2); |
|
64 |
} |
|
65 |
eoprobe |
|
66 |
end |
|
67 |
end |
|
68 |
end |
test/dtrace/test_raise.rb | ||
---|---|---|
1 |
require 'dtrace/helper' |
|
2 | ||
3 |
module DTrace |
|
4 |
class TestRaise < TestCase |
|
5 |
def test_raise |
|
6 |
probe = <<-eoprobe |
|
7 |
ruby$target:::raise |
|
8 |
{ |
|
9 |
printf("%s %s %d\\n", copyinstr(arg0), copyinstr(arg1), arg2); |
|
10 |
} |
|
11 |
eoprobe |
|
12 |
trap_probe(probe, program) { |dpath, rbpath, saw| |
|
13 |
saw = saw.map(&:split).find_all { |_, source_file, _| |
|
14 |
source_file == rbpath |
|
15 |
} |
|
16 |
assert_equal 10, saw.length |
|
17 |
saw.each do |klass, _, source_line| |
|
18 |
assert_equal 'RuntimeError', klass |
|
19 |
assert_equal '1', source_line |
|
20 |
end |
|
21 |
} |
|
22 |
end |
|
23 | ||
24 |
private |
|
25 |
def program |
|
26 |
'10.times { raise rescue nil }' |
|
27 |
end |
|
28 |
end |
|
29 |
end |
test/dtrace/test_require.rb | ||
---|---|---|
1 |
require 'dtrace/helper' |
|
2 | ||
3 |
module DTrace |
|
4 |
class TestRequire < TestCase |
|
5 |
def test_require_entry |
|
6 |
probe = <<-eoprobe |
|
7 |
ruby$target:::require-entry |
|
8 |
{ |
|
9 |
printf("%s %s %d\\n", copyinstr(arg0), copyinstr(arg1), arg2); |
|
10 |
} |
|
11 |
eoprobe |
|
12 |
trap_probe(probe, ruby_program) { |d_file, rb_file, saw| |
|
13 |
required = saw.map { |s| s.split }.find_all do |(required, _)| |
|
14 |
required == 'dtrace/dummy' |
|
15 |
end |
|
16 |
assert_equal 10, required.length |
|
17 |
} |
|
18 |
end |
|
19 | ||
20 |
def test_require_return |
|
21 |
probe = <<-eoprobe |
|
22 |
ruby$target:::require-return |
|
23 |
{ |
|
24 |
printf("%s\\n", copyinstr(arg0)); |
|
25 |
} |
|
26 |
eoprobe |
|
27 |
end |
|
28 | ||
29 |
private |
|
30 |
def ruby_program |
|
31 |
"10.times { require 'dtrace/dummy' }" |
|
32 |
end |
|
33 |
end |
|
34 |
end |
test/dtrace/test_singleton_function.rb | ||
---|---|---|
1 |
require 'dtrace/helper' |
|
2 | ||
3 |
module DTrace |
|
4 |
class TestSingletonFunctionEntry < TestCase |
|
5 |
def test_entry |
|
6 |
probe = <<-eoprobe |
|
7 |
ruby$target:::function-entry |
|
8 |
/strstr(copyinstr(arg0), "Foo") != NULL/ |
|
9 |
{ |
|
10 |
printf("%s %s %s %d\\n", copyinstr(arg0), copyinstr(arg1), copyinstr(arg2), arg3); |
|
11 |
} |
|
12 |
eoprobe |
|
13 | ||
14 |
trap_probe(probe, ruby_program) { |d_file, rb_file, probes| |
|
15 |
foo_calls = probes.map { |line| line.split }.find_all { |row| |
|
16 |
row.first == '#<Class:Foo>' && row[1] == 'foo' |
|
17 |
} |
|
18 | ||
19 |
assert_equal 10, foo_calls.length |
|
20 |
line = '2' |
|
21 |
foo_calls.each { |f| assert_equal line, f[3] } |
|
22 |
foo_calls.each { |f| assert_equal rb_file, f[2] } |
|
23 |
} |
|
24 |
end |
|
25 | ||
26 |
def test_exit |
|
27 |
probe = <<-eoprobe |
|
28 |
ruby$target:::function-return |
|
29 |
{ |
|
30 |
printf("%s %s %s %d\\n", copyinstr(arg0), copyinstr(arg1), copyinstr(arg2), arg3); |
|
31 |
} |
|
32 |
eoprobe |
|
33 | ||
34 |
trap_probe(probe, ruby_program) { |d_file, rb_file, probes| |
|
35 |
foo_calls = probes.map { |line| line.split }.find_all { |row| |
|
36 |
row.first == '#<Class:Foo>' && row[1] == 'foo' |
|
37 |
} |
|
38 | ||
39 |
assert_equal 10, foo_calls.length |
|
40 |
line = '2' |
|
41 |
foo_calls.each { |f| assert_equal line, f[3] } |
|
42 |
foo_calls.each { |f| assert_equal rb_file, f[2] } |
|
43 |
} |
|
44 |
end |
|
45 | ||
46 |
def ruby_program |
|
47 |
<<-eoruby |
|
48 |
class Foo |
|
49 |
def self.foo; end |
|
50 |
end |
|
51 |
10.times { Foo.foo } |
|
52 |
eoruby |
|
53 |
end |
|
54 |
end |
|
55 |
end |
tool/gen_dummy_probes.sed | ||
---|---|---|
1 | ||
2 |
# upper case everything |
|
3 |
y/abcdefghijklmnopqrstuvwxyz/ABCDEFGHIJKLMNOPQRSTUVWXYZ/ |
|
4 | ||
5 |
# remove the pragma declarations |
|
6 |
s/^#PRAGMA.*$// |
|
7 | ||
8 |
# replace the provider section with the start of the header file |
|
9 |
s/PROVIDER RUBY {/#ifndef _PROBES_H\ |
|
10 |
#define _PROBES_H/ |
|
11 | ||
12 |
# finish up the #ifndef sandwich |
|
13 |
s/};/#endif \/* _PROBES_H *\// |
|
14 | ||
15 |
s/__/_/g |
|
16 | ||
17 |
s/([^,)]\{1,\})/(arg0)/ |
|
18 |
s/([^,)]\{1,\},[^,)]\{1,\})/(arg0, arg1)/ |
|
19 |
s/([^,)]\{1,\},[^,)]\{1,\},[^,)]\{1,\})/(arg0, arg1, arg2)/ |
|
20 |
s/([^,)]\{1,\},[^,)]\{1,\},[^,)]\{1,\},[^,)]\{1,\})/(arg0, arg1, arg2, arg3)/ |
|
21 |
s/([^,)]\{1,\},[^,)]\{1,\},[^,)]\{1,\},[^,)]\{1,\},[^,)]\{1,\})/(arg0, arg1, arg2, arg3, arg4)/ |
|
22 | ||
23 |
s/[ ]*PROBE[ ]\([^\(]*\)\(([^\)]*)\);/#define RUBY_DTRACE_\1_ENABLED() 0\ |
|
24 |
#define RUBY_DTRACE_\1\2\ do \{ \} while\(0\)/ |
vm_eval.c | ||
---|---|---|
66 | 66 |
} |
67 | 67 |
case VM_METHOD_TYPE_NOTIMPLEMENTED: |
68 | 68 |
case VM_METHOD_TYPE_CFUNC: { |
69 |
if (RUBY_DTRACE_FUNCTION_ENTRY_ENABLED()) { |
|
70 |
const char * classname = rb_class2name(klass); |
|
71 |
const char * methodname = rb_id2name(id); |
|
72 |
const char * filename = rb_sourcefile(); |
|
73 |
if (classname && methodname && filename) { |
|
74 |
RUBY_DTRACE_FUNCTION_ENTRY( |
|
75 |
classname, |
|
76 |
methodname, |
|
77 |
filename, |
|
78 |
rb_sourceline()); |
|
79 |
} |
|
80 |
} |
|
69 | 81 |
EXEC_EVENT_HOOK(th, RUBY_EVENT_C_CALL, recv, id, klass); |
70 | 82 |
{ |
71 | 83 |
rb_control_frame_t *reg_cfp = th->cfp; |
... | ... | |
81 | 93 |
} |
82 | 94 |
vm_pop_frame(th); |
83 | 95 |
} |
96 |
if (RUBY_DTRACE_FUNCTION_RETURN_ENABLED()) { |
|
97 |
const char * classname = rb_class2name(klass); |
|
98 |
const char * methodname = rb_id2name(id); |
|
99 |
const char * filename = rb_sourcefile(); |
|
100 |
if (classname && methodname && filename) { |
|
101 |
RUBY_DTRACE_FUNCTION_RETURN( |
|
102 |
classname, |
|
103 |
methodname, |
|
104 |
filename, |
|
105 |
rb_sourceline()); |
|
106 |
} |
|
107 |
} |
|
84 | 108 |
EXEC_EVENT_HOOK(th, RUBY_EVENT_C_RETURN, recv, id, klass); |
85 | 109 |
break; |
86 | 110 |
} |
... | ... | |
138 | 162 |
rb_bug("vm_call0: unsupported method type (%d)", def->type); |
139 | 163 |
val = Qundef; |
140 | 164 |
} |
165 | ||
141 | 166 |
RUBY_VM_CHECK_INTS(); |
142 | 167 |
return val; |
143 | 168 |
} |
vm_insnhelper.c | ||
---|---|---|
13 | 13 |
#include <math.h> |
14 | 14 |
#include "constant.h" |
15 | 15 |
#include "internal.h" |
16 |
#include "probes.h" |
|
16 | 17 | |
17 | 18 |
/* control stack frame */ |
18 | 19 | |
... | ... | |
420 | 421 |
volatile VALUE val = 0; |
421 | 422 |
const rb_method_definition_t *def = me->def; |
422 | 423 | |
424 |
if (RUBY_DTRACE_FUNCTION_ENTRY_ENABLED()) { |
|
425 |
const char * classname = rb_class2name(me->klass); |
|
426 |
const char * methodname = rb_id2name(me->called_id); |
|
427 |
const char * filename = rb_sourcefile(); |
|
428 |
if (classname && methodname && filename) { |
|
429 |
RUBY_DTRACE_FUNCTION_ENTRY( |
|
430 |
classname, |
|
431 |
methodname, |
|
432 |
filename, |
|
433 |
rb_sourceline()); |
|
434 |
} |
|
435 |
} |
|
423 | 436 |
EXEC_EVENT_HOOK(th, RUBY_EVENT_C_CALL, recv, me->called_id, me->klass); |
424 | 437 | |
425 | 438 |
vm_push_frame(th, 0, VM_FRAME_MAGIC_CFUNC, recv, |
... | ... | |
435 | 448 | |
436 | 449 |
vm_pop_frame(th); |
437 | 450 | |
451 |
if (RUBY_DTRACE_FUNCTION_RETURN_ENABLED()) { |
|
452 |
const char * classname = rb_class2name(me->klass); |
|
453 |
const char * methodname = rb_id2name(me->called_id); |
|
454 |
const char * filename = rb_sourcefile(); |
|
455 |
if (classname && methodname && filename) { |
|
456 |
RUBY_DTRACE_FUNCTION_RETURN( |
|
457 |
classname, |
|
458 |
methodname, |
|
459 |
filename, |
|
460 |
rb_sourceline()); |
|
461 |
} |
|
462 |
} |
|
438 | 463 |
EXEC_EVENT_HOOK(th, RUBY_EVENT_C_RETURN, recv, me->called_id, me->klass); |
439 | 464 | |
440 | 465 |
return val; |
... | ... | |
447 | 472 |
rb_proc_t *proc; |
448 | 473 |
VALUE val; |
449 | 474 | |
475 |
if (RUBY_DTRACE_FUNCTION_ENTRY_ENABLED()) { |
|
476 |
RUBY_DTRACE_FUNCTION_ENTRY( |
|
477 |
rb_class2name(me->klass), |
|
478 |
rb_id2name(me->called_id), |
|
479 |
rb_sourcefile(), |
|
480 |
rb_sourceline()); |
|
481 |
} |
|
450 | 482 |
EXEC_EVENT_HOOK(th, RUBY_EVENT_CALL, recv, me->called_id, me->klass); |
451 | 483 | |
452 | 484 |
/* control block frame */ |
... | ... | |
454 | 486 |
GetProcPtr(me->def->body.proc, proc); |
455 | 487 |
val = rb_vm_invoke_proc(th, proc, recv, argc, argv, blockptr); |
456 | 488 | |
489 |
if (RUBY_DTRACE_FUNCTION_RETURN_ENABLED()) { |
|
490 |
RUBY_DTRACE_FUNCTION_RETURN( |
|
491 |
rb_class2name(me->klass), |
|
492 |
rb_id2name(me->called_id), |
|
493 |
rb_sourcefile(), |
|
494 |
rb_sourceline()); |
|
495 |
} |
|
457 | 496 |
EXEC_EVENT_HOOK(th, RUBY_EVENT_RETURN, recv, me->called_id, me->klass); |
458 | 497 | |
459 | 498 |
return val; |