Project

General

Profile

Feature #2565 ยป dtrace.diff

tenderlovemaking (Aaron Patterson), 05/02/2012 08:25 AM

View differences:

.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
137 137
OBJCOPY       = @OBJCOPY@
138 138
VCS           = @VCS@
139 139
VCSUP         = @VCSUP@
140
DTRACE        = @DTRACE@
140 141

  
141 142
OBJEXT        = @OBJEXT@
142 143
ASMEXT        = S
......
251 252
$(srcdir)/configure: $(srcdir)/configure.in
252 253
	$(CHDIR) $(srcdir) && exec $(AUTOCONF)
253 254

  
254
incs: id.h
255
incs: id.h probes.h
255 256

  
256 257
# Things which should be considered:
257 258
# * with gperf v.s. without gperf
......
308 309
	@$(ECHO) preprocessing $<
309 310
	$(Q) $(CPP) $(XCFLAGS) $(CPPFLAGS) $(COUTFLAG)$@ -E $< > $@
310 311

  
312
.d.h:
313
	@$(ECHO) translating probes $<
314
	$(Q)if test -n '$(DTRACE)'; then\
315
	  $(DTRACE) -o $@ -h -s $<; \
316
	else \
317
	  cp $(<D)/dummy_$@ $@ ;\
318
	fi
319

  
311 320
clean-local::
312 321
	$(Q)$(RM) ext/extinit.c ext/extinit.$(OBJEXT) ext/ripper/y.output
313 322
	-$(Q)$(RM) $(pkgconfig_DATA)
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
......
593 593
		     {$(VPATH)}subst.h
594 594
ENCODING_H_INCLUDES= {$(VPATH)}encoding.h {$(VPATH)}oniguruma.h
595 595
ID_H_INCLUDES      = {$(VPATH)}id.h {$(VPATH)}vm_opts.h
596
PROBES_H_INCLUDES  = {$(VPATH)}probes.h
596 597
VM_CORE_H_INCLUDES = {$(VPATH)}vm_core.h {$(VPATH)}thread_$(THREAD_MODEL).h \
597 598
		     {$(VPATH)}node.h {$(VPATH)}method.h {$(VPATH)}atomic.h \
598 599
		     $(ID_H_INCLUDES)
......
631 632
eval.$(OBJEXT): {$(VPATH)}eval.c {$(VPATH)}eval_intern.h {$(VPATH)}vm.h \
632 633
  $(RUBY_H_INCLUDES) $(VM_CORE_H_INCLUDES) {$(VPATH)}eval_error.c \
633 634
  {$(VPATH)}eval_jump.c {$(VPATH)}debug.h {$(VPATH)}gc.h {$(VPATH)}iseq.h \
634
  $(ENCODING_H_INCLUDES) {$(VPATH)}internal.h
635
  $(ENCODING_H_INCLUDES) {$(VPATH)}internal.h $(PROBES_H_INCLUDES)
635 636
load.$(OBJEXT): {$(VPATH)}load.c {$(VPATH)}eval_intern.h \
636 637
  {$(VPATH)}util.h $(RUBY_H_INCLUDES) $(VM_CORE_H_INCLUDES) \
637 638
  {$(VPATH)}dln.h {$(VPATH)}debug.h \
638
  {$(VPATH)}internal.h
639
  {$(VPATH)}internal.h $(PROBES_H_INCLUDES)
639 640
file.$(OBJEXT): {$(VPATH)}file.c $(RUBY_H_INCLUDES) {$(VPATH)}io.h \
640 641
  $(ENCODING_H_INCLUDES) {$(VPATH)}util.h {$(VPATH)}dln.h \
641 642
  {$(VPATH)}internal.h
642 643
gc.$(OBJEXT): {$(VPATH)}gc.c $(RUBY_H_INCLUDES) {$(VPATH)}re.h \
643 644
  {$(VPATH)}regex.h $(ENCODING_H_INCLUDES) $(VM_CORE_H_INCLUDES) \
644 645
  {$(VPATH)}gc.h {$(VPATH)}io.h {$(VPATH)}eval_intern.h {$(VPATH)}util.h \
645
  {$(VPATH)}debug.h {$(VPATH)}internal.h {$(VPATH)}constant.h
