Project

General

Profile

Feature #2565 ยป dtrace.patch

updated dtrace patch with sed script - tenderlovemaking (Aaron Patterson), 07/19/2012 03:52 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
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;