ruby-prof 0.13.1 → 1.4.2

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 (209) hide show
  1. checksums.yaml +5 -5
  2. data/CHANGES +579 -371
  3. data/LICENSE +24 -23
  4. data/README.rdoc +5 -433
  5. data/Rakefile +98 -110
  6. data/bin/ruby-prof +328 -329
  7. data/bin/ruby-prof-check-trace +45 -0
  8. data/ext/ruby_prof/extconf.rb +16 -59
  9. data/ext/ruby_prof/rp_aggregate_call_tree.c +59 -0
  10. data/ext/ruby_prof/rp_aggregate_call_tree.h +13 -0
  11. data/ext/ruby_prof/rp_allocation.c +287 -0
  12. data/ext/ruby_prof/rp_allocation.h +31 -0
  13. data/ext/ruby_prof/rp_call_tree.c +369 -0
  14. data/ext/ruby_prof/rp_call_tree.h +43 -0
  15. data/ext/ruby_prof/rp_call_trees.c +288 -0
  16. data/ext/ruby_prof/rp_call_trees.h +28 -0
  17. data/ext/ruby_prof/rp_measure_allocations.c +50 -65
  18. data/ext/ruby_prof/rp_measure_memory.c +42 -73
  19. data/ext/ruby_prof/rp_measure_process_time.c +65 -71
  20. data/ext/ruby_prof/rp_measure_wall_time.c +64 -42
  21. data/ext/ruby_prof/rp_measurement.c +237 -0
  22. data/ext/ruby_prof/rp_measurement.h +50 -0
  23. data/ext/ruby_prof/rp_method.c +491 -420
  24. data/ext/ruby_prof/rp_method.h +62 -57
  25. data/ext/ruby_prof/rp_profile.c +908 -0
  26. data/ext/ruby_prof/rp_profile.h +35 -0
  27. data/ext/ruby_prof/rp_stack.c +212 -128
  28. data/ext/ruby_prof/rp_stack.h +53 -51
  29. data/ext/ruby_prof/rp_thread.c +362 -268
  30. data/ext/ruby_prof/rp_thread.h +39 -27
  31. data/ext/ruby_prof/ruby_prof.c +52 -695
  32. data/ext/ruby_prof/ruby_prof.h +26 -55
  33. data/ext/ruby_prof/vc/ruby_prof.sln +28 -21
  34. data/ext/ruby_prof/vc/{ruby_prof_20.vcxproj → ruby_prof.vcxproj} +56 -8
  35. data/lib/ruby-prof.rb +52 -67
  36. data/lib/ruby-prof/assets/call_stack_printer.html.erb +710 -0
  37. data/lib/ruby-prof/assets/call_stack_printer.png +0 -0
  38. data/lib/ruby-prof/assets/graph_printer.html.erb +355 -0
  39. data/lib/ruby-prof/call_tree.rb +57 -0
  40. data/lib/ruby-prof/call_tree_visitor.rb +36 -0
  41. data/lib/ruby-prof/compatibility.rb +99 -169
  42. data/lib/ruby-prof/exclude_common_methods.rb +198 -0
  43. data/lib/ruby-prof/measurement.rb +17 -0
  44. data/lib/ruby-prof/method_info.rb +78 -131
  45. data/lib/ruby-prof/printers/abstract_printer.rb +137 -85
  46. data/lib/ruby-prof/printers/call_info_printer.rb +53 -41
  47. data/lib/ruby-prof/printers/call_stack_printer.rb +180 -773
  48. data/lib/ruby-prof/printers/call_tree_printer.rb +151 -92
  49. data/lib/ruby-prof/printers/dot_printer.rb +132 -132
  50. data/lib/ruby-prof/printers/flat_printer.rb +53 -69
  51. data/lib/ruby-prof/printers/graph_html_printer.rb +63 -255
  52. data/lib/ruby-prof/printers/graph_printer.rb +113 -116
  53. data/lib/ruby-prof/printers/multi_printer.rb +127 -56
  54. data/lib/ruby-prof/profile.rb +37 -77
  55. data/lib/ruby-prof/rack.rb +62 -15
  56. data/lib/ruby-prof/task.rb +147 -147
  57. data/lib/ruby-prof/thread.rb +10 -12
  58. data/lib/ruby-prof/version.rb +3 -0
  59. data/lib/unprof.rb +10 -10
  60. data/ruby-prof.gemspec +65 -61
  61. data/test/abstract_printer_test.rb +26 -0
  62. data/test/alias_test.rb +126 -0
  63. data/test/basic_test.rb +43 -128
  64. data/test/call_tree_visitor_test.rb +32 -0
  65. data/test/call_trees_test.rb +66 -0
  66. data/test/duplicate_names_test.rb +32 -32
  67. data/test/dynamic_method_test.rb +53 -74
  68. data/test/enumerable_test.rb +21 -16
  69. data/test/exceptions_test.rb +24 -16
  70. data/test/exclude_methods_test.rb +151 -0
  71. data/test/exclude_threads_test.rb +53 -54
  72. data/test/fiber_test.rb +129 -65
  73. data/test/gc_test.rb +90 -0
  74. data/test/inverse_call_tree_test.rb +175 -0
  75. data/test/line_number_test.rb +158 -71
  76. data/test/marshal_test.rb +113 -0
  77. data/test/measure_allocations.rb +30 -0
  78. data/test/measure_allocations_test.rb +375 -25
  79. data/test/measure_allocations_trace_test.rb +375 -0
  80. data/test/measure_memory_trace_test.rb +1101 -0
  81. data/test/measure_process_time_test.rb +785 -62
  82. data/test/measure_times.rb +56 -0
  83. data/test/measure_wall_time_test.rb +434 -254
  84. data/test/multi_printer_test.rb +71 -82
  85. data/test/no_method_class_test.rb +15 -15
  86. data/test/pause_resume_test.rb +175 -166
  87. data/test/prime.rb +54 -54
  88. data/test/prime_script.rb +6 -0
  89. data/test/printer_call_stack_test.rb +27 -0
  90. data/test/printer_call_tree_test.rb +30 -0
  91. data/test/printer_flat_test.rb +99 -0
  92. data/test/printer_graph_html_test.rb +59 -0
  93. data/test/printer_graph_test.rb +40 -0
  94. data/test/printers_test.rb +141 -257
  95. data/test/printing_recursive_graph_test.rb +81 -0
  96. data/test/profile_test.rb +16 -0
  97. data/test/rack_test.rb +93 -0
  98. data/test/recursive_test.rb +206 -215
  99. data/test/singleton_test.rb +38 -38
  100. data/test/stack_printer_test.rb +64 -78
  101. data/test/start_stop_test.rb +109 -112
  102. data/test/test_helper.rb +13 -115
  103. data/test/thread_test.rb +144 -178
  104. data/test/unique_call_path_test.rb +120 -224
  105. data/test/yarv_test.rb +56 -0
  106. metadata +77 -133
  107. data/doc/LICENSE.html +0 -155
  108. data/doc/README_rdoc.html +0 -648
  109. data/doc/Rack.html +0 -167
  110. data/doc/Rack/RubyProf.html +0 -319
  111. data/doc/RubyProf.html +0 -1000
  112. data/doc/RubyProf/AbstractPrinter.html +0 -580
  113. data/doc/RubyProf/AggregateCallInfo.html +0 -570
  114. data/doc/RubyProf/CallInfo.html +0 -512
  115. data/doc/RubyProf/CallInfoPrinter.html +0 -190
  116. data/doc/RubyProf/CallInfoVisitor.html +0 -332
  117. data/doc/RubyProf/CallStackPrinter.html +0 -1600
  118. data/doc/RubyProf/CallTreePrinter.html +0 -413
  119. data/doc/RubyProf/Cmd.html +0 -669
  120. data/doc/RubyProf/DotPrinter.html +0 -312
  121. data/doc/RubyProf/FlatPrinter.html +0 -229
  122. data/doc/RubyProf/FlatPrinterWithLineNumbers.html +0 -267
  123. data/doc/RubyProf/GraphHtmlPrinter.html +0 -630
  124. data/doc/RubyProf/GraphPrinter.html +0 -209
  125. data/doc/RubyProf/MethodInfo.html +0 -713
  126. data/doc/RubyProf/MultiPrinter.html +0 -407
  127. data/doc/RubyProf/Profile.html +0 -821
  128. data/doc/RubyProf/ProfileTask.html +0 -532
  129. data/doc/RubyProf/Test.html +0 -578
  130. data/doc/RubyProf/Thread.html +0 -262
  131. data/doc/created.rid +0 -32
  132. data/doc/examples/flat_txt.html +0 -191
  133. data/doc/examples/graph_txt.html +0 -305
  134. data/doc/images/add.png +0 -0
  135. data/doc/images/brick.png +0 -0
  136. data/doc/images/brick_link.png +0 -0
  137. data/doc/images/bug.png +0 -0
  138. data/doc/images/bullet_black.png +0 -0
  139. data/doc/images/bullet_toggle_minus.png +0 -0
  140. data/doc/images/bullet_toggle_plus.png +0 -0
  141. data/doc/images/date.png +0 -0
  142. data/doc/images/delete.png +0 -0
  143. data/doc/images/find.png +0 -0
  144. data/doc/images/loadingAnimation.gif +0 -0
  145. data/doc/images/macFFBgHack.png +0 -0
  146. data/doc/images/package.png +0 -0
  147. data/doc/images/page_green.png +0 -0
  148. data/doc/images/page_white_text.png +0 -0
  149. data/doc/images/page_white_width.png +0 -0
  150. data/doc/images/plugin.png +0 -0
  151. data/doc/images/ruby.png +0 -0
  152. data/doc/images/tag_blue.png +0 -0
  153. data/doc/images/tag_green.png +0 -0
  154. data/doc/images/transparent.png +0 -0
  155. data/doc/images/wrench.png +0 -0
  156. data/doc/images/wrench_orange.png +0 -0
  157. data/doc/images/zoom.png +0 -0
  158. data/doc/index.html +0 -647
  159. data/doc/js/darkfish.js +0 -155
  160. data/doc/js/jquery.js +0 -18
  161. data/doc/js/navigation.js +0 -142
  162. data/doc/js/search.js +0 -94
  163. data/doc/js/search_index.js +0 -1
  164. data/doc/js/searcher.js +0 -228
  165. data/doc/rdoc.css +0 -543
  166. data/doc/table_of_contents.html +0 -462
  167. data/examples/empty.png +0 -0
  168. data/examples/flat.txt +0 -55
  169. data/examples/graph.dot +0 -106
  170. data/examples/graph.html +0 -823
  171. data/examples/graph.png +0 -0
  172. data/examples/graph.txt +0 -170
  173. data/examples/minus.png +0 -0
  174. data/examples/multi.flat.txt +0 -23
  175. data/examples/multi.graph.html +0 -906
  176. data/examples/multi.grind.dat +0 -194
  177. data/examples/multi.stack.html +0 -573
  178. data/examples/plus.png +0 -0
  179. data/examples/stack.html +0 -573
  180. data/ext/ruby_prof/rp_call_info.c +0 -407
  181. data/ext/ruby_prof/rp_call_info.h +0 -48
  182. data/ext/ruby_prof/rp_measure.c +0 -48
  183. data/ext/ruby_prof/rp_measure.h +0 -45
  184. data/ext/ruby_prof/rp_measure_cpu_time.c +0 -112
  185. data/ext/ruby_prof/rp_measure_gc_runs.c +0 -65
  186. data/ext/ruby_prof/rp_measure_gc_time.c +0 -57
  187. data/ext/ruby_prof/vc/ruby_prof_18.vcxproj +0 -108
  188. data/ext/ruby_prof/vc/ruby_prof_19.vcxproj +0 -110
  189. data/ext/ruby_prof/version.h +0 -7
  190. data/lib/ruby-prof/aggregate_call_info.rb +0 -72
  191. data/lib/ruby-prof/call_info.rb +0 -89
  192. data/lib/ruby-prof/call_info_visitor.rb +0 -44
  193. data/lib/ruby-prof/images/empty.png +0 -0
  194. data/lib/ruby-prof/images/minus.png +0 -0
  195. data/lib/ruby-prof/images/plus.png +0 -0
  196. data/lib/ruby-prof/printers/flat_printer_with_line_numbers.rb +0 -57
  197. data/lib/ruby-prof/test.rb +0 -150
  198. data/test/aggregate_test.rb +0 -136
  199. data/test/call_info_test.rb +0 -78
  200. data/test/call_info_visitor_test.rb +0 -31
  201. data/test/exec_test.rb +0 -14
  202. data/test/measure_cpu_time_test.rb +0 -220
  203. data/test/measure_gc_runs_test.rb +0 -32
  204. data/test/measure_gc_time_test.rb +0 -36
  205. data/test/measure_memory_test.rb +0 -31
  206. data/test/method_elimination_test.rb +0 -84
  207. data/test/module_test.rb +0 -45
  208. data/test/stack_test.rb +0 -138
  209. data/test/test_suite.rb +0 -37