646
  {$(VPATH)}debug.h {$(VPATH)}internal.h {$(VPATH)}constant.h $(PROBES_H_INCLUDES)
646 647
hash.$(OBJEXT): {$(VPATH)}hash.c $(RUBY_H_INCLUDES) {$(VPATH)}util.h \
647 648
  $(ENCODING_H_INCLUDES)
648 649
inits.$(OBJEXT): {$(VPATH)}inits.c $(RUBY_H_INCLUDES) \
......
660 661
numeric.$(OBJEXT): {$(VPATH)}numeric.c $(RUBY_H_INCLUDES) \
661 662
  {$(VPATH)}util.h $(ENCODING_H_INCLUDES) {$(VPATH)}internal.h
662 663
object.$(OBJEXT): {$(VPATH)}object.c $(RUBY_H_INCLUDES) {$(VPATH)}util.h \
663
  {$(VPATH)}internal.h {$(VPATH)}constant.h
664
  {$(VPATH)}internal.h {$(VPATH)}constant.h $(PROBES_H_INCLUDES)
664 665
pack.$(OBJEXT): {$(VPATH)}pack.c $(RUBY_H_INCLUDES) {$(VPATH)}encoding.h \
665 666
  {$(VPATH)}oniguruma.h
666 667
parse.$(OBJEXT): {$(VPATH)}parse.c $(RUBY_H_INCLUDES) {$(VPATH)}node.h \
......
740 741
iseq.$(OBJEXT): {$(VPATH)}iseq.c {$(VPATH)}gc.h {$(VPATH)}iseq.h \
741 742
  $(RUBY_H_INCLUDES) $(VM_CORE_H_INCLUDES) {$(VPATH)}insns.inc \
742 743
  {$(VPATH)}insns_info.inc {$(VPATH)}node_name.inc {$(VPATH)}debug.h {$(VPATH)}internal.h
744
{$(VPATH)}vm_insnhelper.c:$(PROBES_H_INCLUDES)
743 745
vm.$(OBJEXT): {$(VPATH)}vm.c {$(VPATH)}gc.h {$(VPATH)}iseq.h \
744 746
  {$(VPATH)}eval_intern.h $(RUBY_H_INCLUDES) $(ENCODING_H_INCLUDES) \
745 747
  $(VM_CORE_H_INCLUDES) {$(VPATH)}vm_method.c {$(VPATH)}vm_eval.c \
configure.in
286 286
if test x"${build}" != x"${host}"; then
287 287
  AC_CHECK_TOOL(CC, gcc)
