ruby-prof 0.17.0 → 0.18.0

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 (185) hide show
  1. checksums.yaml +5 -5
  2. data/CHANGES +500 -482
  3. data/LICENSE +24 -24
  4. data/README.rdoc +487 -485
  5. data/Rakefile +113 -113
  6. data/bin/ruby-prof +345 -345
  7. data/bin/ruby-prof-check-trace +45 -45
  8. data/examples/flat.txt +50 -50
  9. data/examples/graph.dot +84 -84
  10. data/examples/graph.html +823 -823
  11. data/examples/graph.txt +139 -139
  12. data/examples/multi.flat.txt +23 -23
  13. data/examples/multi.graph.html +760 -760
  14. data/examples/multi.grind.dat +114 -114
  15. data/examples/multi.stack.html +547 -547
  16. data/examples/stack.html +547 -547
  17. data/ext/ruby_prof/extconf.rb +68 -68
  18. data/ext/ruby_prof/rp_call_info.c +425 -425
  19. data/ext/ruby_prof/rp_call_info.h +53 -53
  20. data/ext/ruby_prof/rp_measure.c +40 -40
  21. data/ext/ruby_prof/rp_measure.h +45 -45
  22. data/ext/ruby_prof/rp_measure_allocations.c +76 -76
  23. data/ext/ruby_prof/rp_measure_cpu_time.c +136 -136
  24. data/ext/ruby_prof/rp_measure_gc_runs.c +73 -73
  25. data/ext/ruby_prof/rp_measure_gc_time.c +60 -60
  26. data/ext/ruby_prof/rp_measure_memory.c +77 -77
  27. data/ext/ruby_prof/rp_measure_process_time.c +71 -71
  28. data/ext/ruby_prof/rp_measure_wall_time.c +45 -45
  29. data/ext/ruby_prof/rp_method.c +630 -636
  30. data/ext/ruby_prof/rp_method.h +75 -75
  31. data/ext/ruby_prof/rp_stack.c +173 -173
  32. data/ext/ruby_prof/rp_stack.h +63 -63
  33. data/ext/ruby_prof/rp_thread.c +277 -276
  34. data/ext/ruby_prof/rp_thread.h +27 -27
  35. data/ext/ruby_prof/ruby_prof.c +794 -774
  36. data/ext/ruby_prof/ruby_prof.h +60 -59
  37. data/ext/ruby_prof/vc/ruby_prof.sln +20 -21
  38. data/ext/ruby_prof/vc/{ruby_prof_20.vcxproj → ruby_prof.vcxproj} +31 -0
  39. data/lib/ruby-prof.rb +68 -68
  40. data/lib/ruby-prof/aggregate_call_info.rb +76 -76
  41. data/lib/ruby-prof/assets/call_stack_printer.css.html +116 -116
  42. data/lib/ruby-prof/assets/call_stack_printer.js.html +384 -384
  43. data/lib/ruby-prof/call_info.rb +115 -115
  44. data/lib/ruby-prof/call_info_visitor.rb +40 -40
  45. data/lib/ruby-prof/compatibility.rb +179 -178
  46. data/lib/ruby-prof/method_info.rb +121 -121
  47. data/lib/ruby-prof/printers/abstract_printer.rb +104 -103
  48. data/lib/ruby-prof/printers/call_info_printer.rb +41 -41
  49. data/lib/ruby-prof/printers/call_stack_printer.rb +265 -265
  50. data/lib/ruby-prof/printers/call_tree_printer.rb +143 -143
  51. data/lib/ruby-prof/printers/dot_printer.rb +132 -132
  52. data/lib/ruby-prof/printers/flat_printer.rb +70 -70
  53. data/lib/ruby-prof/printers/flat_printer_with_line_numbers.rb +83 -83
  54. data/lib/ruby-prof/printers/graph_html_printer.rb +249 -249
  55. data/lib/ruby-prof/printers/graph_printer.rb +116 -116
  56. data/lib/ruby-prof/printers/multi_printer.rb +84 -84
  57. data/lib/ruby-prof/profile.rb +26 -26
  58. data/lib/ruby-prof/profile/exclude_common_methods.rb +207 -201
  59. data/lib/ruby-prof/profile/legacy_method_elimination.rb +50 -49
  60. data/lib/ruby-prof/rack.rb +174 -174
  61. data/lib/ruby-prof/task.rb +147 -147
  62. data/lib/ruby-prof/thread.rb +35 -35
  63. data/lib/ruby-prof/version.rb +3 -3
  64. data/lib/unprof.rb +10 -10
  65. data/ruby-prof.gemspec +58 -58
  66. data/test/abstract_printer_test.rb +53 -0
  67. data/test/aggregate_test.rb +136 -136
  68. data/test/basic_test.rb +128 -128
  69. data/test/block_test.rb +74 -74
  70. data/test/call_info_test.rb +78 -78
  71. data/test/call_info_visitor_test.rb +31 -31
  72. data/test/duplicate_names_test.rb +32 -32
  73. data/test/dynamic_method_test.rb +55 -55
  74. data/test/enumerable_test.rb +21 -21
  75. data/test/exceptions_test.rb +24 -16
  76. data/test/exclude_methods_test.rb +146 -146
  77. data/test/exclude_threads_test.rb +53 -53
  78. data/test/fiber_test.rb +79 -79
  79. data/test/issue137_test.rb +63 -63
  80. data/test/line_number_test.rb +80 -80
  81. data/test/measure_allocations_test.rb +26 -26
  82. data/test/measure_cpu_time_test.rb +212 -213
  83. data/test/measure_gc_runs_test.rb +32 -32
  84. data/test/measure_gc_time_test.rb +36 -36
  85. data/test/measure_memory_test.rb +33 -33
  86. data/test/measure_process_time_test.rb +61 -63
  87. data/test/measure_wall_time_test.rb +255 -255
  88. data/test/method_elimination_test.rb +84 -84
  89. data/test/module_test.rb +45 -45
  90. data/test/multi_printer_test.rb +104 -104
  91. data/test/no_method_class_test.rb +15 -15
  92. data/test/pause_resume_test.rb +166 -166
  93. data/test/prime.rb +54 -54
  94. data/test/printers_test.rb +275 -275
  95. data/test/printing_recursive_graph_test.rb +127 -127
  96. data/test/rack_test.rb +157 -157
  97. data/test/recursive_test.rb +215 -215
  98. data/test/singleton_test.rb +38 -38
  99. data/test/stack_printer_test.rb +77 -78
  100. data/test/stack_test.rb +138 -138
  101. data/test/start_stop_test.rb +112 -112
  102. data/test/test_helper.rb +267 -275
  103. data/test/thread_test.rb +187 -187
  104. data/test/unique_call_path_test.rb +202 -202
  105. data/test/yarv_test.rb +55 -55
  106. metadata +17 -96
  107. data/doc/LICENSE.html +0 -115
  108. data/doc/README_rdoc.html +0 -637
  109. data/doc/Rack.html +0 -96
  110. data/doc/Rack/RubyProf.html +0 -233
  111. data/doc/Rack/RubyProf/RackProfiler.html +0 -343
  112. data/doc/RubyProf.html +0 -974
  113. data/doc/RubyProf/AbstractPrinter.html +0 -625
  114. data/doc/RubyProf/AggregateCallInfo.html +0 -552
  115. data/doc/RubyProf/CallInfo.html +0 -579
  116. data/doc/RubyProf/CallInfoPrinter.html +0 -121
  117. data/doc/RubyProf/CallInfoVisitor.html +0 -199
  118. data/doc/RubyProf/CallStackPrinter.html +0 -1127
  119. data/doc/RubyProf/CallTreePrinter.html +0 -725
  120. data/doc/RubyProf/Cmd.html +0 -637
  121. data/doc/RubyProf/DeprecationWarnings.html +0 -148
  122. data/doc/RubyProf/DotPrinter.html +0 -258
  123. data/doc/RubyProf/FlatPrinter.html +0 -164
  124. data/doc/RubyProf/FlatPrinterWithLineNumbers.html +0 -210
  125. data/doc/RubyProf/GraphHtmlPrinter.html +0 -558
  126. data/doc/RubyProf/GraphPrinter.html +0 -140
  127. data/doc/RubyProf/MethodInfo.html +0 -676
  128. data/doc/RubyProf/MultiPrinter.html +0 -574
  129. data/doc/RubyProf/Profile.html +0 -908
  130. data/doc/RubyProf/Profile/ExcludeCommonMethods.html +0 -411
  131. data/doc/RubyProf/Profile/LegacyMethodElimination.html +0 -158
  132. data/doc/RubyProf/ProfileTask.html +0 -491
  133. data/doc/RubyProf/Thread.html +0 -275
  134. data/doc/created.rid +0 -33
  135. data/doc/css/fonts.css +0 -167
  136. data/doc/css/rdoc.css +0 -590
  137. data/doc/examples/flat_txt.html +0 -139
  138. data/doc/examples/graph_html.html +0 -910
  139. data/doc/examples/graph_txt.html +0 -248
  140. data/doc/fonts/Lato-Light.ttf +0 -0
  141. data/doc/fonts/Lato-LightItalic.ttf +0 -0
  142. data/doc/fonts/Lato-Regular.ttf +0 -0
  143. data/doc/fonts/Lato-RegularItalic.ttf +0 -0
  144. data/doc/fonts/SourceCodePro-Bold.ttf +0 -0
  145. data/doc/fonts/SourceCodePro-Regular.ttf +0 -0
  146. data/doc/images/add.png +0 -0
  147. data/doc/images/arrow_up.png +0 -0
  148. data/doc/images/brick.png +0 -0
  149. data/doc/images/brick_link.png +0 -0
  150. data/doc/images/bug.png +0 -0
  151. data/doc/images/bullet_black.png +0 -0
  152. data/doc/images/bullet_toggle_minus.png +0 -0
  153. data/doc/images/bullet_toggle_plus.png +0 -0
  154. data/doc/images/date.png +0 -0
  155. data/doc/images/delete.png +0 -0
  156. data/doc/images/find.png +0 -0
  157. data/doc/images/loadingAnimation.gif +0 -0
  158. data/doc/images/macFFBgHack.png +0 -0
  159. data/doc/images/package.png +0 -0
  160. data/doc/images/page_green.png +0 -0
  161. data/doc/images/page_white_text.png +0 -0
  162. data/doc/images/page_white_width.png +0 -0
  163. data/doc/images/plugin.png +0 -0
  164. data/doc/images/ruby.png +0 -0
  165. data/doc/images/tag_blue.png +0 -0
  166. data/doc/images/tag_green.png +0 -0
  167. data/doc/images/transparent.png +0 -0
  168. data/doc/images/wrench.png +0 -0
  169. data/doc/images/wrench_orange.png +0 -0
  170. data/doc/images/zoom.png +0 -0
  171. data/doc/index.html +0 -666
  172. data/doc/js/darkfish.js +0 -161
  173. data/doc/js/jquery.js +0 -4
  174. data/doc/js/navigation.js +0 -142
  175. data/doc/js/navigation.js.gz +0 -0
  176. data/doc/js/search.js +0 -109
  177. data/doc/js/search_index.js +0 -1
  178. data/doc/js/search_index.js.gz +0 -0
  179. data/doc/js/searcher.js +0 -229
  180. data/doc/js/searcher.js.gz +0 -0
  181. data/doc/table_of_contents.html +0 -1052
  182. data/examples/cachegrind.out.1 +0 -114
  183. data/examples/cachegrind.out.1.32313213 +0 -114
  184. data/ext/ruby_prof/vc/ruby_prof_18.vcxproj +0 -108
  185. data/ext/ruby_prof/vc/ruby_prof_19.vcxproj +0 -110
