pline 0.0.3

Sign up to get free protection for your applications and to get access to all the features.
Files changed (51) hide show
  1. data/README +134 -0
  2. data/ext/pline/depend +55 -0
  3. data/ext/pline/extconf.rb +14 -0
  4. data/ext/pline/iseq.c +124 -0
  5. data/ext/pline/minfo.c +167 -0
  6. data/ext/pline/pline.c.rb +68 -0
  7. data/ext/pline/profiler.c +125 -0
  8. data/ext/pline/ruby_source/1.9.2/debug.h +36 -0
  9. data/ext/pline/ruby_source/1.9.2/eval_intern.h +232 -0
  10. data/ext/pline/ruby_source/1.9.2/gc.h +77 -0
  11. data/ext/pline/ruby_source/1.9.2/id.h +170 -0
  12. data/ext/pline/ruby_source/1.9.2/insns.inc +179 -0
  13. data/ext/pline/ruby_source/1.9.2/insns_info.inc +695 -0
  14. data/ext/pline/ruby_source/1.9.2/iseq.h +104 -0
  15. data/ext/pline/ruby_source/1.9.2/manual_update.h +19 -0
  16. data/ext/pline/ruby_source/1.9.2/method.h +103 -0
  17. data/ext/pline/ruby_source/1.9.2/node.h +483 -0
  18. data/ext/pline/ruby_source/1.9.2/thread_pthread.h +27 -0
  19. data/ext/pline/ruby_source/1.9.2/thread_win32.h +33 -0
  20. data/ext/pline/ruby_source/1.9.2/vm_core.h +706 -0
  21. data/ext/pline/ruby_source/1.9.2/vm_exec.h +184 -0
  22. data/ext/pline/ruby_source/1.9.2/vm_insnhelper.c +1734 -0
  23. data/ext/pline/ruby_source/1.9.2/vm_insnhelper.h +208 -0
  24. data/ext/pline/ruby_source/1.9.2/vm_opts.h +51 -0
  25. data/ext/pline/ruby_source/1.9.3/atomic.h +56 -0
  26. data/ext/pline/ruby_source/1.9.3/constant.h +34 -0
  27. data/ext/pline/ruby_source/1.9.3/debug.h +41 -0
  28. data/ext/pline/ruby_source/1.9.3/eval_intern.h +234 -0
  29. data/ext/pline/ruby_source/1.9.3/gc.h +98 -0
  30. data/ext/pline/ruby_source/1.9.3/id.h +175 -0
  31. data/ext/pline/ruby_source/1.9.3/insns.inc +179 -0
  32. data/ext/pline/ruby_source/1.9.3/insns_info.inc +695 -0
  33. data/ext/pline/ruby_source/1.9.3/internal.h +227 -0
  34. data/ext/pline/ruby_source/1.9.3/iseq.h +125 -0
  35. data/ext/pline/ruby_source/1.9.3/manual_update.h +19 -0
  36. data/ext/pline/ruby_source/1.9.3/method.h +105 -0
  37. data/ext/pline/ruby_source/1.9.3/node.h +503 -0
  38. data/ext/pline/ruby_source/1.9.3/thread_pthread.h +51 -0
  39. data/ext/pline/ruby_source/1.9.3/thread_win32.h +40 -0
  40. data/ext/pline/ruby_source/1.9.3/vm_core.h +756 -0
  41. data/ext/pline/ruby_source/1.9.3/vm_exec.h +184 -0
  42. data/ext/pline/ruby_source/1.9.3/vm_insnhelper.c +1749 -0
  43. data/ext/pline/ruby_source/1.9.3/vm_insnhelper.h +220 -0
  44. data/ext/pline/ruby_source/1.9.3/vm_opts.h +51 -0
  45. data/ext/pline/sinfo.c +311 -0
  46. data/lib/pline.rb +11 -0
  47. data/lib/pline/minfo.rb +22 -0
  48. data/lib/pline/summarize.rb +127 -0
  49. data/lib/pline/util.rb +54 -0
  50. data/pline.gemspec +28 -0
  51. metadata +102 -0