288 288
fi
289

  
290
AC_CHECK_TOOL(DTRACE, dtrace)
291

  
289 292
RUBY_MINGW32
290 293
AC_PROG_CC
291 294
AC_PROG_CXX
dummy_probes.h
1
#ifndef	_PROBES_H
2
#define	_PROBES_H
3

  
4
#defune RUBY_FUNCTION_ENTRY(arg0, arg1, arg2, arg3)
5
#define RUBY_FUNCTION_ENTRY_ENABLED() 0
6
#defune RUBY_FUNCTION_RETURN(arg0, arg1, arg2, arg3)
7
#define RUBY_FUNCTION_RETURN_ENABLED() 0
8
#define RUBY_GC_BEGIN() 0
9
#define RUBY_GC_BEGIN_ENABLED() 0
10
#define RUBY_GC_END() 0
11
#define RUBY_GC_END_ENABLED() 0
12
#define RUBY_GC_MARK_BEGIN() 0
13
#define RUBY_GC_MARK_BEGIN_ENABLED() 0
14
#define RUBY_GC_MARK_END() 0
15
#define RUBY_GC_MARK_END_ENABLED() 0
16
#define RUBY_GC_SWEEP_BEGIN() 0
17
#define RUBY_GC_SWEEP_BEGIN_ENABLED() 0
18
#define RUBY_GC_SWEEP_END() 0
19
#define RUBY_GC_SWEEP_END_ENABLED() 0
20
#defune RUBY_LINE(arg0, arg1)
21
#define RUBY_LINE_ENABLED() 0
22
#defune RUBY_LOAD_ENTRY(arg0, arg1, arg2)
23
#define RUBY_LOAD_ENTRY_ENABLED() 0
24
#defune RUBY_LOAD_RETURN(arg0)
25
#define RUBY_LOAD_RETURN_ENABLED() 0
26
#defune RUBY_OBJECT_CREATE_DONE(arg0, arg1, arg2)
27
#define RUBY_OBJECT_CREATE_DONE_ENABLED() 0
28
#defune RUBY_OBJECT_CREATE_START(arg0, arg1, arg2)
29
#define RUBY_OBJECT_CREATE_START_ENABLED() 0
30
#defune RUBY_RAISE(arg0, arg1, arg2)
31
#define RUBY_RAISE_ENABLED() 0
32
#defune RUBY_REQUIRE_ENTRY(arg0, arg1, arg2)
33
#define RUBY_REQUIRE_ENTRY_ENABLED() 0
34
#defune RUBY_REQUIRE_RETURN(arg0)
35
#define RUBY_REQUIRE_RETURN_ENABLED() 0
36
#defune RUBY_FUNCTION_ENTRY(arg0, arg1, arg2, arg3)
37
#defune RUBY_FUNCTION_RETURN(arg0, arg1, arg2, arg3)
38
#define RUBY_GC_BEGIN() 0
39
#define RUBY_GC_END() 0
40
#define RUBY_GC_MARK_BEGIN() 0
41
#define RUBY_GC_MARK_END() 0
42
#define RUBY_GC_SWEEP_BEGIN() 0
43
#define RUBY_GC_SWEEP_END() 0
44
#defune RUBY_LINE(arg0, arg1)
45
#defune RUBY_LOAD_ENTRY(arg0, arg1, arg2)
46
#defune RUBY_LOAD_RETURN(arg0)
47
#defune RUBY_OBJECT_CREATE_DONE(arg0, arg1, arg2)
48
#defune RUBY_OBJECT_CREATE_START(arg0, arg1, arg2)
49
#defune RUBY_RAISE(arg0, arg1, arg2)
50
#defune RUBY_REQUIRE_ENTRY(arg0, arg1, arg2)
51
#defune RUBY_REQUIRE_RETURN(arg0)
52

  
53
#endif	/* _PROBES_H */
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

  
......
439 440
    }
440 441

  
441 442
    if (tag != TAG_FATAL) {
443
	if(RUBY_RAISE_ENABLED()) {
444
	    RUBY_RAISE(rb_obj_classname(th->errinfo),
445
		    rb_sourcefile(),
446
		    rb_sourceline());
447
	}
442 448
	EXEC_EVENT_HOOK(th, RUBY_EVENT_RAISE, th->cfp->self, 0, 0);
443 449
    }
444 450
}
gc.c
21 21
#include "internal.h"
22 22
#include "gc.h"
23 23
#include "constant.h"
24
#include "probes.h"
24 25
#include <stdio.h>
25 26
#include <setjmp.h>
26 27
#include <sys/types.h>
......
170 171
}
171 172

  
172 173
#define GC_PROF_TIMER_START do {\
174
	if (RUBY_GC_BEGIN_ENABLED()) { \
175
	    RUBY_GC_BEGIN(); \
176
	} \