@@ -0,0 +1,237 @@
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 "rp_measurement.h"
5
+
6
+ VALUE mMeasure;
7
+ VALUE cRpMeasurement;
8
+
9
+ prof_measurer_t* prof_measurer_allocations(bool track_allocations);
10
+ prof_measurer_t* prof_measurer_memory(bool track_allocations);
11
+ prof_measurer_t* prof_measurer_process_time(bool track_allocations);
12
+ prof_measurer_t* prof_measurer_wall_time(bool track_allocations);
13
+
14
+ void rp_init_measure_allocations(void);
15
+ void rp_init_measure_memory(void);
16
+ void rp_init_measure_process_time(void);
17
+ void rp_init_measure_wall_time(void);
18
+
19
+ prof_measurer_t* prof_get_measurer(prof_measure_mode_t measure, bool track_allocations)
20
+ {
21
+ switch (measure)
22
+ {
23
+ case MEASURE_WALL_TIME:
24
+ return prof_measurer_wall_time(track_allocations);
25
+ case MEASURE_PROCESS_TIME:
26
+ return prof_measurer_process_time(track_allocations);
27
+ case MEASURE_ALLOCATIONS:
28
+ return prof_measurer_allocations(track_allocations);
29
+ case MEASURE_MEMORY:
30
+ return prof_measurer_memory(track_allocations);
31
+ default:
32
+ rb_raise(rb_eArgError, "Unknown measure mode: %d", measure);
33
+ }
34
+ };
35
+
36
+ double prof_measure(prof_measurer_t* measurer, rb_trace_arg_t* trace_arg)
37
+ {
38
+ double measurement = measurer->measure(trace_arg);
39
+ return measurement * measurer->multiplier;
40
+ }
41
+
42
+ /* ======= prof_measurement_t ========*/
43
+ prof_measurement_t* prof_measurement_create(void)
44
+ {
45
+ prof_measurement_t* result = ALLOC(prof_measurement_t);
46
+ result->total_time = 0;
47
+ result->self_time = 0;
48
+ result->wait_time = 0;
49
+ result->called = 0;
50
+ result->object = Qnil;
51
+ return result;
52
+ }
53
+
54
+ void prof_measurement_mark(void* data)
55
+ {
56
+ if (!data) return;
57
+
58
+ prof_measurement_t* measurement_data = (prof_measurement_t*)data;
59
+
60
+ if (measurement_data->object != Qnil)
61
+ rb_gc_mark(measurement_data->object);
62
+ }
63
+
64
+ static void prof_measurement_ruby_gc_free(void* data)
65
+ {
66
+ if (data)
67
+ {
68
+ // Measurements are freed by their owning object (call info or method)
69
+ prof_measurement_t* measurement = (prof_measurement_t*)data;
70
+ measurement->object = Qnil;
71
+ }
72
+ }
73
+
74
+ void prof_measurement_free(prof_measurement_t* measurement)
75
+ {
76
+ /* Has this measurement object been accessed by Ruby? If
77
+ yes clean it up so to avoid a segmentation fault. */
78
+ if (measurement->object != Qnil)
79
+ {
80
+ RTYPEDDATA(measurement->object)->data = NULL;
81
+ measurement->object = Qnil;
82
+ }
83
+
84
+ xfree(measurement);
85
+ }
86
+
87
+ size_t prof_measurement_size(const void* data)
88
+ {
89
+ return sizeof(prof_measurement_t);
90
+ }
91
+
92
+ static const rb_data_type_t measurement_type =
93
+ {
94
+ .wrap_struct_name = "Measurement",
95
+ .function =
96
+ {
97
+ .dmark = prof_measurement_mark,
98
+ .dfree = prof_measurement_ruby_gc_free,
99
+ .dsize = prof_measurement_size,
100
+ },
101
+ .data = NULL,
102
+ .flags = RUBY_TYPED_FREE_IMMEDIATELY
103
+ };
104
+
105
+ VALUE prof_measurement_wrap(prof_measurement_t* measurement)
106
+ {
107
+ if (measurement->object == Qnil)
108
+ {
109
+ measurement->object = TypedData_Wrap_Struct(cRpMeasurement, &measurement_type, measurement);
110
+ }
111
+ return measurement->object;
112
+ }
113
+
114
+ static VALUE prof_measurement_allocate(VALUE klass)
115
+ {
116
+ prof_measurement_t* measurement = prof_measurement_create();
117
+ measurement->object = prof_measurement_wrap(measurement);
118
+ return measurement->object;
119
+ }
120
+
121
+ prof_measurement_t* prof_get_measurement(VALUE self)
122
+ {
123
+ /* Can't use Data_Get_Struct because that triggers the event hook
124
+ ending up in endless recursion. */
125
+ prof_measurement_t* result = RTYPEDDATA_DATA(self);
126
+
127
+ if (!result)
128
+ rb_raise(rb_eRuntimeError, "This RubyProf::Measurement instance has already been freed, likely because its profile has been freed.");
129
+
130
+ return result;
131
+ }
132
+
133
+ /* call-seq:
134
+ total_time -> float
135
+
136
+ Returns the total amount of time spent in this method and its children. */
137
+ static VALUE prof_measurement_total_time(VALUE self)
138
+ {
139
+ prof_measurement_t* result = prof_get_measurement(self);
140
+ return rb_float_new(result->total_time);
141
+ }
142
+
143
+ /* call-seq:
144
+ self_time -> float
145
+
146
+ Returns the total amount of time spent in this method. */
147
+ static VALUE
148
+ prof_measurement_self_time(VALUE self)
149
+ {
150
+ prof_measurement_t* result = prof_get_measurement(self);
151
+
152
+ return rb_float_new(result->self_time);
153
+ }
154
+
155
+ /* call-seq:
156
+ wait_time -> float
157
+
158
+ Returns the total amount of time this method waited for other threads. */
159
+ static VALUE prof_measurement_wait_time(VALUE self)
160
+ {
161
+ prof_measurement_t* result = prof_get_measurement(self);
162
+
163
+ return rb_float_new(result->wait_time);
164
+ }
165
+
166
+ /* call-seq:
167
+ called -> int
168
+
169
+ Returns the total amount of times this method was called. */
170
+ static VALUE prof_measurement_called(VALUE self)
171
+ {
172
+ prof_measurement_t* result = prof_get_measurement(self);
173
+ return INT2NUM(result->called);
174
+ }
175
+
176
+ /* call-seq:
177
+ called=n -> n
178
+
179
+ Sets the call count to n. */
180
+ static VALUE prof_measurement_set_called(VALUE self, VALUE called)
181
+ {
182
+ prof_measurement_t* result = prof_get_measurement(self);
183
+ result->called = NUM2INT(called);
184
+ return called;
185
+ }
186
+
187
+ /* :nodoc: */
188
+ static VALUE
189
+ prof_measurement_dump(VALUE self)
190
+ {
191
+ prof_measurement_t* measurement_data = prof_get_measurement(self);
192
+ VALUE result = rb_hash_new();
193
+
194
+ rb_hash_aset(result, ID2SYM(rb_intern("total_time")), rb_float_new(measurement_data->total_time));
195
+ rb_hash_aset(result, ID2SYM(rb_intern("self_time")), rb_float_new(measurement_data->self_time));
196
+ rb_hash_aset(result, ID2SYM(rb_intern("wait_time")), rb_float_new(measurement_data->wait_time));
197
+ rb_hash_aset(result, ID2SYM(rb_intern("called")), INT2FIX(measurement_data->called));
198
+
199
+ return result;
200
+ }
201
+
202
+ /* :nodoc: */
203
+ static VALUE
204
+ prof_measurement_load(VALUE self, VALUE data)
205
+ {
206
+ prof_measurement_t* measurement = prof_get_measurement(self);
207
+ measurement->object = self;
208
+
209
+ measurement->total_time = rb_num2dbl(rb_hash_aref(data, ID2SYM(rb_intern("total_time"))));
210
+ measurement->self_time = rb_num2dbl(rb_hash_aref(data, ID2SYM(rb_intern("self_time"))));
211
+ measurement->wait_time = rb_num2dbl(rb_hash_aref(data, ID2SYM(rb_intern("wait_time"))));
212
+ measurement->called = FIX2INT(rb_hash_aref(data, ID2SYM(rb_intern("called"))));
213
+
214
+ return data;
215
+ }
216
+
217
+ void rp_init_measure()
218
+ {
219
+ mMeasure = rb_define_module_under(mProf, "Measure");
220
+ rp_init_measure_wall_time();
221
+ rp_init_measure_process_time();
222
+ rp_init_measure_allocations();
223
+ rp_init_measure_memory();
224
+
225
+ cRpMeasurement = rb_define_class_under(mProf, "Measurement", rb_cObject);
226
+ rb_undef_method(CLASS_OF(cRpMeasurement), "new");
227
+ rb_define_alloc_func(cRpMeasurement, prof_measurement_allocate);
228
+
229
+ rb_define_method(cRpMeasurement, "called", prof_measurement_called, 0);
230
+ rb_define_method(cRpMeasurement, "called=", prof_measurement_set_called, 1);
231
+ rb_define_method(cRpMeasurement, "total_time", prof_measurement_total_time, 0);
232
+ rb_define_method(cRpMeasurement, "self_time", prof_measurement_self_time, 0);
233
+ rb_define_method(cRpMeasurement, "wait_time", prof_measurement_wait_time, 0);
234
+
235
+ rb_define_method(cRpMeasurement, "_dump_data", prof_measurement_dump, 0);
236
+ rb_define_method(cRpMeasurement, "_load_data", prof_measurement_load, 1);
237
+ }
@@ -0,0 +1,50 @@
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
+ #ifndef __rp_measurementMENT_H__
5
+ #define __rp_measurementMENT_H__
6
+
7
+ #include "ruby_prof.h"
8
+
9
+ extern VALUE mMeasure;
10
+
11
+ typedef double (*get_measurement)(rb_trace_arg_t* trace_arg);
12
+
13
+ typedef enum
14
+ {
15
+ MEASURE_WALL_TIME,
16
+ MEASURE_PROCESS_TIME,
17
+ MEASURE_ALLOCATIONS,
18
+ MEASURE_MEMORY
19
+ } prof_measure_mode_t;
20
+
21
+ typedef struct prof_measurer_t
22
+ {
23
+ get_measurement measure;
24
+ prof_measure_mode_t mode;
25
+ double multiplier;
26
+ bool track_allocations;
27
+ } prof_measurer_t;
28
+
29
+ /* Callers and callee information for a method. */
30
+ typedef struct prof_measurement_t
31
+ {
32
+ double total_time;
33
+ double self_time;
34
+ double wait_time;
35
+ int called;
36
+ VALUE object;
37
+ } prof_measurement_t;
38
+
39
+ prof_measurer_t* prof_get_measurer(prof_measure_mode_t measure, bool track_allocations);
40
+ double prof_measure(prof_measurer_t* measurer, rb_trace_arg_t* trace_arg);
41
+
42
+ prof_measurement_t* prof_measurement_create(void);
43
+ void prof_measurement_free(prof_measurement_t* measurement);
44
+ VALUE prof_measurement_wrap(prof_measurement_t* measurement);
45
+ prof_measurement_t* prof_get_measurement(VALUE self);
46
+ void prof_measurement_mark(void* data);
47
+
48
+ void rp_init_measure(void);
49
+
50
+ #endif //__rp_measurementMENT_H__
@@ -1,420 +1,491 @@
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
- VALUE cMethodInfo;
7
-
8
- /* ================ Helper Functions =================*/
9
- static VALUE
10
- figure_singleton_name(VALUE klass)
11
- {
12
- VALUE result = Qnil;
13
-
14
- /* We have come across a singleton object. First
15
- figure out what it is attached to.*/
16
- VALUE attached = rb_iv_get(klass, "__attached__");
17
-
18
- /* Is this a singleton class acting as a metaclass? */
19
- if (BUILTIN_TYPE(attached) == T_CLASS)
20
- {
21
- result = rb_str_new2("<Class::");
22
- rb_str_append(result, rb_inspect(attached));
23
- rb_str_cat2(result, ">");
24
- }
25
-
26
- /* Is this for singleton methods on a module? */
27
- else if (BUILTIN_TYPE(attached) == T_MODULE)
28
- {
29
- result = rb_str_new2("<Module::");
30
- rb_str_append(result, rb_inspect(attached));
31
- rb_str_cat2(result, ">");
32
- }
33
-
34
- /* Is this for singleton methods on an object? */
35
- else if (BUILTIN_TYPE(attached) == T_OBJECT)
36
- {
37
- /* Make sure to get the super class so that we don't
38
- mistakenly grab a T_ICLASS which would lead to
39
- unknown method errors. */
40
- #ifdef HAVE_RB_CLASS_SUPERCLASS
41
- // 1.9.3
42
- VALUE super = rb_class_superclass(klass);
43
- #else
44
- # ifdef RCLASS_SUPER
45
- VALUE super = rb_class_real(RCLASS_SUPER(klass));
46
- # else
47
- VALUE super = rb_class_real(RCLASS(klass)->super);
48
- # endif
49
- #endif
50
- result = rb_str_new2("<Object::");
51
- rb_str_append(result, rb_inspect(super));
52
- rb_str_cat2(result, ">");
53
- }
54
-
55
- /* Ok, this could be other things like an array made put onto
56
- a singleton object (yeah, it happens, see the singleton
57
- objects test case). */
58
- else
59
- {
60
- result = rb_inspect(klass);
61
- }
62
-
63
- return result;
64
- }
65
-
66
- static VALUE
67
- klass_name(VALUE klass)
68
- {
69
- VALUE result = Qnil;
70
-
71
- if (klass == 0 || klass == Qnil)
72
- {
73
- result = rb_str_new2("Global");
74
- }
75
- else if (BUILTIN_TYPE(klass) == T_MODULE)
76
- {
77
- result = rb_inspect(klass);
78
- }
79
- else if (BUILTIN_TYPE(klass) == T_CLASS && FL_TEST(klass, FL_SINGLETON))
80
- {
81
- result = figure_singleton_name(klass);
82
- }
83
- else if (BUILTIN_TYPE(klass) == T_CLASS)
84
- {
85
- result = rb_inspect(klass);
86
- }
87
- else
88
- {
89
- /* Should never happen. */
90
- result = rb_str_new2("Unknown");
91
- }
92
-
93
- return result;
94
- }
95
-
96
- static VALUE
97
- method_name(ID mid)
98
- {
99
- VALUE result;
100
-
101
- if (mid == 0)
102
- result = rb_str_new2("[No method]");
103
- #ifdef ID_ALLOCATOR
104
- else if (mid == ID_ALLOCATOR)
105
- result = rb_str_new2("allocate");
106
- #endif
107
- else
108
- result = rb_String(ID2SYM(mid));
109
-
110
- return result;
111
- }
112
-
113
- static VALUE
114
- full_name(VALUE klass, ID mid)
115
- {
116
- VALUE result = klass_name(klass);
117
- rb_str_cat2(result, "#");
118
- rb_str_append(result, method_name(mid));
119
-
120
- return result;
121
- }
122
-
123
- void
124
- method_key(prof_method_key_t* key, VALUE klass, ID mid)
125
- {
126
- /* Is this an include for a module? If so get the actual
127
- module class since we want to combine all profiling
128
- results for that module. */
129
- if (klass != 0)
130
- klass = (BUILTIN_TYPE(klass) == T_ICLASS ? RBASIC(klass)->klass : klass);
131
-
132
- key->klass = klass;
133
- key->mid = mid;
134
- key->key = (klass << 4) + (mid << 2);
135
- }
136
-
137
- /* ================ prof_method_t =================*/
138
- prof_method_t*
139
- prof_method_create(VALUE klass, ID mid, const char* source_file, int line)
140
- {
141
- prof_method_t *result = ALLOC(prof_method_t);
142
- result->object = Qnil;
143
- result->call_infos = prof_call_infos_create();
144
-
145
- result->key = ALLOC(prof_method_key_t);
146
- method_key(result->key, klass, mid);
147
-
148
- //result->call_info_table = call_info_table_create();
149
-
150
- if (source_file != NULL)
151
- {
152
- size_t len = strlen(source_file) + 1;
153
- char *buffer = ALLOC_N(char, len);
154
-
155
- MEMCPY(buffer, source_file, char, len);
156
- result->source_file = buffer;
157
- }
158
- else
159
- {
160
- result->source_file = source_file;
161
- }
162
- result->line = line;
163
-
164
- return result;
165
- }
166
-
167
- /* The underlying c structures are freed when the parent profile is freed.
168
- However, on shutdown the Ruby GC frees objects in any will-nilly order.
169
- That means the ruby thread object wrapping the c thread struct may
170
- be freed before the parent profile. Thus we add in a free function
171
- for the garbage collector so that if it does get called will nil
172
- out our Ruby object reference.*/
173
- static void
174
- prof_method_ruby_gc_free(prof_method_t* method)
175
- {
176
- /* Has this thread object been accessed by Ruby? If
177
- yes clean it up so to avoid a segmentation fault. */
178
- if (method->object != Qnil)
179
- {
180
- RDATA(method->object)->data = NULL;
181
- RDATA(method->object)->dfree = NULL;
182
- RDATA(method->object)->dmark = NULL;
183
- }
184
- method->object = Qnil;
185
- }
186
-
187
- static void
188
- prof_method_free(prof_method_t* method)
189
- {
190
- prof_method_ruby_gc_free(method);
191
- prof_call_infos_free(method->call_infos);
192
- xfree(method->call_infos);
193
-
194
- xfree(method->key);
195
- method->key = NULL;
196
-
197
- xfree(method);
198
- }
199
-
200
- void
201
- prof_method_mark(prof_method_t *method)
202
- {
203
- if (method->object)
204
- rb_gc_mark(method->object);
205
-
206
- prof_call_infos_mark(method->call_infos);
207
- }
208
-
209
- VALUE
210
- prof_method_wrap(prof_method_t *result)
211
- {
212
- if (result->object == Qnil)
213
- {
214
- result->object = Data_Wrap_Struct(cMethodInfo, prof_method_mark, prof_method_ruby_gc_free, result);
215
- }
216
- return result->object;
217
- }
218
-
219
- static prof_method_t *
220
- get_prof_method(VALUE self)
221
- {
222
- /* Can't use Data_Get_Struct because that triggers the event hook
223
- ending up in endless recursion. */
224
- prof_method_t* result = DATA_PTR(self);
225
-
226
- if (!result)
227
- rb_raise(rb_eRuntimeError, "This RubyProf::MethodInfo instance has already been freed, likely because its profile has been freed.");
228
-
229
- return result;
230
- }
231
-
232
- /* ================ Method Table =================*/
233
- int
234
- method_table_cmp(prof_method_key_t *key1, prof_method_key_t *key2)
235
- {
236
- return (key1->klass != key2->klass) || (key1->mid != key2->mid);
237
- }
238
-
239
- st_index_t
240
- method_table_hash(prof_method_key_t *key)
241
- {
242
- return key->key;
243
- }
244
-
245
- struct st_hash_type type_method_hash = {
246
- method_table_cmp,
247
- method_table_hash
248
- };
249
-
250
- st_table *
251
- method_table_create()
252
- {
253
- return st_init_table(&type_method_hash);
254
- }
255
-
256
- static int
257
- method_table_free_iterator(st_data_t key, st_data_t value, st_data_t dummy)
258
- {
259
- prof_method_free((prof_method_t*)value);
260
- return ST_CONTINUE;
261
- }
262
-
263
- void
264
- method_table_free(st_table *table)
265
- {
266
- st_foreach(table, method_table_free_iterator, 0);
267
- st_free_table(table);
268
- }
269
-
270
-
271
- size_t
272
- method_table_insert(st_table *table, const prof_method_key_t *key, prof_method_t *val)
273
- {
274
- return st_insert(table, (st_data_t) key, (st_data_t) val);
275
- }
276
-
277
- prof_method_t *
278
- method_table_lookup(st_table *table, const prof_method_key_t* key)
279
- {
280
- st_data_t val;
281
- if (st_lookup(table, (st_data_t)key, &val))
282
- {
283
- return (prof_method_t *) val;
284
- }
285
- else
286
- {
287
- return NULL;
288
- }
289
- }
290
-
291
- /* ================ Method Info =================*/
292
- /* Document-class: RubyProf::MethodInfo
293
- The RubyProf::MethodInfo class stores profiling data for a method.
294
- One instance of the RubyProf::MethodInfo class is created per method
295
- called per thread. Thus, if a method is called in two different
296
- thread then there will be two RubyProf::MethodInfo objects
297
- created. RubyProf::MethodInfo objects can be accessed via
298
- the RubyProf::Result object.
299
- */
300
-
301
- /* call-seq:
302
- line_no -> int
303
-
304
- returns the line number of the method */
305
- static VALUE
306
- prof_method_line(VALUE self)
307
- {
308
- return rb_int_new(get_prof_method(self)->line);
309
- }
310
-
311
- /* call-seq:
312
- source_file => string
313
-
314
- return the source file of the method
315
- */
316
- static VALUE prof_method_source_file(VALUE self)
317
- {
318
- const char* sf = get_prof_method(self)->source_file;
319
- if(!sf)
320
- {
321
- return rb_str_new2("ruby_runtime");
322
- }
323
- else
324
- {
325
- return rb_str_new2(sf);
326
- }
327
- }
328
-
329
-
330
- /* call-seq:
331
- method_class -> klass
332
-
333
- Returns the Ruby klass that owns this method. */
334
- static VALUE
335
- prof_method_klass(VALUE self)
336
- {
337
- prof_method_t *result = get_prof_method(self);
338
- return result->key->klass;
339
- }
340
-
341
- /* call-seq:
342
- method_id -> ID
343
-
344
- Returns the id of this method. */
345
- static VALUE
346
- prof_method_id(VALUE self)
347
- {
348
- prof_method_t *result = get_prof_method(self);
349
- return ID2SYM(result->key->mid);
350
- }
351
-
352
- /* call-seq:
353
- klass_name -> string
354
-
355
- Returns the name of this method's class. Singleton classes
356
- will have the form <Object::Object>. */
357
-
358
- static VALUE
359
- prof_klass_name(VALUE self)
360
- {
361
- prof_method_t *method = get_prof_method(self);
362
- return klass_name(method->key->klass);
363
- }
364
-
365
- /* call-seq:
366
- method_name -> string
367
-
368
- Returns the name of this method in the format Object#method. Singletons
369
- methods will be returned in the format <Object::Object>#method.*/
370
-
371
- static VALUE
372
- prof_method_name(VALUE self)
373
- {
374
- prof_method_t *method = get_prof_method(self);
375
- return method_name(method->key->mid);
376
- }
377
-
378
- /* call-seq:
379
- full_name -> string
380
-
381
- Returns the full name of this method in the format Object#method.*/
382
-
383
- static VALUE
384
- prof_full_name(VALUE self)
385
- {
386
- prof_method_t *method = get_prof_method(self);
387
- return full_name(method->key->klass, method->key->mid);
388
- }
389
-
390
- /* call-seq:
391
- call_infos -> Array of call_info
392
-
393
- Returns an array of call info objects that contain profiling information
394
- about the current method.*/
395
- static VALUE
396
- prof_method_call_infos(VALUE self)
397
- {
398
- prof_method_t *method = get_prof_method(self);
399
- if (method->call_infos->object == Qnil)
400
- {
401
- method->call_infos->object = prof_call_infos_wrap(method->call_infos);
402
- }
403
- return method->call_infos->object;
404
- }
405
-
406
- void rp_init_method_info()
407
- {
408
- /* MethodInfo */
409
- cMethodInfo = rb_define_class_under(mProf, "MethodInfo", rb_cObject);
410
- rb_undef_method(CLASS_OF(cMethodInfo), "new");
411
-
412
- rb_define_method(cMethodInfo, "klass", prof_method_klass, 0);
413
- rb_define_method(cMethodInfo, "klass_name", prof_klass_name, 0);
414
- rb_define_method(cMethodInfo, "method_name", prof_method_name, 0);
415
- rb_define_method(cMethodInfo, "full_name", prof_full_name, 0);
416
- rb_define_method(cMethodInfo, "method_id", prof_method_id, 0);
417
- rb_define_method(cMethodInfo, "source_file", prof_method_source_file,0);
418
- rb_define_method(cMethodInfo, "line", prof_method_line, 0);
419
- rb_define_method(cMethodInfo, "call_infos", prof_method_call_infos, 0);
420
- }
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 "rp_allocation.h"
5
+ #include "rp_call_trees.h"
6
+ #include "rp_method.h"
7
+
8
+ VALUE cRpMethodInfo;
9
+
10
+ /* ================ Helper Functions =================*/
11
+ VALUE resolve_klass(VALUE klass, unsigned int* klass_flags)
12
+ {
13
+ VALUE result = klass;
14
+
15
+ if (klass == 0 || klass == Qnil)
16
+ {
17
+ result = Qnil;
18
+ }
19
+ else if (BUILTIN_TYPE(klass) == T_CLASS && FL_TEST(klass, FL_SINGLETON))
20
+ {
21
+ /* We have come across a singleton object. First
22
+ figure out what it is attached to.*/
23
+ VALUE attached = rb_iv_get(klass, "__attached__");
24
+
25
+ /* Is this a singleton class acting as a metaclass? */
26
+ if (BUILTIN_TYPE(attached) == T_CLASS)
27
+ {
28
+ *klass_flags |= kClassSingleton;
29
+ result = attached;
30
+ }
31
+ /* Is this for singleton methods on a module? */
32
+ else if (BUILTIN_TYPE(attached) == T_MODULE)
33
+ {
34
+ *klass_flags |= kModuleSingleton;
35
+ result = attached;
36
+ }
37
+ /* Is this for singleton methods on an object? */
38
+ else if (BUILTIN_TYPE(attached) == T_OBJECT)
39
+ {
40
+ *klass_flags |= kObjectSingleton;
41
+ result = rb_class_superclass(klass);
42
+ }
43
+ /* Ok, this could be other things like an array made put onto
44
+ a singleton object (yeah, it happens, see the singleton
45
+ objects test case). */
46
+ else
47
+ {
48
+ *klass_flags |= kOtherSingleton;
49
+ result = klass;
50
+ }
51
+ }
52
+ /* Is this an include for a module? If so get the actual
53
+ module class since we want to combine all profiling
54
+ results for that module. */
55
+ else if (BUILTIN_TYPE(klass) == T_ICLASS)
56
+ {
57
+ unsigned int dummy;
58
+ *klass_flags |= kModuleIncludee;
59
+ result = resolve_klass(RBASIC(klass)->klass, &dummy);
60
+ }
61
+ return result;
62
+ }
63
+
64
+ VALUE resolve_klass_name(VALUE klass, unsigned int* klass_flags)
65
+ {
66
+ VALUE result = Qnil;
67
+
68
+ if (klass == Qnil)
69
+ {
70
+ result = rb_str_new2("[global]");
71
+ }
72
+ else if (*klass_flags & kOtherSingleton)
73
+ {
74
+ result = rb_any_to_s(klass);
75
+ }
76
+ else
77
+ {
78
+ result = rb_class_name(klass);
79
+ }
80
+
81
+ return result;
82
+ }
83
+
84
+ st_data_t method_key(VALUE klass, VALUE msym)
85
+ {
86
+ VALUE resolved_klass = klass;
87
+
88
+ /* Is this an include for a module? If so get the actual
89
+ module class since we want to combine all profiling
90
+ results for that module. */
91
+ if (klass == 0 || klass == Qnil)
92
+ {
93
+ resolved_klass = Qnil;
94
+ }
95
+ else if (BUILTIN_TYPE(klass) == T_ICLASS)
96
+ {
97
+ resolved_klass = RBASIC(klass)->klass;
98
+ }
99
+
100
+ return (resolved_klass << 4) + (msym);
101
+ }
102
+
103
+ /* ====== Allocation Table ====== */
104
+ st_table* allocations_table_create()
105
+ {
106
+ return rb_st_init_numtable();
107
+ }
108
+
109
+ static int allocations_table_free_iterator(st_data_t key, st_data_t value, st_data_t dummy)
110
+ {
111
+ prof_allocation_free((prof_allocation_t*)value);
112
+ return ST_CONTINUE;
113
+ }
114
+
115
+ static int prof_method_collect_allocations(st_data_t key, st_data_t value, st_data_t result)
116
+ {
117
+ prof_allocation_t* allocation = (prof_allocation_t*)value;
118
+ VALUE arr = (VALUE)result;
119
+ rb_ary_push(arr, prof_allocation_wrap(allocation));
120
+ return ST_CONTINUE;
121
+ }
122
+
123
+ static int prof_method_mark_allocations(st_data_t key, st_data_t value, st_data_t data)
124
+ {
125
+ prof_allocation_t* allocation = (prof_allocation_t*)value;
126
+ prof_allocation_mark(allocation);
127
+ return ST_CONTINUE;
128
+ }
129
+
130
+ void allocations_table_free(st_table* table)
131
+ {
132
+ rb_st_foreach(table, allocations_table_free_iterator, 0);
133
+ rb_st_free_table(table);
134
+ }
135
+
136
+ /* ================ prof_method_t =================*/
137
+ prof_method_t* prof_get_method(VALUE self)
138
+ {
139
+ /* Can't use Data_Get_Struct because that triggers the event hook
140
+ ending up in endless recursion. */
141
+ prof_method_t* result = RTYPEDDATA_DATA(self);
142
+
143
+ if (!result)
144
+ rb_raise(rb_eRuntimeError, "This RubyProf::MethodInfo instance has already been freed, likely because its profile has been freed.");
145
+
146
+ return result;
147
+ }
148
+
149
+ prof_method_t* prof_method_create(VALUE profile, VALUE klass, VALUE msym, VALUE source_file, int source_line)
150
+ {
151
+ prof_method_t* result = ALLOC(prof_method_t);
152
+ result->profile = profile;
153
+
154
+ result->key = method_key(klass, msym);
155
+ result->klass_flags = 0;
156
+
157
+ /* Note we do not call resolve_klass_name now because that causes an object allocation that shows up
158
+ in the allocation results so we want to avoid it until after the profile run is complete. */
159
+ result->klass = resolve_klass(klass, &result->klass_flags);
160
+ result->klass_name = Qnil;
161
+ result->method_name = msym;
162
+ result->measurement = prof_measurement_create();
163
+
164
+ result->call_trees = prof_call_trees_create();
165
+ result->allocations_table = allocations_table_create();
166
+
167
+ result->visits = 0;
168
+ result->recursive = false;
169
+
170
+ result->object = Qnil;
171
+
172
+ result->source_file = source_file;
173
+ result->source_line = source_line;
174
+
175
+ return result;
176
+ }
177
+
178
+ /* The underlying c structures are freed when the parent profile is freed.
179
+ However, on shutdown the Ruby GC frees objects in any will-nilly order.
180
+ That means the ruby thread object wrapping the c thread struct may
181
+ be freed before the parent profile. Thus we add in a free function
182
+ for the garbage collector so that if it does get called will nil
183
+ out our Ruby object reference.*/
184
+ static void prof_method_ruby_gc_free(void* data)
185
+ {
186
+ if (data)
187
+ {
188
+ prof_method_t* method = (prof_method_t*)data;
189
+ method->object = Qnil;
190
+ }
191
+ }
192
+
193
+ static void prof_method_free(prof_method_t* method)
194
+ {
195
+ /* Has this method object been accessed by Ruby? If
196
+ yes clean it up so to avoid a segmentation fault. */
197
+ if (method->object != Qnil)
198
+ {
199
+ RTYPEDDATA(method->object)->data = NULL;
200
+ method->object = Qnil;
201
+ }
202
+
203
+ allocations_table_free(method->allocations_table);
204
+ prof_call_trees_free(method->call_trees);
205
+ prof_measurement_free(method->measurement);
206
+ xfree(method);
207
+ }
208
+
209
+ size_t prof_method_size(const void* data)
210
+ {
211
+ return sizeof(prof_method_t);
212
+ }
213
+
214
+ void prof_method_mark(void* data)
215
+ {
216
+ if (!data) return;
217
+
218
+ prof_method_t* method = (prof_method_t*)data;
219
+
220
+ if (method->profile != Qnil)
221
+ rb_gc_mark(method->profile);
222
+
223
+ if (method->object != Qnil)
224
+ rb_gc_mark(method->object);
225
+
226
+ rb_gc_mark(method->klass_name);
227
+ rb_gc_mark(method->method_name);
228
+ rb_gc_mark(method->source_file);
229
+
230
+ if (method->klass != Qnil)
231
+ rb_gc_mark(method->klass);
232
+
233
+ prof_measurement_mark(method->measurement);
234
+
235
+ rb_st_foreach(method->allocations_table, prof_method_mark_allocations, 0);
236
+ }
237
+
238
+ static VALUE prof_method_allocate(VALUE klass)
239
+ {
240
+ prof_method_t* method_data = prof_method_create(Qnil, Qnil, Qnil, Qnil, 0);
241
+ method_data->object = prof_method_wrap(method_data);
242
+ return method_data->object;
243
+ }
244
+
245
+ static const rb_data_type_t method_info_type =
246
+ {
247
+ .wrap_struct_name = "MethodInfo",
248
+ .function =
249
+ {
250
+ .dmark = prof_method_mark,
251
+ .dfree = prof_method_ruby_gc_free,
252
+ .dsize = prof_method_size,
253
+ },
254
+ .data = NULL,
255
+ .flags = RUBY_TYPED_FREE_IMMEDIATELY
256
+ };
257
+
258
+ VALUE prof_method_wrap(prof_method_t* method)
259
+ {
260
+ if (method->object == Qnil)
261
+ {
262
+ method->object = TypedData_Wrap_Struct(cRpMethodInfo, &method_info_type, method);
263
+ }
264
+ return method->object;
265
+ }
266
+
267
+ st_table* method_table_create()
268
+ {
269
+ return rb_st_init_numtable();
270
+ }
271
+
272
+ static int method_table_free_iterator(st_data_t key, st_data_t value, st_data_t dummy)
273
+ {
274
+ prof_method_free((prof_method_t*)value);
275
+ return ST_CONTINUE;
276
+ }
277
+
278
+ void method_table_free(st_table* table)
279
+ {
280
+ rb_st_foreach(table, method_table_free_iterator, 0);
281
+ rb_st_free_table(table);
282
+ }
283
+
284
+ size_t method_table_insert(st_table* table, st_data_t key, prof_method_t* val)
285
+ {
286
+ return rb_st_insert(table, (st_data_t)key, (st_data_t)val);
287
+ }
288
+
289
+ prof_method_t* method_table_lookup(st_table* table, st_data_t key)
290
+ {
291
+ st_data_t val;
292
+ if (rb_st_lookup(table, (st_data_t)key, &val))
293
+ {
294
+ return (prof_method_t*)val;
295
+ }
296
+ else
297
+ {
298
+ return NULL;
299
+ }
300
+ }
301
+
302
+ /* ================ Method Info =================*/
303
+ /* Document-class: RubyProf::MethodInfo
304
+ The RubyProf::MethodInfo class stores profiling data for a method.
305
+ One instance of the RubyProf::MethodInfo class is created per method
306
+ called per thread. Thus, if a method is called in two different
307
+ thread then there will be two RubyProf::MethodInfo objects
308
+ created. RubyProf::MethodInfo objects can be accessed via
309
+ the RubyProf::Profile object.
310
+ */
311
+
312
+ /* call-seq:
313
+ allocations -> array
314
+
315
+ Returns an array of allocation information.*/
316
+ static VALUE prof_method_allocations(VALUE self)
317
+ {
318
+ prof_method_t* method = prof_get_method(self);
319
+ VALUE result = rb_ary_new();
320
+ rb_st_foreach(method->allocations_table, prof_method_collect_allocations, result);
321
+ return result;
322
+ }
323
+
324
+ /* call-seq:
325
+ called -> Measurement
326
+
327
+ Returns the measurement associated with this method. */
328
+ static VALUE prof_method_measurement(VALUE self)
329
+ {
330
+ prof_method_t* method = prof_get_method(self);
331
+ return prof_measurement_wrap(method->measurement);
332
+ }
333
+
334
+ /* call-seq:
335
+ source_file => string
336
+
337
+ return the source file of the method
338
+ */
339
+ static VALUE prof_method_source_file(VALUE self)
340
+ {
341
+ prof_method_t* method = prof_get_method(self);
342
+ return method->source_file;
343
+ }
344
+
345
+ /* call-seq:
346
+ line_no -> int
347
+
348
+ returns the line number of the method */
349
+ static VALUE prof_method_line(VALUE self)
350
+ {
351
+ prof_method_t* method = prof_get_method(self);
352
+ return INT2FIX(method->source_line);
353
+ }
354
+
355
+ /* call-seq:
356
+ klass_name -> string
357
+
358
+ Returns the name of this method's class. Singleton classes
359
+ will have the form <Object::Object>. */
360
+
361
+ static VALUE prof_method_klass_name(VALUE self)
362
+ {
363
+ prof_method_t* method = prof_get_method(self);
364
+ if (method->klass_name == Qnil)
365
+ method->klass_name = resolve_klass_name(method->klass, &method->klass_flags);
366
+
367
+ return method->klass_name;
368
+ }
369
+
370
+ /* call-seq:
371
+ klass_flags -> integer
372
+
373
+ Returns the klass flags */
374
+
375
+ static VALUE prof_method_klass_flags(VALUE self)
376
+ {
377
+ prof_method_t* method = prof_get_method(self);
378
+ return INT2FIX(method->klass_flags);
379
+ }
380
+
381
+ /* call-seq:
382
+ method_name -> string
383
+
384
+ Returns the name of this method in the format Object#method. Singletons
385
+ methods will be returned in the format <Object::Object>#method.*/
386
+
387
+ static VALUE prof_method_name(VALUE self)
388
+ {
389
+ prof_method_t* method = prof_get_method(self);
390
+ return method->method_name;
391
+ }
392
+
393
+ /* call-seq:
394
+ recursive? -> boolean
395
+
396
+ Returns the true if this method is recursively invoked */
397
+ static VALUE prof_method_recursive(VALUE self)
398
+ {
399
+ prof_method_t* method = prof_get_method(self);
400
+ return method->recursive ? Qtrue : Qfalse;
401
+ }
402
+
403
+ /* call-seq:
404
+ call_trees -> CallTrees
405
+
406
+ Returns the CallTrees associated with this method. */
407
+ static VALUE prof_method_call_trees(VALUE self)
408
+ {
409
+ prof_method_t* method = prof_get_method(self);
410
+ return prof_call_trees_wrap(method->call_trees);
411
+ }
412
+
413
+ /* :nodoc: */
414
+ static VALUE prof_method_dump(VALUE self)
415
+ {
416
+ prof_method_t* method_data = prof_get_method(self);
417
+ VALUE result = rb_hash_new();
418
+
419
+ rb_hash_aset(result, ID2SYM(rb_intern("klass_name")), prof_method_klass_name(self));
420
+ rb_hash_aset(result, ID2SYM(rb_intern("klass_flags")), INT2FIX(method_data->klass_flags));
421
+ rb_hash_aset(result, ID2SYM(rb_intern("method_name")), method_data->method_name);
422
+
423
+ rb_hash_aset(result, ID2SYM(rb_intern("key")), INT2FIX(method_data->key));
424
+ rb_hash_aset(result, ID2SYM(rb_intern("recursive")), prof_method_recursive(self));
425
+ rb_hash_aset(result, ID2SYM(rb_intern("source_file")), method_data->source_file);
426
+ rb_hash_aset(result, ID2SYM(rb_intern("source_line")), INT2FIX(method_data->source_line));
427
+
428
+ rb_hash_aset(result, ID2SYM(rb_intern("call_trees")), prof_call_trees_wrap(method_data->call_trees));
429
+ rb_hash_aset(result, ID2SYM(rb_intern("measurement")), prof_measurement_wrap(method_data->measurement));
430
+ rb_hash_aset(result, ID2SYM(rb_intern("allocations")), prof_method_allocations(self));
431
+
432
+ return result;
433
+ }
434
+
435
+ /* :nodoc: */
436
+ static VALUE prof_method_load(VALUE self, VALUE data)
437
+ {
438
+ prof_method_t* method_data = prof_get_method(self);
439
+ method_data->object = self;
440
+
441
+ method_data->klass_name = rb_hash_aref(data, ID2SYM(rb_intern("klass_name")));
442
+ method_data->klass_flags = FIX2INT(rb_hash_aref(data, ID2SYM(rb_intern("klass_flags"))));
443
+ method_data->method_name = rb_hash_aref(data, ID2SYM(rb_intern("method_name")));
444
+ method_data->key = FIX2LONG(rb_hash_aref(data, ID2SYM(rb_intern("key"))));
445
+
446
+ method_data->recursive = rb_hash_aref(data, ID2SYM(rb_intern("recursive"))) == Qtrue ? true : false;
447
+
448
+ method_data->source_file = rb_hash_aref(data, ID2SYM(rb_intern("source_file")));
449
+ method_data->source_line = FIX2INT(rb_hash_aref(data, ID2SYM(rb_intern("source_line"))));
450
+
451
+ VALUE call_trees = rb_hash_aref(data, ID2SYM(rb_intern("call_trees")));
452
+ method_data->call_trees = prof_get_call_trees(call_trees);
453
+
454
+ VALUE measurement = rb_hash_aref(data, ID2SYM(rb_intern("measurement")));
455
+ method_data->measurement = prof_get_measurement(measurement);
456
+
457
+ VALUE allocations = rb_hash_aref(data, ID2SYM(rb_intern("allocations")));
458
+ for (int i = 0; i < rb_array_len(allocations); i++)
459
+ {
460
+ VALUE allocation = rb_ary_entry(allocations, i);
461
+ prof_allocation_t* allocation_data = prof_allocation_get(allocation);
462
+
463
+ rb_st_insert(method_data->allocations_table, allocation_data->key, (st_data_t)allocation_data);
464
+ }
465
+ return data;
466
+ }
467
+
468
+ void rp_init_method_info()
469
+ {
470
+ /* MethodInfo */
471
+ cRpMethodInfo = rb_define_class_under(mProf, "MethodInfo", rb_cObject);
472
+ rb_undef_method(CLASS_OF(cRpMethodInfo), "new");
473
+ rb_define_alloc_func(cRpMethodInfo, prof_method_allocate);
474
+
475
+ rb_define_method(cRpMethodInfo, "klass_name", prof_method_klass_name, 0);
476
+ rb_define_method(cRpMethodInfo, "klass_flags", prof_method_klass_flags, 0);
477
+ rb_define_method(cRpMethodInfo, "method_name", prof_method_name, 0);
478
+
479
+ rb_define_method(cRpMethodInfo, "call_trees", prof_method_call_trees, 0);
480
+
481
+ rb_define_method(cRpMethodInfo, "allocations", prof_method_allocations, 0);
482
+ rb_define_method(cRpMethodInfo, "measurement", prof_method_measurement, 0);
483
+
484
+ rb_define_method(cRpMethodInfo, "source_file", prof_method_source_file, 0);
485
+ rb_define_method(cRpMethodInfo, "line", prof_method_line, 0);
486
+
487
+ rb_define_method(cRpMethodInfo, "recursive?", prof_method_recursive, 0);
488
+
489
+ rb_define_method(cRpMethodInfo, "_dump_data", prof_method_dump, 0);
490
+ rb_define_method(cRpMethodInfo, "_load_data", prof_method_load, 1);
491
+ }