@@ -1,45 +1,45 @@
1
- /* Copyright (C) 2005-2013 Shugo Maeda <shugo@ruby-lang.org> and Charlie Savage <cfis@savagexi.com>
2
- Please see the LICENSE file for copyright and distribution information */
3
-
4
- /* :nodoc: */
5
- #include "ruby_prof.h"
6
- #if HAVE_GETTIMEOFDAY && !defined(_WIN32)
7
- #include <sys/time.h>
8
- #endif
9
-
10
- static VALUE cMeasureWallTime;
11
-
12
- static double
13
- measure_wall_time()
14
- {
15
- struct timeval tv;
16
- gettimeofday(&tv, NULL);
17
- return tv.tv_sec + (tv.tv_usec/1000000.0);
18
- }
19
-
20
- prof_measurer_t* prof_measurer_wall_time()
21
- {
22
- prof_measurer_t* measure = ALLOC(prof_measurer_t);
23
- measure->measure = measure_wall_time;
24
- return measure;
25
- }
26
-
27
- /* Document-method: prof_measure_wall_time
28
- call-seq:
29
- measure_wall_time -> float
30
-
31
- Returns the wall time.*/
32
- static VALUE
33
- prof_measure_wall_time(VALUE self)
34
- {
35
- return rb_float_new(measure_wall_time());
36
- }
37
-
38
- void rp_init_measure_wall_time()
39
- {
40
- rb_define_const(mProf, "WALL_TIME", INT2NUM(MEASURE_WALL_TIME));
41
- rb_define_const(mProf, "WALL_TIME_ENABLED", Qtrue);
42
-
43
- cMeasureWallTime = rb_define_class_under(mMeasure, "WallTime", rb_cObject);
44
- rb_define_singleton_method(cMeasureWallTime, "measure", prof_measure_wall_time, 0);
45
- }
1
+ /* Copyright (C) 2005-2019 Shugo Maeda <shugo@ruby-lang.org> and Charlie Savage <cfis@savagexi.com>
2
+ Please see the LICENSE file for copyright and distribution information */
3
+
4
+ /* :nodoc: */
5
+ #include "ruby_prof.h"
6
+ #if HAVE_GETTIMEOFDAY && !defined(_WIN32)
7
+ #include <sys/time.h>
8
+ #endif
9
+
10
+ static VALUE cMeasureWallTime;
11
+
12
+ static double
13
+ measure_wall_time()
14
+ {
15
+ struct timeval tv;
16
+ gettimeofday(&tv, NULL);
17
+ return tv.tv_sec + (tv.tv_usec/1000000.0);
18
+ }
19
+
20
+ prof_measurer_t* prof_measurer_wall_time()
21
+ {
22
+ prof_measurer_t* measure = ALLOC(prof_measurer_t);
23
+ measure->measure = measure_wall_time;
24
+ return measure;
25
+ }
26
+
27
+ /* Document-method: prof_measure_wall_time
28
+ call-seq:
29
+ measure_wall_time -> float
30
+
31
+ Returns the wall time.*/
32
+ static VALUE
33
+ prof_measure_wall_time(VALUE self)
34
+ {
35
+ return rb_float_new(measure_wall_time());
36
+ }
37
+
38
+ void rp_init_measure_wall_time()
39
+ {
40
+ rb_define_const(mProf, "WALL_TIME", INT2NUM(MEASURE_WALL_TIME));
41
+ rb_define_const(mProf, "WALL_TIME_ENABLED", Qtrue);
42
+
43
+ cMeasureWallTime = rb_define_class_under(mMeasure, "WallTime", rb_cObject);
44
+ rb_define_singleton_method(cMeasureWallTime, "measure", prof_measure_wall_time, 0);
45
+ }
@@ -1,636 +1,630 @@
1
- /* Copyright (C) 2005-2013 Shugo Maeda <shugo@ruby-lang.org> and Charlie Savage <cfis@savagexi.com>
2
- Please see the LICENSE file for copyright and distribution information */
3
-
4
- #include "ruby_prof.h"
5
-
6
- #define RP_REL_GET(r, off) ((r) & (1 << (off)))
7
- #define RP_REL_SET(r, off) \
8
- do { \
9
- r |= (1 << (off)); \
10
- } while (0)
11
-
12
- VALUE cMethodInfo;
13
-
14
- /* ================ Helper Functions =================*/
15
- static VALUE
16
- figure_singleton_name(VALUE klass)
17
- {
18
- volatile VALUE attached, super;
19
- volatile VALUE attached_str, super_str;
20
- volatile VALUE result = Qnil;
21
-
22
- /* We have come across a singleton object. First
23
- figure out what it is attached to.*/
24
- attached = rb_iv_get(klass, "__attached__");
25
-
26
- /* Is this a singleton class acting as a metaclass? */
27
- if (BUILTIN_TYPE(attached) == T_CLASS)
28
- {
29
- attached_str = rb_class_name(attached);
30
- result = rb_str_new2("<Class::");
31
- rb_str_append(result, attached_str);
32
- rb_str_cat2(result, ">");
33
- }
34
-
35
- /* Is this for singleton methods on a module? */
36
- else if (BUILTIN_TYPE(attached) == T_MODULE)
37
- {
38
- attached_str = rb_class_name(attached);
39
- result = rb_str_new2("<Module::");
40
- rb_str_append(result, attached_str);
41
- rb_str_cat2(result, ">");
42
- }
43
-
44
- /* Is this for singleton methods on an object? */
45
- else if (BUILTIN_TYPE(attached) == T_OBJECT)
46
- {
47
- /* Make sure to get the super class so that we don't
48
- mistakenly grab a T_ICLASS which would lead to
49
- unknown method errors. */
50
- super = rb_class_superclass(klass);
51
- super_str = rb_class_name(super);
52
- result = rb_str_new2("<Object::");
53
- rb_str_append(result, super_str);
54
- rb_str_cat2(result, ">");
55
- }
56
-
57
- /* Ok, this could be other things like an array made put onto
58
- a singleton object (yeah, it happens, see the singleton
59
- objects test case). */
60
- else
61
- {
62
- result = rb_any_to_s(klass);
63
- }
64
-
65
- return result;
66
- }
67
-
68
- static VALUE
69
- klass_name(VALUE klass)
70
- {
71
- volatile VALUE result = Qnil;
72
-
73
- if (klass == 0 || klass == Qnil)
74
- {
75
- result = rb_str_new2("[global]");
76
- }
77
- else if (BUILTIN_TYPE(klass) == T_MODULE)
78
- {
79
- result = rb_class_name(klass);
80
- }
81
- else if (BUILTIN_TYPE(klass) == T_CLASS && FL_TEST(klass, FL_SINGLETON))
82
- {
83
- result = figure_singleton_name(klass);
84
- }
85
- else if (BUILTIN_TYPE(klass) == T_CLASS)
86
- {
87
- result = rb_class_name(klass);
88
- }
89
- else
90
- {
91
- /* Should never happen. */
92
- result = rb_str_new2("[unknown]");
93
- }
94
-
95
- return result;
96
- }
97
-
98
- static VALUE
99
- method_name(ID mid)
100
- {
101
- volatile VALUE name = Qnil;
102
-
103
- #ifdef ID_ALLOCATOR
104
- if (mid == ID_ALLOCATOR) {
105
- return rb_str_new2("allocate");
106
- }
107
- #endif
108
-
109
- if (RTEST(mid)) {
110
- name = rb_id2str(mid);
111
- return rb_str_dup(name);
112
- } else {
113
- return rb_str_new2("[no method]");
114
- }
115
- }
116
-
117
- static VALUE
118
- full_name(VALUE klass, ID mid)
119
- {
120
- volatile VALUE klass_str, method_str;
121
- volatile VALUE result = Qnil;
122
-
123
- klass_str = klass_name(klass);
124
- method_str = method_name(mid);
125
-
126
- result = rb_str_dup(klass_str);
127
- rb_str_cat2(result, "#");
128
- rb_str_append(result, method_str);
129
-
130
- return result;
131
- }
132
-
133
- static VALUE
134
- source_klass_name(VALUE source_klass)
135
- {
136
- volatile VALUE klass_str;
137
- volatile VALUE result = Qnil;
138
-
139
- if (RTEST(source_klass)) {
140
- klass_str = rb_class_name(source_klass);
141
- result = rb_str_dup(klass_str);
142
- } else {
143
- result = rb_str_new2("[global]");
144
- }
145
-
146
- return result;
147
- }
148
-
149
- static VALUE
150
- calltree_name(VALUE source_klass, int relation, ID mid)
151
- {
152
- volatile VALUE klass_str, klass_path, joiner;
153
- volatile VALUE method_str;
154
- volatile VALUE result = Qnil;
155
-
156
- klass_str = source_klass_name(source_klass);
157
- method_str = method_name(mid);
158
-
159
- klass_path = rb_str_split(klass_str, "::");
160
- joiner = rb_str_new2("/");
161
- result = rb_ary_join(klass_path, joiner);
162
-
163
- rb_str_cat2(result, "::");
164
-
165
- if (RP_REL_GET(relation, kObjectSingleton)) {
166
- rb_str_cat2(result, "*");
167
- }
168
-
169
- if (RP_REL_GET(relation, kModuleSingleton)) {
170
- rb_str_cat2(result, "^");
171
- }
172
-
173
- rb_str_append(result, method_str);
174
-
175
- return result;
176
- }
177
-
178
- void
179
- method_key(prof_method_key_t* key, VALUE klass, ID mid)
180
- {
181
- /* Is this an include for a module? If so get the actual
182
- module class since we want to combine all profiling
183
- results for that module. */
184
- if (klass != 0 && BUILTIN_TYPE(klass) == T_ICLASS) {
185
- klass = RBASIC(klass)->klass;
186
- }
187
-
188
- key->klass = klass;
189
- key->mid = mid;
190
- key->key = (klass << 4) + (mid << 2);
191
- }
192
-
193
- /* ================ prof_method_t =================*/
194
-
195
- prof_method_t*
196
- prof_method_create(VALUE klass, ID mid, const char* source_file, int line)
197
- {
198
- prof_method_t *result = ALLOC(prof_method_t);
199
-
200
- result->key = ALLOC(prof_method_key_t);
201
- method_key(result->key, klass, mid);
202
-
203
- result->excluded = 0;
204
- result->recursive = 0;
205
-
206
- result->call_infos = prof_call_infos_create();
207
- result->visits = 0;
208
-
209
- result->object = Qnil;
210
-
211
- if (source_file != NULL)
212
- {
213
- size_t len = strlen(source_file) + 1;
214
- char *buffer = ALLOC_N(char, len);
215
-
216
- MEMCPY(buffer, source_file, char, len);
217
- result->source_file = buffer;
218
- } else {
219
- result->source_file = source_file;
220
- }
221
-
222
- result->source_klass = Qnil;
223
- result->line = line;
224
-
225
- result->resolved = 0;
226
- result->relation = 0;
227
-
228
- return result;
229
- }
230
-
231
- prof_method_t*
232
- prof_method_create_excluded(VALUE klass, ID mid)
233
- {
234
- prof_method_t *result = ALLOC(prof_method_t);
235
-
236
- result->key = ALLOC(prof_method_key_t);
237
- method_key(result->key, klass, mid);
238
-
239
- /* Invisible with this flag set. */
240
- result->excluded = 1;
241
- result->recursive = 0;
242
-
243
- result->call_infos = 0;
244
- result->visits = 0;
245
-
246
- result->object = Qnil;
247
- result->source_klass = Qnil;
248
- result->line = 0;
249
-
250
- result->resolved = 0;
251
- result->relation = 0;
252
-
253
- return result;
254
- }
255
-
256
- /* The underlying c structures are freed when the parent profile is freed.
257
- However, on shutdown the Ruby GC frees objects in any will-nilly order.
258
- That means the ruby thread object wrapping the c thread struct may
259
- be freed before the parent profile. Thus we add in a free function
260
- for the garbage collector so that if it does get called will nil
261
- out our Ruby object reference.*/
262
- static void
263
- prof_method_ruby_gc_free(prof_method_t* method)
264
- {
265
- /* Has this thread object been accessed by Ruby? If
266
- yes clean it up so to avoid a segmentation fault. */
267
- if (method->object != Qnil)
268
- {
269
- RDATA(method->object)->data = NULL;
270
- RDATA(method->object)->dfree = NULL;
271
- RDATA(method->object)->dmark = NULL;
272
- }
273
- method->object = Qnil;
274
- }
275
-
276
- static void
277
- prof_method_free(prof_method_t* method)
278
- {
279
- prof_method_ruby_gc_free(method);
280
-
281
- if (method->call_infos) {
282
- prof_call_infos_free(method->call_infos);
283
- xfree(method->call_infos);
284
- }
285
-
286
- xfree(method->key);
287
-
288
- method->key = NULL;
289
- method->source_klass = Qnil;
290
-
291
- xfree(method);
292
- }
293
-
294
- void
295
- prof_method_mark(prof_method_t *method)
296
- {
297
- if (method->key->klass) {
298
- rb_gc_mark(method->key->klass);
299
- }
300
-
301
- if (method->source_klass) {
302
- rb_gc_mark(method->source_klass);
303
- }
304
-
305
- if (method->object) {
306
- rb_gc_mark(method->object);
307
- }
308
-
309
- if (method->call_infos) {
310
- prof_call_infos_mark(method->call_infos);
311
- }
312
- }
313
-
314
- static VALUE
315
- resolve_source_klass(prof_method_t* method)
316
- {
317
- volatile VALUE klass, next_klass;
318
- volatile VALUE attached;
319
- unsigned int relation;
320
-
321
- /* We want to group methods according to their source-level
322
- definitions, not their implementation class. Follow module
323
- inclusions and singleton classes back to a meaningful root
324
- while keeping track of these relationships. */
325
-
326
- if (method->resolved) {
327
- return method->source_klass;
328
- }
329
-
330
- klass = method->key->klass;
331
- relation = 0;
332
-
333
- while (1)
334
- {
335
- /* This is a global/unknown class */
336
- if (klass == 0 || klass == Qnil)
337
- break;
338
-
339
- /* Is this a singleton class? (most common case) */
340
- if (BUILTIN_TYPE(klass) == T_CLASS && FL_TEST(klass, FL_SINGLETON))
341
- {
342
- /* We have come across a singleton object. First
343
- figure out what it is attached to.*/
344
- attached = rb_iv_get(klass, "__attached__");
345
-
346
- /* Is this a singleton class acting as a metaclass?
347
- Or for singleton methods on a module? */
348
- if (BUILTIN_TYPE(attached) == T_CLASS ||
349
- BUILTIN_TYPE(attached) == T_MODULE)
350
- {
351
- RP_REL_SET(relation, kModuleSingleton);
352
- klass = attached;
353
- }
354
- /* Is this for singleton methods on an object? */
355
- else if (BUILTIN_TYPE(attached) == T_OBJECT)
356
- {
357
- RP_REL_SET(relation, kObjectSingleton);
358
- next_klass = rb_class_superclass(klass);
359
- klass = next_klass;
360
- }
361
- /* This is a singleton of an instance of a builtin type. */
362
- else
363
- {
364
- RP_REL_SET(relation, kObjectSingleton);
365
- next_klass = rb_class_superclass(klass);
366
- klass = next_klass;
367
- }
368
- }
369
- /* Is this an include for a module? If so get the actual
370
- module class since we want to combine all profiling
371
- results for that module. */
372
- else if (BUILTIN_TYPE(klass) == T_ICLASS)
373
- {
374
- RP_REL_SET(relation, kModuleIncludee);
375
- next_klass = RBASIC(klass)->klass;
376
- klass = next_klass;
377
- }
378
- /* No transformations apply; so bail. */
379
- else
380
- {
381
- break;
382
- }
383
- }
384
-
385
- method->resolved = 1;
386
- method->relation = relation;
387
- method->source_klass = klass;
388
-
389
- return klass;
390
- }
391
-
392
- VALUE
393
- prof_method_wrap(prof_method_t *result)
394
- {
395
- if (result->object == Qnil) {
396
- result->object = Data_Wrap_Struct(cMethodInfo, prof_method_mark, prof_method_ruby_gc_free, result);
397
- }
398
- return result->object;
399
- }
400
-
401
- static prof_method_t *
402
- get_prof_method(VALUE self)
403
- {
404
- /* Can't use Data_Get_Struct because that triggers the event hook
405
- ending up in endless recursion. */
406
- prof_method_t* result = DATA_PTR(self);
407
-
408
- if (!result) {
409
- rb_raise(rb_eRuntimeError, "This RubyProf::MethodInfo instance has already been freed, likely because its profile has been freed.");
410
- }
411
-
412
- return result;
413
- }
414
-
415
- /* ================ Method Table =================*/
416
- int
417
- method_table_cmp(prof_method_key_t *key1, prof_method_key_t *key2)
418
- {
419
- return (key1->klass != key2->klass) || (key1->mid != key2->mid);
420
- }
421
-
422
- st_index_t
423
- method_table_hash(prof_method_key_t *key)
424
- {
425
- return key->key;
426
- }
427
-
428
- struct st_hash_type type_method_hash = {
429
- method_table_cmp,
430
- method_table_hash
431
- };
432
-
433
- st_table *
434
- method_table_create()
435
- {
436
- return st_init_table(&type_method_hash);
437
- }
438
-
439
- static int
440
- method_table_free_iterator(st_data_t key, st_data_t value, st_data_t dummy)
441
- {
442
- prof_method_free((prof_method_t *)value);
443
- return ST_CONTINUE;
444
- }
445
-
446
- void
447
- method_table_free(st_table *table)
448
- {
449
- st_foreach(table, method_table_free_iterator, 0);
450
- st_free_table(table);
451
- }
452
-
453
- size_t
454
- method_table_insert(st_table *table, const prof_method_key_t *key, prof_method_t *val)
455
- {
456
- return st_insert(table, (st_data_t) key, (st_data_t) val);
457
- }
458
-
459
- prof_method_t *
460
- method_table_lookup(st_table *table, const prof_method_key_t* key)
461
- {
462
- st_data_t val;
463
- if (st_lookup(table, (st_data_t)key, &val)) {
464
- return (prof_method_t *) val;
465
- } else {
466
- return NULL;
467
- }
468
- }
469
-
470
- /* ================ Method Info =================*/
471
- /* Document-class: RubyProf::MethodInfo
472
- The RubyProf::MethodInfo class stores profiling data for a method.
473
- One instance of the RubyProf::MethodInfo class is created per method
474
- called per thread. Thus, if a method is called in two different
475
- thread then there will be two RubyProf::MethodInfo objects
476
- created. RubyProf::MethodInfo objects can be accessed via
477
- the RubyProf::Profile object.
478
- */
479
-
480
- /* call-seq:
481
- line_no -> int
482
-
483
- returns the line number of the method */
484
- static VALUE
485
- prof_method_line(VALUE self)
486
- {
487
- int line = get_prof_method(self)->line;
488
- return rb_int_new(line);
489
- }
490
-
491
- /* call-seq:
492
- source_file => string
493
-
494
- return the source file of the method
495
- */
496
- static VALUE prof_method_source_file(VALUE self)
497
- {
498
- const char* sf = get_prof_method(self)->source_file;
499
- if(!sf) {
500
- return rb_str_new2("ruby_runtime");
501
- } else {
502
- return rb_str_new2(sf);
503
- }
504
- }
505
-
506
-
507
- /* call-seq:
508
- method_class -> klass
509
-
510
- Returns the Ruby klass that owns this method. */
511
- static VALUE
512
- prof_method_klass(VALUE self)
513
- {
514
- prof_method_t *result = get_prof_method(self);
515
- return result->key->klass;
516
- }
517
-
518
- /* call-seq:
519
- method_id -> ID
520
-
521
- Returns the id of this method. */
522
- static VALUE
523
- prof_method_id(VALUE self)
524
- {
525
- prof_method_t *result = get_prof_method(self);
526
- return ID2SYM(result->key->mid);
527
- }
528
-
529
- /* call-seq:
530
- klass_name -> string
531
-
532
- Returns the name of this method's class. Singleton classes
533
- will have the form <Object::Object>. */
534
-
535
- static VALUE
536
- prof_klass_name(VALUE self)
537
- {
538
- prof_method_t *method = get_prof_method(self);
539
- return klass_name(method->key->klass);
540
- }
541
-
542
- /* call-seq:
543
- method_name -> string
544
-
545
- Returns the name of this method in the format Object#method. Singletons
546
- methods will be returned in the format <Object::Object>#method.*/
547
-
548
- static VALUE
549
- prof_method_name(VALUE self)
550
- {
551
- prof_method_t *method = get_prof_method(self);
552
- return method_name(method->key->mid);
553
- }
554
-
555
- /* call-seq:
556
- full_name -> string
557
-
558
- Returns the full name of this method in the format Object#method.*/
559
-
560
- static VALUE
561
- prof_full_name(VALUE self)
562
- {
563
- prof_method_t *method = get_prof_method(self);
564
- return full_name(method->key->klass, method->key->mid);
565
- }
566
-
567
- /* call-seq:
568
- call_infos -> Array of call_info
569
-
570
- Returns an array of call info objects that contain profiling information
571
- about the current method.*/
572
- static VALUE
573
- prof_method_call_infos(VALUE self)
574
- {
575
- prof_method_t *method = get_prof_method(self);
576
- if (method->call_infos->object == Qnil) {
577
- method->call_infos->object = prof_call_infos_wrap(method->call_infos);
578
- }
579
- return method->call_infos->object;
580
- }
581
-
582
- /* call-seq:
583
- recursive? -> boolean
584
-
585
- Returns the true if this method is recursive */
586
- static VALUE
587
- prof_method_recursive(VALUE self)
588
- {
589
- prof_method_t *method = get_prof_method(self);
590
- return method->recursive ? Qtrue : Qfalse;
591
- }
592
-
593
- /* call-seq:
594
- source_klass -> klass
595
-
596
- Returns the Ruby klass of the natural source-level definition. */
597
- static VALUE
598
- prof_source_klass(VALUE self)
599
- {
600
- prof_method_t *method = get_prof_method(self);
601
- return resolve_source_klass(method);
602
- }
603
-
604
- /* call-seq:
605
- calltree_name -> string
606
-
607
- Returns the full name of this method in the calltree format.*/
608
-
609
- static VALUE
610
- prof_calltree_name(VALUE self)
611
- {
612
- prof_method_t *method = get_prof_method(self);
613
- volatile VALUE source_klass = resolve_source_klass(method);
614
- return calltree_name(source_klass, method->relation, method->key->mid);
615
- }
616
-
617
- void rp_init_method_info()
618
- {
619
- /* MethodInfo */
620
- cMethodInfo = rb_define_class_under(mProf, "MethodInfo", rb_cObject);
621
- rb_undef_method(CLASS_OF(cMethodInfo), "new");
622
-
623
- rb_define_method(cMethodInfo, "klass", prof_method_klass, 0);
624
- rb_define_method(cMethodInfo, "klass_name", prof_klass_name, 0);
625
- rb_define_method(cMethodInfo, "method_name", prof_method_name, 0);
626
- rb_define_method(cMethodInfo, "full_name", prof_full_name, 0);
627
- rb_define_method(cMethodInfo, "method_id", prof_method_id, 0);
628
-
629
- rb_define_method(cMethodInfo, "call_infos", prof_method_call_infos, 0);
630
- rb_define_method(cMethodInfo, "source_klass", prof_source_klass, 0);
631
- rb_define_method(cMethodInfo, "source_file", prof_method_source_file, 0);
632
- rb_define_method(cMethodInfo, "line", prof_method_line, 0);
633
-
634
- rb_define_method(cMethodInfo, "recursive?", prof_method_recursive, 0);
635
- rb_define_method(cMethodInfo, "calltree_name", prof_calltree_name, 0);
636
- }
1
+ /* Copyright (C) 2005-2019 Shugo Maeda <shugo@ruby-lang.org> and Charlie Savage <cfis@savagexi.com>
2
+ Please see the LICENSE file for copyright and distribution information */
3
+
4
+ #include "ruby_prof.h"
5
+
6
+ #define RP_REL_GET(r, off) ((r) & (1 << (off)))
7
+ #define RP_REL_SET(r, off) \
8
+ do { \
9
+ r |= (1 << (off)); \
10
+ } while (0)
11
+
12
+ VALUE cMethodInfo;
13
+
14
+ /* ================ Helper Functions =================*/
15
+ static VALUE
16
+ figure_singleton_name(VALUE klass)
17
+ {
18
+ volatile VALUE attached, super;
19
+ volatile VALUE attached_str, super_str;
20
+ volatile VALUE result = Qnil;
21
+
22
+ /* We have come across a singleton object. First
23
+ figure out what it is attached to.*/
24
+ attached = rb_iv_get(klass, "__attached__");
25
+
26
+ /* Is this a singleton class acting as a metaclass? */
27
+ if (BUILTIN_TYPE(attached) == T_CLASS)
28
+ {
29
+ attached_str = rb_class_name(attached);
30
+ result = rb_str_new2("<Class::");
31
+ rb_str_append(result, attached_str);
32
+ rb_str_cat2(result, ">");
33
+ }
34
+
35
+ /* Is this for singleton methods on a module? */
36
+ else if (BUILTIN_TYPE(attached) == T_MODULE)
37
+ {
38
+ attached_str = rb_class_name(attached);
39
+ result = rb_str_new2("<Module::");
40
+ rb_str_append(result, attached_str);
41
+ rb_str_cat2(result, ">");
42
+ }
43
+
44
+ /* Is this for singleton methods on an object? */
45
+ else if (BUILTIN_TYPE(attached) == T_OBJECT)
46
+ {
47
+ /* Make sure to get the super class so that we don't
48
+ mistakenly grab a T_ICLASS which would lead to
49
+ unknown method errors. */
50
+ super = rb_class_superclass(klass);
51
+ super_str = rb_class_name(super);
52
+ result = rb_str_new2("<Object::");
53
+ rb_str_append(result, super_str);
54
+ rb_str_cat2(result, ">");
55
+ }
56
+
57
+ /* Ok, this could be other things like an array made put onto
58
+ a singleton object (yeah, it happens, see the singleton
59
+ objects test case). */
60
+ else
61
+ {
62
+ result = rb_any_to_s(klass);
63
+ }
64
+
65
+ return result;
66
+ }
67
+
68
+ static VALUE
69
+ klass_name(VALUE klass)
70
+ {
71
+ volatile VALUE result = Qnil;
72
+
73
+ if (klass == 0 || klass == Qnil)
74
+ {
75
+ result = rb_str_new2("[global]");
76
+ }
77
+ else if (BUILTIN_TYPE(klass) == T_MODULE)
78
+ {
79
+ result = rb_class_name(klass);
80
+ }
81
+ else if (BUILTIN_TYPE(klass) == T_CLASS && FL_TEST(klass, FL_SINGLETON))
82
+ {
83
+ result = figure_singleton_name(klass);
84
+ }
85
+ else if (BUILTIN_TYPE(klass) == T_CLASS)
86
+ {
87
+ result = rb_class_name(klass);
88
+ }
89
+ else
90
+ {
91
+ /* Should never happen. */
92
+ result = rb_str_new2("[unknown]");
93
+ }
94
+
95
+ return result;
96
+ }
97
+
98
+ static VALUE
99
+ method_name(ID mid)
100
+ {
101
+ volatile VALUE name = Qnil;
102
+
103
+ if (RTEST(mid)) {
104
+ name = rb_id2str(mid);
105
+ return rb_str_dup(name);
106
+ } else {
107
+ return rb_str_new2("[no method]");
108
+ }
109
+ }
110
+
111
+ static VALUE
112
+ full_name(VALUE klass, ID mid)
113
+ {
114
+ volatile VALUE klass_str, method_str;
115
+ volatile VALUE result = Qnil;
116
+
117
+ klass_str = klass_name(klass);
118
+ method_str = method_name(mid);
119
+
120
+ result = rb_str_dup(klass_str);
121
+ rb_str_cat2(result, "#");
122
+ rb_str_append(result, method_str);
123
+
124
+ return result;
125
+ }
126
+
127
+ static VALUE
128
+ source_klass_name(VALUE source_klass)
129
+ {
130
+ volatile VALUE klass_str;
131
+ volatile VALUE result = Qnil;
132
+
133
+ if (RTEST(source_klass)) {
134
+ klass_str = rb_class_name(source_klass);
135
+ result = rb_str_dup(klass_str);
136
+ } else {
137
+ result = rb_str_new2("[global]");
138
+ }
139
+
140
+ return result;
141
+ }
142
+
143
+ static VALUE
144
+ calltree_name(VALUE source_klass, int relation, ID mid)
145
+ {
146
+ volatile VALUE klass_str, klass_path, joiner;
147
+ volatile VALUE method_str;
148
+ volatile VALUE result = Qnil;
149
+
150
+ klass_str = source_klass_name(source_klass);
151
+ method_str = method_name(mid);
152
+
153
+ klass_path = rb_str_split(klass_str, "::");
154
+ joiner = rb_str_new2("/");
155
+ result = rb_ary_join(klass_path, joiner);
156
+
157
+ rb_str_cat2(result, "::");
158
+
159
+ if (RP_REL_GET(relation, kObjectSingleton)) {
160
+ rb_str_cat2(result, "*");
161
+ }
162
+
163
+ if (RP_REL_GET(relation, kModuleSingleton)) {
164
+ rb_str_cat2(result, "^");
165
+ }
166
+
167
+ rb_str_append(result, method_str);
168
+
169
+ return result;
170
+ }
171
+
172
+ void
173
+ method_key(prof_method_key_t* key, VALUE klass, ID mid)
174
+ {
175
+ /* Is this an include for a module? If so get the actual
176
+ module class since we want to combine all profiling
177
+ results for that module. */
178
+ if (klass != 0 && BUILTIN_TYPE(klass) == T_ICLASS) {
179
+ klass = RBASIC(klass)->klass;
180
+ }
181
+
182
+ key->klass = klass;
183
+ key->mid = mid;
184
+ key->key = (klass << 4) + (mid << 2);
185
+ }
186
+
187
+ /* ================ prof_method_t =================*/
188
+
189
+ prof_method_t*
190
+ prof_method_create(VALUE klass, ID mid, const char* source_file, int line)
191
+ {
192
+ prof_method_t *result = ALLOC(prof_method_t);
193
+
194
+ result->key = ALLOC(prof_method_key_t);
195
+ method_key(result->key, klass, mid);
196
+
197
+ result->excluded = 0;
198
+ result->recursive = 0;
199
+
200
+ result->call_infos = prof_call_infos_create();
201
+ result->visits = 0;
202
+
203
+ result->object = Qnil;
204
+
205
+ if (source_file != NULL)
206
+ {
207
+ size_t len = strlen(source_file) + 1;
208
+ char *buffer = ALLOC_N(char, len);
209
+
210
+ MEMCPY(buffer, source_file, char, len);
211
+ result->source_file = buffer;
212
+ } else {
213
+ result->source_file = source_file;
214
+ }
215
+
216
+ result->source_klass = Qnil;
217
+ result->line = line;
218
+
219
+ result->resolved = 0;
220
+ result->relation = 0;
221
+
222
+ return result;
223
+ }
224
+
225
+ prof_method_t*
226
+ prof_method_create_excluded(VALUE klass, ID mid)
227
+ {
228
+ prof_method_t *result = ALLOC(prof_method_t);
229
+
230
+ result->key = ALLOC(prof_method_key_t);
231
+ method_key(result->key, klass, mid);
232
+
233
+ /* Invisible with this flag set. */
234
+ result->excluded = 1;
235
+ result->recursive = 0;
236
+
237
+ result->call_infos = 0;
238
+ result->visits = 0;
239
+
240
+ result->object = Qnil;
241
+ result->source_klass = Qnil;
242
+ result->line = 0;
243
+
244
+ result->resolved = 0;
245
+ result->relation = 0;
246
+
247
+ return result;
248
+ }
249
+
250
+ /* The underlying c structures are freed when the parent profile is freed.
251
+ However, on shutdown the Ruby GC frees objects in any will-nilly order.
252
+ That means the ruby thread object wrapping the c thread struct may
253
+ be freed before the parent profile. Thus we add in a free function
254
+ for the garbage collector so that if it does get called will nil
255
+ out our Ruby object reference.*/
256
+ static void
257
+ prof_method_ruby_gc_free(prof_method_t* method)
258
+ {
259
+ /* Has this thread object been accessed by Ruby? If
260
+ yes clean it up so to avoid a segmentation fault. */
261
+ if (method->object != Qnil)
262
+ {
263
+ RDATA(method->object)->data = NULL;
264
+ RDATA(method->object)->dfree = NULL;
265
+ RDATA(method->object)->dmark = NULL;
266
+ }
267
+ method->object = Qnil;
268
+ }
269
+
270
+ static void
271
+ prof_method_free(prof_method_t* method)
272
+ {
273
+ prof_method_ruby_gc_free(method);
274
+
275
+ if (method->call_infos) {
276
+ prof_call_infos_free(method->call_infos);
277
+ xfree(method->call_infos);
278
+ }
279
+
280
+ xfree(method->key);
281
+
282
+ method->key = NULL;
283
+ method->source_klass = Qnil;
284
+
285
+ xfree(method);
286
+ }
287
+
288
+ void
289
+ prof_method_mark(prof_method_t *method)
290
+ {
291
+ if (method->key->klass) {
292
+ rb_gc_mark(method->key->klass);
293
+ }
294
+
295
+ if (method->source_klass) {
296
+ rb_gc_mark(method->source_klass);
297
+ }
298
+
299
+ if (method->object) {
300
+ rb_gc_mark(method->object);
301
+ }
302
+
303
+ if (method->call_infos) {
304
+ prof_call_infos_mark(method->call_infos);
305
+ }
306
+ }
307
+
308
+ static VALUE
309
+ resolve_source_klass(prof_method_t* method)
310
+ {
311
+ volatile VALUE klass, next_klass;
312
+ volatile VALUE attached;
313
+ unsigned int relation;
314
+
315
+ /* We want to group methods according to their source-level
316
+ definitions, not their implementation class. Follow module
317
+ inclusions and singleton classes back to a meaningful root
318
+ while keeping track of these relationships. */
319
+
320
+ if (method->resolved) {
321
+ return method->source_klass;
322
+ }
323
+
324
+ klass = method->key->klass;
325
+ relation = 0;
326
+
327
+ while (1)
328
+ {
329
+ /* This is a global/unknown class */
330
+ if (klass == 0 || klass == Qnil)
331
+ break;
332
+
333
+ /* Is this a singleton class? (most common case) */
334
+ if (BUILTIN_TYPE(klass) == T_CLASS && FL_TEST(klass, FL_SINGLETON))
335
+ {
336
+ /* We have come across a singleton object. First
337
+ figure out what it is attached to.*/
338
+ attached = rb_iv_get(klass, "__attached__");
339
+
340
+ /* Is this a singleton class acting as a metaclass?
341
+ Or for singleton methods on a module? */
342
+ if (BUILTIN_TYPE(attached) == T_CLASS ||
343
+ BUILTIN_TYPE(attached) == T_MODULE)
344
+ {
345
+ RP_REL_SET(relation, kModuleSingleton);
346
+ klass = attached;
347
+ }
348
+ /* Is this for singleton methods on an object? */
349
+ else if (BUILTIN_TYPE(attached) == T_OBJECT)
350
+ {
351
+ RP_REL_SET(relation, kObjectSingleton);
352
+ next_klass = rb_class_superclass(klass);
353
+ klass = next_klass;
354
+ }
355
+ /* This is a singleton of an instance of a builtin type. */
356
+ else
357
+ {
358
+ RP_REL_SET(relation, kObjectSingleton);
359
+ next_klass = rb_class_superclass(klass);
360
+ klass = next_klass;
361
+ }
362
+ }
363
+ /* Is this an include for a module? If so get the actual
364
+ module class since we want to combine all profiling
365
+ results for that module. */
366
+ else if (BUILTIN_TYPE(klass) == T_ICLASS)
367
+ {
368
+ RP_REL_SET(relation, kModuleIncludee);
369
+ next_klass = RBASIC(klass)->klass;
370
+ klass = next_klass;
371
+ }
372
+ /* No transformations apply; so bail. */
373
+ else
374
+ {
375
+ break;
376
+ }
377
+ }
378
+
379
+ method->resolved = 1;
380
+ method->relation = relation;
381
+ method->source_klass = klass;
382
+
383
+ return klass;
384
+ }
385
+
386
+ VALUE
387
+ prof_method_wrap(prof_method_t *result)
388
+ {
389
+ if (result->object == Qnil) {
390
+ result->object = Data_Wrap_Struct(cMethodInfo, prof_method_mark, prof_method_ruby_gc_free, result);
391
+ }
392
+ return result->object;
393
+ }
394
+
395
+ static prof_method_t *
396
+ get_prof_method(VALUE self)
397
+ {
398
+ /* Can't use Data_Get_Struct because that triggers the event hook
399
+ ending up in endless recursion. */
400
+ prof_method_t* result = DATA_PTR(self);
401
+
402
+ if (!result) {
403
+ rb_raise(rb_eRuntimeError, "This RubyProf::MethodInfo instance has already been freed, likely because its profile has been freed.");
404
+ }
405
+
406
+ return result;
407
+ }
408
+
409
+ /* ================ Method Table =================*/
410
+ int
411
+ method_table_cmp(prof_method_key_t *key1, prof_method_key_t *key2)
412
+ {
413
+ return (key1->klass != key2->klass) || (key1->mid != key2->mid);
414
+ }
415
+
416
+ st_index_t
417
+ method_table_hash(prof_method_key_t *key)
418
+ {
419
+ return key->key;
420
+ }
421
+
422
+ struct st_hash_type type_method_hash = {
423
+ method_table_cmp,
424
+ method_table_hash
425
+ };
426
+
427
+ st_table *
428
+ method_table_create()
429
+ {
430
+ return st_init_table(&type_method_hash);
431
+ }
432
+
433
+ static int
434
+ method_table_free_iterator(st_data_t key, st_data_t value, st_data_t dummy)
435
+ {
436
+ prof_method_free((prof_method_t *)value);
437
+ return ST_CONTINUE;
438
+ }
439
+
440
+ void
441
+ method_table_free(st_table *table)
442
+ {
443
+ st_foreach(table, method_table_free_iterator, 0);
444
+ st_free_table(table);
445
+ }
446
+
447
+ size_t
448
+ method_table_insert(st_table *table, const prof_method_key_t *key, prof_method_t *val)
449
+ {
450
+ return st_insert(table, (st_data_t) key, (st_data_t) val);
451
+ }
452
+
453
+ prof_method_t *
454
+ method_table_lookup(st_table *table, const prof_method_key_t* key)
455
+ {
456
+ st_data_t val;
457
+ if (st_lookup(table, (st_data_t)key, &val)) {
458
+ return (prof_method_t *) val;
459
+ } else {
460
+ return NULL;
461
+ }
462
+ }
463
+
464
+ /* ================ Method Info =================*/
465
+ /* Document-class: RubyProf::MethodInfo
466
+ The RubyProf::MethodInfo class stores profiling data for a method.
467
+ One instance of the RubyProf::MethodInfo class is created per method
468
+ called per thread. Thus, if a method is called in two different
469
+ thread then there will be two RubyProf::MethodInfo objects
470
+ created. RubyProf::MethodInfo objects can be accessed via
471
+ the RubyProf::Profile object.
472
+ */
473
+
474
+ /* call-seq:
475
+ line_no -> int
476
+
477
+ returns the line number of the method */
478
+ static VALUE
479
+ prof_method_line(VALUE self)
480
+ {
481
+ int line = get_prof_method(self)->line;
482
+ return rb_int_new(line);
483
+ }
484
+
485
+ /* call-seq:
486
+ source_file => string
487
+
488
+ return the source file of the method
489
+ */
490
+ static VALUE prof_method_source_file(VALUE self)
491
+ {
492
+ const char* sf = get_prof_method(self)->source_file;
493
+ if(!sf) {
494
+ return rb_str_new2("ruby_runtime");
495
+ } else {
496
+ return rb_str_new2(sf);
497
+ }
498
+ }
499
+
500
+
501
+ /* call-seq:
502
+ method_class -> klass
503
+
504
+ Returns the Ruby klass that owns this method. */
505
+ static VALUE
506
+ prof_method_klass(VALUE self)
507
+ {
508
+ prof_method_t *result = get_prof_method(self);
509
+ return result->key->klass;
510
+ }
511
+
512
+ /* call-seq:
513
+ method_id -> ID
514
+
515
+ Returns the id of this method. */
516
+ static VALUE
517
+ prof_method_id(VALUE self)
518
+ {
519
+ prof_method_t *result = get_prof_method(self);
520
+ return ID2SYM(result->key->mid);
521
+ }
522
+
523
+ /* call-seq:
524
+ klass_name -> string
525
+
526
+ Returns the name of this method's class. Singleton classes
527
+ will have the form <Object::Object>. */
528
+
529
+ static VALUE
530
+ prof_klass_name(VALUE self)
531
+ {
532
+ prof_method_t *method = get_prof_method(self);
533
+ return klass_name(method->key->klass);
534
+ }
535
+
536
+ /* call-seq:
537
+ method_name -> string
538
+
539
+ Returns the name of this method in the format Object#method. Singletons
540
+ methods will be returned in the format <Object::Object>#method.*/
541
+
542
+ static VALUE
543
+ prof_method_name(VALUE self)
544
+ {
545
+ prof_method_t *method = get_prof_method(self);
546
+ return method_name(method->key->mid);
547
+ }
548
+
549
+ /* call-seq:
550
+ full_name -> string
551
+
552
+ Returns the full name of this method in the format Object#method.*/
553
+
554
+ static VALUE
555
+ prof_full_name(VALUE self)
556
+ {
557
+ prof_method_t *method = get_prof_method(self);
558
+ return full_name(method->key->klass, method->key->mid);
559
+ }
560
+
561
+ /* call-seq:
562
+ call_infos -> Array of call_info
563
+
564
+ Returns an array of call info objects that contain profiling information
565
+ about the current method.*/
566
+ static VALUE
567
+ prof_method_call_infos(VALUE self)
568
+ {
569
+ prof_method_t *method = get_prof_method(self);
570
+ if (method->call_infos->object == Qnil) {
571
+ method->call_infos->object = prof_call_infos_wrap(method->call_infos);
572
+ }
573
+ return method->call_infos->object;
574
+ }
575
+
576
+ /* call-seq:
577
+ recursive? -> boolean
578
+
579
+ Returns the true if this method is recursive */
580
+ static VALUE
581
+ prof_method_recursive(VALUE self)
582
+ {
583
+ prof_method_t *method = get_prof_method(self);
584
+ return method->recursive ? Qtrue : Qfalse;
585
+ }
586
+
587
+ /* call-seq:
588
+ source_klass -> klass
589
+
590
+ Returns the Ruby klass of the natural source-level definition. */
591
+ static VALUE
592
+ prof_source_klass(VALUE self)
593
+ {
594
+ prof_method_t *method = get_prof_method(self);
595
+ return resolve_source_klass(method);
596
+ }
597
+
598
+ /* call-seq:
599
+ calltree_name -> string
600
+
601
+ Returns the full name of this method in the calltree format.*/
602
+
603
+ static VALUE
604
+ prof_calltree_name(VALUE self)
605
+ {
606
+ prof_method_t *method = get_prof_method(self);
607
+ volatile VALUE source_klass = resolve_source_klass(method);
608
+ return calltree_name(source_klass, method->relation, method->key->mid);
609
+ }
610
+
611
+ void rp_init_method_info()
612
+ {
613
+ /* MethodInfo */
614
+ cMethodInfo = rb_define_class_under(mProf, "MethodInfo", rb_cObject);
615
+ rb_undef_method(CLASS_OF(cMethodInfo), "new");
616
+
617
+ rb_define_method(cMethodInfo, "klass", prof_method_klass, 0);
618
+ rb_define_method(cMethodInfo, "klass_name", prof_klass_name, 0);
619
+ rb_define_method(cMethodInfo, "method_name", prof_method_name, 0);
620
+ rb_define_method(cMethodInfo, "full_name", prof_full_name, 0);
621
+ rb_define_method(cMethodInfo, "method_id", prof_method_id, 0);
622
+
623
+ rb_define_method(cMethodInfo, "call_infos", prof_method_call_infos, 0);
624
+ rb_define_method(cMethodInfo, "source_klass", prof_source_klass, 0);
625
+ rb_define_method(cMethodInfo, "source_file", prof_method_source_file, 0);
626
+ rb_define_method(cMethodInfo, "line", prof_method_line, 0);
627
+
628
+ rb_define_method(cMethodInfo, "recursive?", prof_method_recursive, 0);
629
+ rb_define_method(cMethodInfo, "calltree_name", prof_calltree_name, 0);
630
+ }