173 177
	if (objspace->profile.run) {\
174 178
	    if (!objspace->profile.record) {\
175 179
		objspace->profile.size = 1000;\
......
189 193
    } while(0)
190 194

  
191 195
#define GC_PROF_TIMER_STOP(marked) do {\
196
	if (RUBY_GC_END_ENABLED()) { \
197
	    RUBY_GC_END(); \
198
	} \
192 199
	if (objspace->profile.run) {\
193 200
	    gc_time = getrusage_time() - gc_time;\
194 201
	    if (gc_time < 0) gc_time = 0;\
......
2377 2384

  
2378 2385
    during_gc++;
2379 2386
    GC_PROF_TIMER_START;
2387
    if (RUBY_GC_SWEEP_BEGIN_ENABLED()) {
2388
	RUBY_GC_SWEEP_BEGIN();
2389
    }
2380 2390
    GC_PROF_SWEEP_TIMER_START;
2381 2391

  
2382 2392
    if (objspace->heap.sweep_slots) {
2383 2393
        res = lazy_sweep(objspace);
2384 2394
        if (res) {
2395
	    if (RUBY_GC_SWEEP_END_ENABLED()) {
2396
		RUBY_GC_SWEEP_END();
2397
	    }
2385 2398
            GC_PROF_SWEEP_TIMER_STOP;
2386 2399
            GC_PROF_SET_MALLOC_INFO;
2387 2400
            GC_PROF_TIMER_STOP(Qfalse);
......
2403 2416
	set_heaps_increment(objspace);
2404 2417
    }
2405 2418

  
2419
    if (RUBY_GC_SWEEP_BEGIN_ENABLED()) {
2420
	RUBY_GC_SWEEP_BEGIN();
2421
    }
2406 2422
    GC_PROF_SWEEP_TIMER_START;
2407 2423
    if (!(res = lazy_sweep(objspace))) {
2408 2424
        after_gc_sweep(objspace);
......
2411 2427
            during_gc = 0;
2412 2428
        }
2413 2429
    }
2430
    if (RUBY_GC_SWEEP_END_ENABLED()) {
2431
	RUBY_GC_SWEEP_END();
2432
    }
2414 2433
    GC_PROF_SWEEP_TIMER_STOP;
2415 2434

  
2416 2435
    GC_PROF_TIMER_STOP(Qtrue);
......
2648 2667
{
2649 2668
    struct gc_list *list;
2650 2669
    rb_thread_t *th = GET_THREAD();
2670
    if (RUBY_GC_MARK_BEGIN_ENABLED()) {
2671
	RUBY_GC_MARK_BEGIN();
2672
    }
2651 2673
    GC_PROF_MARK_TIMER_START;
2652 2674

  
2653 2675
    objspace->heap.live_num = 0;
......
2691 2713
	    gc_mark_rest(objspace);
2692 2714
	}
2693 2715
    }
2716
    if (RUBY_GC_MARK_END_ENABLED()) {
2717
	RUBY_GC_MARK_END();
2718
    }
2694 2719
    GC_PROF_MARK_TIMER_STOP;
2695 2720
}
2696 2721

  
......
2715 2740
    during_gc++;
2716 2741
    gc_marks(objspace);
2717 2742

  
2743
    if (RUBY_GC_SWEEP_BEGIN_ENABLED()) {
2744
	RUBY_GC_SWEEP_BEGIN();
2745
    }
2718 2746
    GC_PROF_SWEEP_TIMER_START;
2719 2747
    gc_sweep(objspace);
2748
    if (RUBY_GC_SWEEP_END_ENABLED()) {
2749
	RUBY_GC_SWEEP_END();
2750
    }
2720 2751
    GC_PROF_SWEEP_TIMER_STOP;
2721 2752

  
2722 2753
    GC_PROF_TIMER_STOP(Qtrue);