data/README ADDED
@@ -0,0 +1,134 @@
1
+ * About PLine
2
+ PLine is a profiler for Ruby1.9.3 and Ruby1.9.2.
3
+ PLine profiles each line of Ruby method (method written in Ruby) you specified.
4
+ Using PLine, you can profile each line of Ruby method easily.
5
+
6
+ This README document introduces basic functionality of PLine.
7
+ If you have any questions or comments, please send email to shiba@rvm.jp,
8
+ or use http://github.com/soba1104/PLine/issues.
9
+
10
+
11
+
12
+ * License
13
+ Same as the license of Ruby runtime.
14
+
15
+
16
+
17
+ * Installation
18
+ $gem install pline
19
+
20
+ Currently, PLine supports Ruby1.9.3 and Ruby1.9.2 only.
21
+ So, if you want to use PLine, please install PLine
22
+ under Ruby1.9.3 or Ruby1.9.2 runtime.
23
+
24
+
25
+
26
+ * Usage
27
+ ############### sample code ###############
28
+ require 'pline'
29
+
30
+ # Target method of profiling
31
+ def sum(a, b)
32
+ a + b
33
+ end
34
+
35
+ # Specify unit of measurement to PLine
36
+ PLine.show_msec()
37
+
38
+ # Specify profiling to PLine
39
+ PLine.profile(self, :sum, true)
40
+
41
+ 1000000.times{|i| sum(i, i)}
42
+
43
+ ################## result ##################
44
+ -----------------------------------------
45
+ | main.sum: tmp/sample.rb(4 - 6) |
46
+ |-----------------------------------------|
47
+ | Line | Time(msec) | Source |
48
+ |-----------------------------------------|
49
+ | 4 | 0 | def sum(a, b) |
50
+ | 5 | 625 | a + b | < You can know that
51
+ | 6 | 0 | end | 'a + b' takes 625 microseconds.
52
+ -----------------------------------------
53
+
54
+
55
+
56
+ * Attention
57
+ Currently, PLine is alpha version. So, you must not use PLine in critical mission.
58
+ This section introduces some attentions about PLine.
59
+
60
+ ** Recursive call profiling
61
+ PLine cannot profile recursive call statements correctly.
62
+ Profiling results of recursive call statements may become short.
63
+
64
+ ** Block invocation profiling
65
+ PLine cannot profile exit points of block invocation.
66
+ Profiling results of exit points of block invocation may become significantly short.
67
+
68
+ ------------------------ example ------------------------
69
+ # sample code
70
+ require 'pline'
71
+
72
+ def foo
73
+ sum = 0
74
+ 100000.times{|i|
75
+ sum += i
76
+ sum += i
77
+ }
78
+ sum
79
+ end
80
+
81
+ PLine.profile(self, :foo, true)
82
+ foo()
83
+
84
+ # result
85
+ ----------------------------------------
86
+ | main.foo: tmp/test2.rb(3 - 10) |
87
+ |----------------------------------------|
88
+ | Line | Time(usec) | Source |
89
+ |----------------------------------------|
90
+ | 3 | 0 | def foo |
91
+ | 4 | 2 | sum = 0 |
92
+ | 5 | 2 | 100000.times{|i| |
93
+ | 6 | 81190 | sum += i |
94
+ | 7 | 3 | sum += i | <= this
95
+ | 8 | 0 | } |
96
+ | 9 | 1 | sum |
97
+ | 10 | 0 | end |
98
+ ----------------------------------------
99
+ ---------------------------------------------------------
100
+
101
+ ** Using together with other profiler
102
+ PLine rewrites RUBY_EVENT_LINE event to RUBY_EVENT_END event.
103
+ So, when you use PLine, above events become incompatible.
104
+ You should not use PLine together with other profilers which use above events.
105
+
106
+
107
+
108
+ * PLine APIs
109
+ This section introduces PLine APIs.
110
+
111
+ ** A API of specifying profiling
112
+ - PLine.profile(object, method_id, singleton_p = false)
113
+ Specify profiling to PLine.
114
+ When singleton_p argument(third argument) is false, PLine searches object#method_id (instance method).
115
+ Otherwise, PLine searches object.method_id (singleton_method).
116
+
117
+ ** APIs of specifying output
118
+ - PLine.output=(io)
119
+ Specify output io object.
120
+ Default output of PLine is STDERR.
121
+
122
+ - PLine.show_sec()
123
+ Specify sec as the unit of measurement.
124
+
125
+ - PLine.show_msec()
126
+ Specify millisec as the unit of measurement.
127
+
128
+ - PLine.show_usec()
129
+ Specify microsec as the unit of measurement.
130
+ Microsec is the default unit of measurement.
131
+
132
+ - PLine.show_nsec()
133
+ Specify nanosec as the unit of measurement.
134
+
@@ -0,0 +1,55 @@
1
+ HEADERS = \
2
+ $(arch_hdrdir)/ruby/config.h \
3
+ $(hdrdir)/ruby/defines.h \
4
+ $(hdrdir)/ruby/intern.h \
5
+ $(hdrdir)/ruby/missing.h \
6
+ $(hdrdir)/ruby/ruby.h \
7
+ $(hdrdir)/ruby/st.h \
8
+ $(srcdir)/ruby_source/1.9.3/eval_intern.h \
9
+ $(srcdir)/ruby_source/1.9.3/iseq.h \
10
+ $(srcdir)/ruby_source/1.9.3/method.h \
11
+ $(srcdir)/ruby_source/1.9.3/node.h \
12
+ $(srcdir)/ruby_source/1.9.3/thread_pthread.h \
13
+ $(srcdir)/ruby_source/1.9.3/thread_win32.h \
14
+ $(srcdir)/ruby_source/1.9.3/vm_core.h \
15
+ $(srcdir)/ruby_source/1.9.3/vm_exec.h \
16
+ $(srcdir)/ruby_source/1.9.3/vm_insnhelper.c \
17
+ $(srcdir)/ruby_source/1.9.3/vm_insnhelper.h \
18
+ $(srcdir)/ruby_source/1.9.3/vm_opts.h \
19
+ $(srcdir)/ruby_source/1.9.3/insns_info.inc \
20
+ $(srcdir)/ruby_source/1.9.3/insns.inc \
21
+ $(srcdir)/ruby_source/1.9.3/constant.h \
22
+ $(srcdir)/ruby_source/1.9.3/atomic.h \
23
+ $(srcdir)/ruby_source/1.9.3/internal.h \
24
+ $(srcdir)/ruby_source/1.9.3/manual_update.h \
25
+ $(srcdir)/ruby_source/1.9.2/debug.h \
26
+ $(srcdir)/ruby_source/1.9.2/gc.h \
27
+ $(srcdir)/ruby_source/1.9.2/id.h \
28
+ $(srcdir)/ruby_source/1.9.2/eval_intern.h \
29
+ $(srcdir)/ruby_source/1.9.2/iseq.h \
30
+ $(srcdir)/ruby_source/1.9.2/method.h \
31
+ $(srcdir)/ruby_source/1.9.2/node.h \
32
+ $(srcdir)/ruby_source/1.9.2/thread_pthread.h \
33
+ $(srcdir)/ruby_source/1.9.2/thread_win32.h \
34
+ $(srcdir)/ruby_source/1.9.2/vm_core.h \
35
+ $(srcdir)/ruby_source/1.9.2/vm_exec.h \
36
+ $(srcdir)/ruby_source/1.9.2/vm_insnhelper.c \
37
+ $(srcdir)/ruby_source/1.9.2/vm_insnhelper.h \
38
+ $(srcdir)/ruby_source/1.9.2/vm_opts.h \
39
+ $(srcdir)/ruby_source/1.9.2/insns_info.inc \
40
+ $(srcdir)/ruby_source/1.9.2/insns.inc \
41
+ $(srcdir)/ruby_source/1.9.2/manual_update.h \
42
+ $(srcdir)/extconf.h
43
+
44
+ $(srcdir)/pline.c: \
45
+ $(srcdir)/pline.c.rb
46
+ $(RUBY) -- $(srcdir)/pline.c.rb > $@
47
+
48
+ $(srcdir)/pline.o: \
49
+ $(HEADERS) \
50
+ $(srcdir)/profiler.c \
51
+ $(srcdir)/sinfo.c \
52
+ $(srcdir)/minfo.c \
53
+ $(srcdir)/iseq.c \
54
+ $(srcdir)/pline.c
55
+
@@ -0,0 +1,14 @@
1
+ # coding=utf-8
2
+
3
+ require 'mkmf'
4
+ require 'rbconfig'
5
+ extend RbConfig
6
+
7
+ $defs.push '-DCABI_OPERANDS' if enable_config 'cabi-operands', true
8
+ $defs.push '-DCABI_PASS_CFP' if enable_config 'cabi-pass-cfp', true
9
+
10
+ $INCFLAGS << ' -I$(srcdir)/ruby_source'
11
+ $objs = %w'$(srcdir)/pline.o'
12
+ create_header
13
+ create_makefile 'pline'
14
+
@@ -0,0 +1,124 @@
1
+ static rb_iseq_t *iseq_find(VALUE obj, VALUE mid, VALUE singleton_p)
2
+ {
3
+ rb_method_entry_t *me;
4
+ rb_method_definition_t *def;
5
+ VALUE km;
6
+ int class;
7
+ const char *msg = NULL;
8
+ VALUE name;
9
+ const char *sep = RTEST(singleton_p) ? "." : "#";
10
+
11
+ if (RTEST(singleton_p)) {
12
+ class = 1;
13
+ km = rb_class_of(obj);
14
+ } else {
15
+ VALUE c = rb_obj_class(obj);
16
+ if (c == rb_cClass) {
17
+ class = 1;
18
+ } else if (c == rb_cModule) {
19
+ class = 0;
20
+ } else {
21
+ rb_raise(rb_eArgError, "expected class or module");
22
+ }
23
+ km = obj;
24
+ }
25
+
26
+ me = search_method(km, SYM2ID(mid));
27
+ if (!me) {
28
+ if (class) {
29
+ name = rb_class_path(km);
30
+ } else {
31
+ name = rb_mod_name(km);
32
+ }
33
+ rb_raise(rb_eArgError, "method not found (%s%s%s)",
34
+ RSTRING_PTR(name), sep, rb_id2name(SYM2ID(mid)));
35
+ }
36
+
37
+ def = me->def;
38
+ switch (def->type) {
39
+ case VM_METHOD_TYPE_ISEQ:
40
+ return def->body.iseq;
41
+ case VM_METHOD_TYPE_CFUNC:
42
+ msg = "PLine cannot handle C method";
43
+ break;
44
+ case VM_METHOD_TYPE_ATTRSET:
45
+ msg = "PLine cannot handle attr_writer";
46
+ break;
47
+ case VM_METHOD_TYPE_IVAR:
48
+ msg = "PLine cannot handle attr_reader";
49
+ break;
50
+ case VM_METHOD_TYPE_BMETHOD:
51
+ msg = "Currently, PLine cannot handle method defined by define_method";
52
+ break;
53
+ case VM_METHOD_TYPE_ZSUPER:
54
+ msg = "Unsupported method type zsuper";
55
+ break;
56
+ case VM_METHOD_TYPE_UNDEF:
57
+ msg = "Unsupported method type undef";
58
+ break;
59
+ case VM_METHOD_TYPE_NOTIMPLEMENTED:
60
+ msg = "Unsupported method type notimplemented";
61
+ break;
62
+ case VM_METHOD_TYPE_OPTIMIZED:
63
+ msg = "Unsupported method type optimized";
64
+ break;
65
+ case VM_METHOD_TYPE_MISSING:
66
+ msg = "Unsupported method type missing";
67
+ break;
68
+ default:
69
+ msg = NULL;
70
+ }
71
+
72
+ if (!msg) {
73
+ rb_bug("pline_find_iseq: should not be reached(1)");
74
+ }
75
+
76
+ if (class) {
77
+ name = rb_class_path(km);
78
+ } else {
79
+ name = rb_mod_name(km);
80
+ }
81
+ rb_raise(rb_eArgError, "%s (%s%s%s)",
82
+ msg, RSTRING_PTR(name), sep, rb_id2name(SYM2ID(mid)));
83
+ }
84
+
85
+ static void iseq_inject(rb_iseq_t *iseq)
86
+ {
87
+ int idx, len = iseq->iseq_size;
88
+ VALUE *seq = iseq->iseq;
89
+ VALUE *enc = iseq->iseq_encoded;
90
+
91
+ for (idx = 0; idx < len; idx += insn_len(seq[idx])) {
92
+ VALUE insn = seq[idx];
93
+ VALUE *op0 = &seq[idx] + 1;
94
+ VALUE *op1 = &enc[idx] + 1;
95
+ rb_num_t nf;
96
+ rb_iseq_t *child = NULL;
97
+
98
+ switch(insn) {
99
+ case BIN(trace):
100
+ nf = op0[0];
101
+ if (nf == RUBY_EVENT_LINE || nf == RUBY_EVENT_RETURN) {
102
+ op0[0] = RUBY_EVENT_END;
103
+ op1[0] = RUBY_EVENT_END;
104
+ }
105
+ break;
106
+ case BIN(putiseq):
107
+ child = (rb_iseq_t *)op0[0];
108
+ break;
109
+ case BIN(defineclass):
110
+ child = (rb_iseq_t *)op0[1];
111
+ break;
112
+ case BIN(send):
113
+ child = (rb_iseq_t *)op0[2];
114
+ break;
115
+ case BIN(invokesuper):
116
+ child = (rb_iseq_t *)op0[1];
117
+ break;
118
+ }
119
+ if (child) {
120
+ iseq_inject(child);
121
+ }
122
+ }
123
+ }
124
+
@@ -0,0 +1,167 @@
1
+ typedef struct pline_method_info {
2
+ VALUE obj;
3
+ VALUE mid;
4
+ VALUE spath;
5
+ VALUE sline;
6
+ VALUE eline;
7
+ VALUE singleton_p;
8
+ } pline_method_info_t;
9
+
10
+ static void minfo_mark(void *ptr)
11
+ {
12
+ pline_method_info_t *m = ptr;
13
+
14
+ if (!m) return;
15
+ rb_gc_mark(m->obj);
16
+ rb_gc_mark(m->mid);
17
+ rb_gc_mark(m->spath);
18
+ rb_gc_mark(m->sline);
19
+ rb_gc_mark(m->eline);
20
+ rb_gc_mark(m->singleton_p);
21
+ }
22
+
23
+ static void minfo_free(void *p)
24
+ {
25
+ if (p) xfree(p);
26
+ }
27
+
28
+ static const rb_data_type_t minfo_data_type = {
29
+ "pline_method_info",
30
+ {minfo_mark, minfo_free, NULL,},
31
+ };
32
+
33
+ static VALUE minfo_s_alloc(VALUE klass)
34
+ {
35
+ VALUE obj;
36
+ pline_method_info_t *m;
37
+
38
+ obj = TypedData_Make_Struct(klass, pline_method_info_t, &minfo_data_type, m);
39
+ m->spath = Qnil;
40
+ m->sline = Qnil;
41
+ m->eline = Qnil;
42
+
43
+ return obj;
44
+ }
45
+
46
+ static void minfo_source_information_error(void)
47
+ {
48
+ rb_raise(rb_eArgError, "unexpected source information");
49
+ }
50
+
51
+ static void check_line_information(VALUE line)
52
+ {
53
+ if (rb_class_of(line) != rb_cFixnum || FIX2LONG(line) < 0) {
54
+ minfo_source_information_error();
55
+ }
56
+ }
57
+
58
+ static VALUE minfo_spath_from_iseq(VALUE iseqval)
59
+ {
60
+ rb_iseq_t *iseq = DATA_PTR(iseqval);
61
+ VALUE spath = iseq->filename;
62
+ VALUE valid = rb_funcall(rb_cFile, rb_intern("exist?"), 1, spath);
63
+
64
+ if (!RTEST(valid)) {
65
+ minfo_source_information_error();
66
+ }
67
+
68
+ return spath;
69
+ }
70
+
71
+ static VALUE minfo_sline_from_iseq(VALUE iseqval)
72
+ {
73
+ rb_iseq_t *iseq = DATA_PTR(iseqval);
74
+ VALUE sline = iseq->line_no;
75
+
76
+ check_line_information(sline);
77
+
78
+ return sline;
79
+ }
80
+
81
+ static VALUE minfo_eline_from_iseq(VALUE iseqval)
82
+ {
83
+ rb_iseq_t *iseq = DATA_PTR(iseqval);
84
+ VALUE eline = iseq->line_no;
85
+ unsigned int i;
86
+
87
+ check_line_information(eline);
88
+
89
+ for (i = 0; i < iseq->insn_info_size; i++) {
90
+ VALUE l = LONG2FIX(iseq->insn_info_table[i].line_no);
91
+ if (l > eline) {
92
+ eline = l;
93
+ }
94
+ }
95
+
96
+ return eline;
97
+ }
98
+
99
+ static VALUE minfo_m_init(VALUE self, VALUE iseq, VALUE obj, VALUE mid, VALUE singleton_p)
100
+ {
101
+ pline_method_info_t *m = DATA_PTR(self);
102
+ VALUE spath, sline, eline;
103
+
104
+ if (rb_obj_class(mid) != rb_cSymbol ||
105
+ rb_obj_class(iseq) != rb_cISeq) {
106
+ rb_raise(rb_eArgError, "invalid arguments");
107
+ }
108
+
109
+ m->obj = obj;
110
+ m->mid = mid;
111
+ m->spath = minfo_spath_from_iseq(iseq);
112
+ m->sline = minfo_sline_from_iseq(iseq);
113
+ m->eline = minfo_eline_from_iseq(iseq);
114
+ m->singleton_p = singleton_p;
115
+
116
+ return Qnil;
117
+ }
118
+
119
+ static VALUE minfo_m_obj(VALUE self)
120
+ {
121
+ pline_method_info_t *m = DATA_PTR(self);
122
+ return m->obj;
123
+ }
124
+
125
+ static VALUE minfo_m_mid(VALUE self)
126
+ {
127
+ pline_method_info_t *m = DATA_PTR(self);
128
+ return m->mid;
129
+ }
130
+
131
+ static VALUE minfo_m_spath(VALUE self)
132
+ {
133
+ pline_method_info_t *m = DATA_PTR(self);
134
+ return m->spath;
135
+ }
136
+
137
+ static VALUE minfo_m_sline(VALUE self)
138
+ {
139
+ pline_method_info_t *m = DATA_PTR(self);
140
+ return m->sline;
141
+ }
142
+
143
+ static VALUE minfo_m_eline(VALUE self)
144
+ {
145
+ pline_method_info_t *m = DATA_PTR(self);
146
+ return m->eline;
147
+ }
148
+
149
+ static VALUE minfo_m_singleton_p(VALUE self)
150
+ {
151
+ pline_method_info_t *m = DATA_PTR(self);
152
+ return RTEST(m->singleton_p) ? Qtrue : Qfalse;
153
+ }
154
+
155
+ static void pline_minfo_init(void)
156
+ {
157
+ cMethodInfo = rb_define_class_under(mPLine, "MethodInfo", rb_cObject);
158
+ rb_define_method(cMethodInfo, "obj", minfo_m_obj, 0);
159
+ rb_define_method(cMethodInfo, "mid", minfo_m_mid, 0);
160
+ rb_define_method(cMethodInfo, "spath", minfo_m_spath, 0);
161
+ rb_define_method(cMethodInfo, "sline", minfo_m_sline, 0);
162
+ rb_define_method(cMethodInfo, "eline", minfo_m_eline, 0);
163
+ rb_define_method(cMethodInfo, "singleton?", minfo_m_singleton_p, 0);
164
+ rb_define_method(cMethodInfo, "initialize", minfo_m_init, 4);
165
+ rb_define_alloc_func(cMethodInfo, minfo_s_alloc);
166
+ }
167
+