pline 0.0.3

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