insns.def
378 378
()
379 379
(VALUE val)
380 380
{
381
    if(RUBY_OBJECT_CREATE_START_ENABLED()) {
382
	RUBY_OBJECT_CREATE_START("String", rb_sourcefile(), rb_sourceline());
383
    }
384

  
381 385
    val = rb_str_resurrect(str);
386

  
387
    if(RUBY_OBJECT_CREATE_DONE_ENABLED()) {
388
	RUBY_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_OBJECT_CREATE_START_ENABLED()) {
462
	RUBY_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_OBJECT_CREATE_DONE_ENABLED()) {
468
	RUBY_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_OBJECT_CREATE_START_ENABLED()) {
613
	RUBY_OBJECT_CREATE_START("Hash", rb_sourcefile(), rb_sourceline());
614
    }
615

  
595 616
    val = rb_hash_new();
596 617

  
618
    if(RUBY_OBJECT_CREATE_DONE_ENABLED()) {
619
	RUBY_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);
......
875 900
{
876 901
    rb_event_flag_t flag = (rb_event_flag_t)nf;
877 902

  
903
    if (RUBY_LINE_ENABLED()) {
904
	if (flag == RUBY_EVENT_LINE) {
905
          RUBY_LINE(rb_sourcefile(), rb_sourceline());
906
	}
907
    }
908

  
909
    if (RUBY_FUNCTION_ENTRY_ENABLED()) {
910
        if (flag == RUBY_EVENT_CALL || flag == RUBY_EVENT_C_CALL) {
911
          VALUE klass;
912
          ID called_id;
913

  
914
          rb_thread_method_id_and_class(th, &called_id, &klass);
915

  
916
          RUBY_FUNCTION_ENTRY(
917
                  rb_class2name(klass),
918
                  rb_id2name(called_id),
919
                  rb_sourcefile(),
920
                  rb_sourceline());
921
        }
922
    }
923
    if (RUBY_FUNCTION_RETURN_ENABLED()) {
924
        if (flag == RUBY_EVENT_RETURN || flag == RUBY_EVENT_C_RETURN) {
925
          VALUE klass;
926
          ID called_id;
927

  
928
          rb_thread_method_id_and_class(th, &called_id, &klass);
929

  
930
          RUBY_FUNCTION_RETURN(
931
                  rb_class2name(klass),
932
                  rb_id2name(called_id),
933
                  rb_sourcefile(),
934
                  rb_sourceline());
935
        }
936
    }
878 937
    EXEC_EVENT_HOOK(th, flag, GET_SELF(), 0, 0 /* TODO: id, klass */);
879 938
}
880 939

  
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

  
......
374 375
    VALUE fname, wrap, path;
375 376

  
376 377
    rb_scan_args(argc, argv, "11", &fname, &wrap);
378

  
379
    if(RUBY_LOAD_ENTRY_ENABLED()) {
380
      RUBY_LOAD_ENTRY(
381
          StringValuePtr(fname),
382
          rb_sourcefile(),
383
          rb_sourceline());
384
    }
385

  
377 386
    path = rb_find_file(FilePathValue(fname));
378 387
    if (!path) {
379 388
	if (!rb_file_load_ok(RSTRING_PTR(fname)))
......
381 390
	path = fname;
382 391
    }
383 392
    rb_load_internal(path, RTEST(wrap));
393

  
394
    if(RUBY_LOAD_RETURN_ENABLED()) {
395
      RUBY_LOAD_RETURN(StringValuePtr(fname));
396
    }
397

  
384 398
    return Qtrue;
385 399
}
386 400

  
......
614 628
    } volatile saved;
615 629
    char *volatile ftptr = 0;
616 630

  
631
    if(RUBY_REQUIRE_ENTRY_ENABLED()) {
632
      RUBY_REQUIRE_ENTRY(
633
          StringValuePtr(fname),
634
          rb_sourcefile(),
635
          rb_sourceline());
636
    }
637

  
617 638
    PUSH_TAG();
618 639
    saved.safe = rb_safe_level();
619 640
    if ((state = EXEC_TAG()) == 0) {
......
660 681

  
661 682
    th->errinfo = errinfo;
662 683

  
684
    if(RUBY_REQUIRE_RETURN_ENABLED()) {
685
      RUBY_REQUIRE_RETURN(StringValuePtr(fname));
686
    }
687

  
663 688
    return result;
664 689
}
665 690

  
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_OBJECT_CREATE_START_ENABLED()) {
1681
        const char * file = rb_sourcefile();
1682
        RUBY_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_OBJECT_CREATE_DONE_ENABLED()) {
1690
        const char * file = rb_sourcefile();
1691
        RUBY_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
tool/dummy_probe_gen.rb
1
system("dtrace -o probes.h -h -s probes.d")
2
funcs = File.readlines('probes.h').grep(/^#define\s*(RUBY_.*?)\s*\\$/) {
3
  function = $1
4
  if function =~ /\(\)$/
5
    "#define #{function} 0"
6
  else
7
    "#defune #{function}"
8
  end
9
}
10

  
11
puts <<-eoheader
12
#ifndef	_PROBES_H
13
#define	_PROBES_H
14

  
15
#{funcs.join "\n"}
16

  
17
#endif	/* _PROBES_H */
18
eoheader
vm_eval.c
68 68
      }
69 69
      case VM_METHOD_TYPE_NOTIMPLEMENTED:
70 70
      case VM_METHOD_TYPE_CFUNC: {
71
        if (RUBY_FUNCTION_ENTRY_ENABLED()) {
72
            const char * classname  = rb_class2name(klass);
73
            const char * methodname = rb_id2name(id);
74
            const char * filename   = rb_sourcefile();
75
            if (classname && methodname && filename) {
76
              RUBY_FUNCTION_ENTRY(
77
                      classname,
78
                      methodname,
79
                      filename,
80
                      rb_sourceline());
81
            }
82
        }
71 83
	EXEC_EVENT_HOOK(th, RUBY_EVENT_C_CALL, recv, id, klass);
72 84
	{
73 85
	    rb_control_frame_t *reg_cfp = th->cfp;
......
83 95
	    }
84 96
	    vm_pop_frame(th);
85 97
	}
98
        if (RUBY_FUNCTION_RETURN_ENABLED()) {
99
            const char * classname  = rb_class2name(klass);
100
            const char * methodname = rb_id2name(id);
101
            const char * filename   = rb_sourcefile();
102
            if (classname && methodname && filename) {
103
              RUBY_FUNCTION_RETURN(
104
                      classname,
105
                      methodname,
106
                      filename,
107
                      rb_sourceline());
108
            }
109
        }
86 110
	EXEC_EVENT_HOOK(th, RUBY_EVENT_C_RETURN, recv, id, klass);
87 111
	break;
88 112
      }
......
140 164
	rb_bug("vm_call0: unsupported method type (%d)", def->type);
141 165
	val = Qundef;
142 166
    }
167

  
143 168
    RUBY_VM_CHECK_INTS();
144 169
    return val;
145 170
}
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

  
......
444 445
    const rb_method_definition_t *def = me->def;
445 446
    rb_control_frame_t *cfp;
446 447

  
448
    if (RUBY_FUNCTION_ENTRY_ENABLED()) {
449
        const char * classname  = rb_class2name(me->klass);
450
        const char * methodname = rb_id2name(me->called_id);
451
        const char * filename   = rb_sourcefile();
452
        if (classname && methodname && filename) {
453
            RUBY_FUNCTION_ENTRY(
454
                    classname,
455
                    methodname,
456
                    filename,
457
                    rb_sourceline());
458
        }
459
    }
447 460
    EXEC_EVENT_HOOK(th, RUBY_EVENT_C_CALL, recv, me->called_id, me->klass);
448 461

  
449 462
    cfp = vm_push_frame(th, 0, VM_FRAME_MAGIC_CFUNC,
......
459 472

  
460 473
    vm_pop_frame(th);
461 474

  
475
    if (RUBY_FUNCTION_RETURN_ENABLED()) {
476
        const char * classname  = rb_class2name(me->klass);
477
        const char * methodname = rb_id2name(me->called_id);
478
        const char * filename   = rb_sourcefile();
479
        if (classname && methodname && filename) {
480
            RUBY_FUNCTION_RETURN(
481
                    classname,
482
                    methodname,
483
                    filename,
484
                    rb_sourceline());
485
        }
486
    }
462 487
    EXEC_EVENT_HOOK(th, RUBY_EVENT_C_RETURN, recv, me->called_id, me->klass);
463 488

  
464 489
    return val;
......
471 496
    rb_proc_t *proc;
472 497
    VALUE val;
473 498

  
499
    if (RUBY_FUNCTION_ENTRY_ENABLED()) {
500
	RUBY_FUNCTION_ENTRY(
501
		rb_class2name(me->klass),
502
		rb_id2name(me->called_id),
503
		rb_sourcefile(),
504
		rb_sourceline());
505
    }
474 506
    EXEC_EVENT_HOOK(th, RUBY_EVENT_CALL, recv, me->called_id, me->klass);
475 507

  
476 508
    /* control block frame */
......
478 510
    GetProcPtr(me->def->body.proc, proc);
479 511
    val = rb_vm_invoke_proc(th, proc, recv, argc, argv, blockptr);
480 512

  
513
    if (RUBY_FUNCTION_RETURN_ENABLED()) {
514
	RUBY_FUNCTION_RETURN(
515
		rb_class2name(me->klass),
516
		rb_id2name(me->called_id),
517
		rb_sourcefile(),
518
		rb_sourceline());
519
    }
481 520
    EXEC_EVENT_HOOK(th, RUBY_EVENT_RETURN, recv, me->called_id, me->klass);
482 521

  
483 522
    return val;