ruby-prof 1.1.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (99) hide show
  1. checksums.yaml +7 -0
  2. data/CHANGES +532 -0
  3. data/LICENSE +25 -0
  4. data/README.rdoc +5 -0
  5. data/Rakefile +110 -0
  6. data/bin/ruby-prof +380 -0
  7. data/bin/ruby-prof-check-trace +45 -0
  8. data/ext/ruby_prof/extconf.rb +36 -0
  9. data/ext/ruby_prof/rp_allocation.c +279 -0
  10. data/ext/ruby_prof/rp_allocation.h +31 -0
  11. data/ext/ruby_prof/rp_call_info.c +271 -0
  12. data/ext/ruby_prof/rp_call_info.h +35 -0
  13. data/ext/ruby_prof/rp_measure_allocations.c +52 -0
  14. data/ext/ruby_prof/rp_measure_memory.c +42 -0
  15. data/ext/ruby_prof/rp_measure_process_time.c +67 -0
  16. data/ext/ruby_prof/rp_measure_wall_time.c +62 -0
  17. data/ext/ruby_prof/rp_measurement.c +230 -0
  18. data/ext/ruby_prof/rp_measurement.h +50 -0
  19. data/ext/ruby_prof/rp_method.c +630 -0
  20. data/ext/ruby_prof/rp_method.h +70 -0
  21. data/ext/ruby_prof/rp_profile.c +895 -0
  22. data/ext/ruby_prof/rp_profile.h +37 -0
  23. data/ext/ruby_prof/rp_stack.c +196 -0
  24. data/ext/ruby_prof/rp_stack.h +56 -0
  25. data/ext/ruby_prof/rp_thread.c +337 -0
  26. data/ext/ruby_prof/rp_thread.h +36 -0
  27. data/ext/ruby_prof/ruby_prof.c +48 -0
  28. data/ext/ruby_prof/ruby_prof.h +17 -0
  29. data/ext/ruby_prof/vc/ruby_prof.sln +31 -0
  30. data/ext/ruby_prof/vc/ruby_prof.vcxproj +143 -0
  31. data/lib/ruby-prof.rb +52 -0
  32. data/lib/ruby-prof/assets/call_stack_printer.html.erb +713 -0
  33. data/lib/ruby-prof/assets/call_stack_printer.png +0 -0
  34. data/lib/ruby-prof/assets/graph_printer.html.erb +356 -0
  35. data/lib/ruby-prof/call_info.rb +57 -0
  36. data/lib/ruby-prof/call_info_visitor.rb +38 -0
  37. data/lib/ruby-prof/compatibility.rb +109 -0
  38. data/lib/ruby-prof/exclude_common_methods.rb +198 -0
  39. data/lib/ruby-prof/measurement.rb +14 -0
  40. data/lib/ruby-prof/method_info.rb +90 -0
  41. data/lib/ruby-prof/printers/abstract_printer.rb +127 -0
  42. data/lib/ruby-prof/printers/call_info_printer.rb +51 -0
  43. data/lib/ruby-prof/printers/call_stack_printer.rb +182 -0
  44. data/lib/ruby-prof/printers/call_tree_printer.rb +151 -0
  45. data/lib/ruby-prof/printers/dot_printer.rb +132 -0
  46. data/lib/ruby-prof/printers/flat_printer.rb +52 -0
  47. data/lib/ruby-prof/printers/graph_html_printer.rb +63 -0
  48. data/lib/ruby-prof/printers/graph_printer.rb +114 -0
  49. data/lib/ruby-prof/printers/multi_printer.rb +127 -0
  50. data/lib/ruby-prof/profile.rb +33 -0
  51. data/lib/ruby-prof/rack.rb +171 -0
  52. data/lib/ruby-prof/task.rb +147 -0
  53. data/lib/ruby-prof/thread.rb +35 -0
  54. data/lib/ruby-prof/version.rb +3 -0
  55. data/lib/unprof.rb +10 -0
  56. data/ruby-prof.gemspec +58 -0
  57. data/test/abstract_printer_test.rb +26 -0
  58. data/test/alias_test.rb +129 -0
  59. data/test/basic_test.rb +129 -0
  60. data/test/call_info_visitor_test.rb +31 -0
  61. data/test/duplicate_names_test.rb +32 -0
  62. data/test/dynamic_method_test.rb +53 -0
  63. data/test/enumerable_test.rb +21 -0
  64. data/test/exceptions_test.rb +24 -0
  65. data/test/exclude_methods_test.rb +146 -0
  66. data/test/exclude_threads_test.rb +53 -0
  67. data/test/fiber_test.rb +73 -0
  68. data/test/gc_test.rb +96 -0
  69. data/test/line_number_test.rb +161 -0
  70. data/test/marshal_test.rb +119 -0
  71. data/test/measure_allocations.rb +30 -0
  72. data/test/measure_allocations_test.rb +385 -0
  73. data/test/measure_allocations_trace_test.rb +385 -0
  74. data/test/measure_memory_trace_test.rb +756 -0
  75. data/test/measure_process_time_test.rb +849 -0
  76. data/test/measure_times.rb +54 -0
  77. data/test/measure_wall_time_test.rb +459 -0
  78. data/test/multi_printer_test.rb +71 -0
  79. data/test/no_method_class_test.rb +15 -0
  80. data/test/parser_timings.rb +24 -0
  81. data/test/pause_resume_test.rb +166 -0
  82. data/test/prime.rb +56 -0
  83. data/test/printer_call_stack_test.rb +28 -0
  84. data/test/printer_call_tree_test.rb +31 -0
  85. data/test/printer_flat_test.rb +68 -0
  86. data/test/printer_graph_html_test.rb +60 -0
  87. data/test/printer_graph_test.rb +41 -0
  88. data/test/printers_test.rb +141 -0
  89. data/test/printing_recursive_graph_test.rb +81 -0
  90. data/test/rack_test.rb +157 -0
  91. data/test/recursive_test.rb +210 -0
  92. data/test/singleton_test.rb +38 -0
  93. data/test/stack_printer_test.rb +64 -0
  94. data/test/start_stop_test.rb +109 -0
  95. data/test/test_helper.rb +24 -0
  96. data/test/thread_test.rb +144 -0
  97. data/test/unique_call_path_test.rb +190 -0
  98. data/test/yarv_test.rb +56 -0
  99. metadata +191 -0
@@ -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
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__
@@ -0,0 +1,630 @@
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_info.h"
6
+ #include "rp_method.h"
7
+
8
+ VALUE cRpMethodInfo;
9
+
10
+ /* ================ Helper Functions =================*/
11
+ VALUE
12
+ resolve_klass(VALUE klass, unsigned int *klass_flags)
13
+ {
14
+ VALUE result = klass;
15
+
16
+ if (klass == 0 || klass == Qnil)
17
+ {
18
+ result = Qnil;
19
+ }
20
+ else if (BUILTIN_TYPE(klass) == T_CLASS && FL_TEST(klass, FL_SINGLETON))
21
+ {
22
+ /* We have come across a singleton object. First
23
+ figure out what it is attached to.*/
24
+ VALUE 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
+ *klass_flags |= kClassSingleton;
30
+ result = attached;
31
+ }
32
+ /* Is this for singleton methods on a module? */
33
+ else if (BUILTIN_TYPE(attached) == T_MODULE)
34
+ {
35
+ *klass_flags |= kModuleSingleton;
36
+ result = attached;
37
+ }
38
+ /* Is this for singleton methods on an object? */
39
+ else if (BUILTIN_TYPE(attached) == T_OBJECT)
40
+ {
41
+ *klass_flags |= kObjectSingleton;
42
+ result = rb_class_superclass(klass);
43
+ }
44
+ /* Ok, this could be other things like an array made put onto
45
+ a singleton object (yeah, it happens, see the singleton
46
+ objects test case). */
47
+ else
48
+ {
49
+ *klass_flags |= kOtherSingleton;
50
+ result = klass;
51
+ }
52
+ }
53
+ /* Is this an include for a module? If so get the actual
54
+ module class since we want to combine all profiling
55
+ results for that module. */
56
+ else if (BUILTIN_TYPE(klass) == T_ICLASS)
57
+ {
58
+ unsigned int dummy;
59
+ *klass_flags |= kModuleIncludee;
60
+ result = resolve_klass(RBASIC(klass)->klass, &dummy);
61
+ }
62
+ return result;
63
+ }
64
+
65
+ VALUE
66
+ resolve_klass_name(VALUE klass, unsigned int* klass_flags)
67
+ {
68
+ VALUE result = Qnil;
69
+
70
+ if (klass == Qnil)
71
+ {
72
+ result = rb_str_new2("[global]");
73
+ }
74
+ else if (*klass_flags & kOtherSingleton)
75
+ {
76
+ result = rb_any_to_s(klass);
77
+ }
78
+ else
79
+ {
80
+ result = rb_class_name(klass);
81
+ }
82
+
83
+ return result;
84
+ }
85
+
86
+ st_data_t
87
+ method_key(VALUE klass, VALUE msym)
88
+ {
89
+ VALUE resolved_klass = klass;
90
+
91
+ /* Is this an include for a module? If so get the actual
92
+ module class since we want to combine all profiling
93
+ results for that module. */
94
+ if (klass == 0 || klass == Qnil)
95
+ {
96
+ resolved_klass = Qnil;
97
+ }
98
+ else if (BUILTIN_TYPE(klass) == T_ICLASS)
99
+ {
100
+ resolved_klass = RBASIC(klass)->klass;
101
+ }
102
+
103
+ return (resolved_klass << 4) + (msym);
104
+ }
105
+
106
+ /* ====== Allocation Table ====== */
107
+ st_table*
108
+ allocations_table_create()
109
+ {
110
+ return st_init_numtable();
111
+ }
112
+
113
+ static int
114
+ allocations_table_free_iterator(st_data_t key, st_data_t value, st_data_t dummy)
115
+ {
116
+ prof_allocation_free((prof_allocation_t*)value);
117
+ return ST_CONTINUE;
118
+ }
119
+
120
+ static int
121
+ prof_method_collect_allocations(st_data_t key, st_data_t value, st_data_t result)
122
+ {
123
+ prof_allocation_t* allocation = (prof_allocation_t*)value;
124
+ VALUE arr = (VALUE)result;
125
+ rb_ary_push(arr, prof_allocation_wrap(allocation));
126
+ return ST_CONTINUE;
127
+ }
128
+
129
+ static int
130
+ prof_method_mark_allocations(st_data_t key, st_data_t value, st_data_t data)
131
+ {
132
+ prof_allocation_t* allocation = (prof_allocation_t*)value;
133
+ prof_allocation_mark(allocation);
134
+ return ST_CONTINUE;
135
+ }
136
+
137
+ void
138
+ allocations_table_free(st_table* table)
139
+ {
140
+ st_foreach(table, allocations_table_free_iterator, 0);
141
+ st_free_table(table);
142
+ }
143
+
144
+ /* ================ prof_method_t =================*/
145
+ static prof_method_t*
146
+ prof_get_method(VALUE self)
147
+ {
148
+ /* Can't use Data_Get_Struct because that triggers the event hook
149
+ ending up in endless recursion. */
150
+ prof_method_t* result = DATA_PTR(self);
151
+
152
+ if (!result)
153
+ rb_raise(rb_eRuntimeError, "This RubyProf::MethodInfo instance has already been freed, likely because its profile has been freed.");
154
+
155
+ return result;
156
+ }
157
+
158
+ prof_method_t*
159
+ prof_method_create(VALUE klass, VALUE msym, VALUE source_file, int source_line)
160
+ {
161
+ prof_method_t *result = ALLOC(prof_method_t);
162
+ result->key = method_key(klass, msym);
163
+ result->klass_flags = 0;
164
+
165
+ /* Note we do not call resolve_klass_name now because that causes an object allocation that shows up
166
+ in the allocation results so we want to avoid it until after the profile run is complete. */
167
+ result->klass = resolve_klass(klass, &result->klass_flags);
168
+ result->klass_name = Qnil;
169
+ result->method_name = msym;
170
+ result->measurement = prof_measurement_create();
171
+
172
+ result->root = false;
173
+ result->excluded = false;
174
+
175
+ result->parent_call_infos = method_table_create();
176
+ result->child_call_infos = method_table_create();
177
+ result->allocations_table = allocations_table_create();
178
+
179
+ result->visits = 0;
180
+ result->recursive = false;
181
+
182
+ result->object = Qnil;
183
+
184
+ result->source_file = source_file;
185
+ result->source_line = source_line;
186
+
187
+ return result;
188
+ }
189
+
190
+ prof_method_t*
191
+ prof_method_create_excluded(VALUE klass, VALUE msym)
192
+ {
193
+ prof_method_t* result = prof_method_create(klass, msym, Qnil, 0);
194
+ result->excluded = 1;
195
+ return result;
196
+ }
197
+
198
+ static int
199
+ prof_method_collect_call_infos(st_data_t key, st_data_t value, st_data_t result)
200
+ {
201
+ prof_call_info_t* call_info = (prof_call_info_t*)value;
202
+ VALUE arr = (VALUE)result;
203
+ rb_ary_push(arr, prof_call_info_wrap(call_info));
204
+ return ST_CONTINUE;
205
+ }
206
+
207
+ static int
208
+ prof_method_mark_call_infos(st_data_t key, st_data_t value, st_data_t data)
209
+ {
210
+ prof_call_info_t* call_info = (prof_call_info_t*)value;
211
+ prof_call_info_mark(call_info);
212
+ return ST_CONTINUE;
213
+ }
214
+
215
+ static int
216
+ call_infos_free_iterator(st_data_t key, st_data_t value, st_data_t dummy)
217
+ {
218
+ prof_call_info_free((prof_call_info_t*)value);
219
+ return ST_CONTINUE;
220
+ }
221
+
222
+ void
223
+ call_info_table_free(st_table* table)
224
+ {
225
+ st_foreach(table, call_infos_free_iterator, 0);
226
+ st_free_table(table);
227
+ }
228
+
229
+ /* The underlying c structures are freed when the parent profile is freed.
230
+ However, on shutdown the Ruby GC frees objects in any will-nilly order.
231
+ That means the ruby thread object wrapping the c thread struct may
232
+ be freed before the parent profile. Thus we add in a free function
233
+ for the garbage collector so that if it does get called will nil
234
+ out our Ruby object reference.*/
235
+ static void
236
+ prof_method_ruby_gc_free(void *data)
237
+ {
238
+ prof_method_t* method = (prof_method_t*)data;
239
+
240
+ /* Has this method object been accessed by Ruby? If
241
+ yes clean it up so to avoid a segmentation fault. */
242
+ if (method->object != Qnil)
243
+ {
244
+ RDATA(method->object)->dmark = NULL;
245
+ RDATA(method->object)->dfree = NULL;
246
+ RDATA(method->object)->data = NULL;
247
+ method->object = Qnil;
248
+ }
249
+ method->klass_name = Qnil;
250
+ method->method_name = Qnil;
251
+ }
252
+
253
+ static void
254
+ prof_method_free(prof_method_t* method)
255
+ {
256
+ prof_method_ruby_gc_free(method);
257
+ allocations_table_free(method->allocations_table);
258
+
259
+ /* Remember call infos are referenced by their parent method and child method, so we only want
260
+ to iterate over one of them to avoid a double freeing */
261
+ call_info_table_free(method->parent_call_infos);
262
+ xfree(method->child_call_infos);
263
+
264
+ prof_measurement_free(method->measurement);
265
+ xfree(method);
266
+ }
267
+
268
+ size_t
269
+ prof_method_size(const void *data)
270
+ {
271
+ return sizeof(prof_method_t);
272
+ }
273
+
274
+ void
275
+ prof_method_mark(void *data)
276
+ {
277
+ prof_method_t* method = (prof_method_t*)data;
278
+ rb_gc_mark(method->klass_name);
279
+ rb_gc_mark(method->method_name);
280
+
281
+ if (method->klass != Qnil)
282
+ rb_gc_mark(method->klass);
283
+
284
+ if (method->object != Qnil)
285
+ rb_gc_mark(method->object);
286
+
287
+ prof_measurement_mark(method->measurement);
288
+
289
+ st_foreach(method->parent_call_infos, prof_method_mark_call_infos, 0);
290
+ st_foreach(method->child_call_infos, prof_method_mark_call_infos, 0);
291
+ st_foreach(method->allocations_table, prof_method_mark_allocations, 0);
292
+ }
293
+
294
+ static VALUE
295
+ prof_method_allocate(VALUE klass)
296
+ {
297
+ prof_method_t* method_data = prof_method_create(Qnil, Qnil, Qnil, 0);
298
+ method_data->object = prof_method_wrap(method_data);
299
+ return method_data->object;
300
+ }
301
+
302
+ VALUE
303
+ prof_method_wrap(prof_method_t *method)
304
+ {
305
+ if (method->object == Qnil)
306
+ {
307
+ method->object = Data_Wrap_Struct(cRpMethodInfo, prof_method_mark, prof_method_ruby_gc_free, method);
308
+ }
309
+ return method->object;
310
+ }
311
+
312
+ prof_method_t *
313
+ prof_method_get(VALUE self)
314
+ {
315
+ /* Can't use Data_Get_Struct because that triggers the event hook
316
+ ending up in endless recursion. */
317
+ prof_method_t* result = DATA_PTR(self);
318
+
319
+ if (!result)
320
+ {
321
+ rb_raise(rb_eRuntimeError, "This RubyProf::MethodInfo instance has already been freed, likely because its profile has been freed.");
322
+ }
323
+
324
+ return result;
325
+ }
326
+
327
+ st_table *
328
+ method_table_create()
329
+ {
330
+ return st_init_numtable();
331
+ }
332
+
333
+ static int
334
+ method_table_free_iterator(st_data_t key, st_data_t value, st_data_t dummy)
335
+ {
336
+ prof_method_free((prof_method_t *)value);
337
+ return ST_CONTINUE;
338
+ }
339
+
340
+ void
341
+ method_table_free(st_table *table)
342
+ {
343
+ st_foreach(table, method_table_free_iterator, 0);
344
+ st_free_table(table);
345
+ }
346
+
347
+ size_t
348
+ method_table_insert(st_table *table, st_data_t key, prof_method_t *val)
349
+ {
350
+ return st_insert(table, (st_data_t) key, (st_data_t) val);
351
+ }
352
+
353
+ prof_method_t *
354
+ method_table_lookup(st_table *table, st_data_t key)
355
+ {
356
+ st_data_t val;
357
+ if (st_lookup(table, (st_data_t)key, &val))
358
+ {
359
+ return (prof_method_t *) val;
360
+ }
361
+ else
362
+ {
363
+ return NULL;
364
+ }
365
+ }
366
+
367
+ /* ================ Method Info =================*/
368
+ /* Document-class: RubyProf::MethodInfo
369
+ The RubyProf::MethodInfo class stores profiling data for a method.
370
+ One instance of the RubyProf::MethodInfo class is created per method
371
+ called per thread. Thus, if a method is called in two different
372
+ thread then there will be two RubyProf::MethodInfo objects
373
+ created. RubyProf::MethodInfo objects can be accessed via
374
+ the RubyProf::Profile object.
375
+ */
376
+
377
+ /* call-seq:
378
+ callers -> array
379
+
380
+ Returns an array of call info objects that called this method (ie, parents).*/
381
+ static VALUE
382
+ prof_method_callers(VALUE self)
383
+ {
384
+ prof_method_t* method = prof_get_method(self);
385
+ VALUE result = rb_ary_new();
386
+ st_foreach(method->parent_call_infos, prof_method_collect_call_infos, result);
387
+ return result;
388
+ }
389
+
390
+ /* call-seq:
391
+ callees -> array
392
+
393
+ Returns an array of call info objects that this method called (ie, children).*/
394
+ static VALUE
395
+ prof_method_callees(VALUE self)
396
+ {
397
+ prof_method_t* method = prof_get_method(self);
398
+ VALUE result = rb_ary_new();
399
+ st_foreach(method->child_call_infos, prof_method_collect_call_infos, result);
400
+ return result;
401
+ }
402
+
403
+ /* call-seq:
404
+ allocations -> array
405
+
406
+ Returns an array of allocation information.*/
407
+ static VALUE
408
+ prof_method_allocations(VALUE self)
409
+ {
410
+ prof_method_t* method = prof_get_method(self);
411
+ VALUE result = rb_ary_new();
412
+ st_foreach(method->allocations_table, prof_method_collect_allocations, result);
413
+ return result;
414
+ }
415
+
416
+ /* call-seq:
417
+ called -> Measurement
418
+
419
+ Returns the measurement associated with this method. */
420
+ static VALUE
421
+ prof_method_measurement(VALUE self)
422
+ {
423
+ prof_method_t* method = prof_get_method(self);
424
+ return prof_measurement_wrap(method->measurement);
425
+ }
426
+
427
+ /* call-seq:
428
+ source_file => string
429
+
430
+ return the source file of the method
431
+ */
432
+ static VALUE prof_method_source_file(VALUE self)
433
+ {
434
+ prof_method_t* method = prof_method_get(self);
435
+ return method->source_file;
436
+ }
437
+
438
+ /* call-seq:
439
+ line_no -> int
440
+
441
+ returns the line number of the method */
442
+ static VALUE
443
+ prof_method_line(VALUE self)
444
+ {
445
+ prof_method_t* method = prof_method_get(self);
446
+ return INT2FIX(method->source_line);
447
+ }
448
+
449
+ /* call-seq:
450
+ klass_name -> string
451
+
452
+ Returns the name of this method's class. Singleton classes
453
+ will have the form <Object::Object>. */
454
+
455
+ static VALUE
456
+ prof_method_klass_name(VALUE self)
457
+ {
458
+ prof_method_t *method = prof_method_get(self);
459
+ if (method->klass_name == Qnil)
460
+ method->klass_name = resolve_klass_name(method->klass, &method->klass_flags);
461
+
462
+ return method->klass_name;
463
+ }
464
+
465
+ /* call-seq:
466
+ klass_flags -> integer
467
+
468
+ Returns the klass flags */
469
+
470
+ static VALUE
471
+ prof_method_klass_flags(VALUE self)
472
+ {
473
+ prof_method_t* method = prof_method_get(self);
474
+ return INT2FIX(method->klass_flags);
475
+ }
476
+
477
+ /* call-seq:
478
+ method_name -> string
479
+
480
+ Returns the name of this method in the format Object#method. Singletons
481
+ methods will be returned in the format <Object::Object>#method.*/
482
+
483
+ static VALUE
484
+ prof_method_name(VALUE self)
485
+ {
486
+ prof_method_t *method = prof_method_get(self);
487
+ return method->method_name;
488
+ }
489
+
490
+ /* call-seq:
491
+ root? -> boolean
492
+
493
+ Returns the true if this method is at the top of the call stack */
494
+ static VALUE
495
+ prof_method_root(VALUE self)
496
+ {
497
+ prof_method_t *method = prof_method_get(self);
498
+ return method->root ? Qtrue : Qfalse;
499
+ }
500
+
501
+ /* call-seq:
502
+ recursive? -> boolean
503
+
504
+ Returns the true if this method is recursively invoked */
505
+ static VALUE
506
+ prof_method_recursive(VALUE self)
507
+ {
508
+ prof_method_t* method = prof_method_get(self);
509
+ return method->recursive ? Qtrue : Qfalse;
510
+ }
511
+
512
+ /* call-seq:
513
+ excluded? -> boolean
514
+
515
+ Returns the true if this method was excluded */
516
+ static VALUE
517
+ prof_method_excluded(VALUE self)
518
+ {
519
+ prof_method_t* method = prof_method_get(self);
520
+ return method->excluded ? Qtrue : Qfalse;
521
+ }
522
+
523
+ /* :nodoc: */
524
+ static VALUE
525
+ prof_method_dump(VALUE self)
526
+ {
527
+ prof_method_t* method_data = DATA_PTR(self);
528
+ VALUE result = rb_hash_new();
529
+
530
+ rb_hash_aset(result, ID2SYM(rb_intern("klass_name")), prof_method_klass_name(self));
531
+ rb_hash_aset(result, ID2SYM(rb_intern("klass_flags")), INT2FIX(method_data->klass_flags));
532
+ rb_hash_aset(result, ID2SYM(rb_intern("method_name")), method_data->method_name);
533
+
534
+ rb_hash_aset(result, ID2SYM(rb_intern("key")), INT2FIX(method_data->key));
535
+ rb_hash_aset(result, ID2SYM(rb_intern("root")), prof_method_root(self));
536
+ rb_hash_aset(result, ID2SYM(rb_intern("recursive")), prof_method_recursive(self));
537
+ rb_hash_aset(result, ID2SYM(rb_intern("excluded")), prof_method_excluded(self));
538
+ rb_hash_aset(result, ID2SYM(rb_intern("source_file")), method_data->source_file);
539
+ rb_hash_aset(result, ID2SYM(rb_intern("source_line")), INT2FIX(method_data->source_line));
540
+
541
+ rb_hash_aset(result, ID2SYM(rb_intern("measurement")), prof_measurement_wrap(method_data->measurement));
542
+
543
+ rb_hash_aset(result, ID2SYM(rb_intern("callers")), prof_method_callers(self));
544
+ rb_hash_aset(result, ID2SYM(rb_intern("callees")), prof_method_callees(self));
545
+
546
+ rb_hash_aset(result, ID2SYM(rb_intern("allocations")), prof_method_allocations(self));
547
+
548
+ return result;
549
+ }
550
+
551
+ /* :nodoc: */
552
+ static VALUE
553
+ prof_method_load(VALUE self, VALUE data)
554
+ {
555
+ prof_method_t* method_data = RDATA(self)->data;
556
+ method_data->object = self;
557
+
558
+ method_data->klass_name = rb_hash_aref(data, ID2SYM(rb_intern("klass_name")));
559
+ method_data->klass_flags = FIX2INT(rb_hash_aref(data, ID2SYM(rb_intern("klass_flags"))));
560
+ method_data->method_name = rb_hash_aref(data, ID2SYM(rb_intern("method_name")));
561
+ method_data->key = FIX2LONG(rb_hash_aref(data, ID2SYM(rb_intern("key"))));
562
+
563
+ method_data->root = rb_hash_aref(data, ID2SYM(rb_intern("root"))) == Qtrue ? true : false;
564
+ method_data->recursive = rb_hash_aref(data, ID2SYM(rb_intern("recursive"))) == Qtrue ? true : false;
565
+ method_data->excluded = rb_hash_aref(data, ID2SYM(rb_intern("excluded"))) == Qtrue ? true : false;
566
+
567
+ method_data->source_file = rb_hash_aref(data, ID2SYM(rb_intern("source_file")));
568
+ method_data->source_line = FIX2INT(rb_hash_aref(data, ID2SYM(rb_intern("source_line"))));
569
+
570
+ VALUE measurement = rb_hash_aref(data, ID2SYM(rb_intern("measurement")));
571
+ method_data->measurement = prof_get_measurement(measurement);
572
+
573
+ VALUE callers = rb_hash_aref(data, ID2SYM(rb_intern("callers")));
574
+ for (int i = 0; i < rb_array_len(callers); i++)
575
+ {
576
+ VALUE call_info = rb_ary_entry(callers, i);
577
+ prof_call_info_t *call_info_data = prof_get_call_info(call_info);
578
+ st_data_t key = call_info_data->parent ? call_info_data->parent->key : method_key(Qnil, 0);
579
+ call_info_table_insert(method_data->parent_call_infos, key, call_info_data);
580
+ }
581
+
582
+ VALUE callees = rb_hash_aref(data, ID2SYM(rb_intern("callees")));
583
+ for (int i = 0; i < rb_array_len(callees); i++)
584
+ {
585
+ VALUE call_info = rb_ary_entry(callees, i);
586
+ prof_call_info_t *call_info_data = prof_get_call_info(call_info);
587
+
588
+ st_data_t key = call_info_data->method ? call_info_data->method->key : method_key(Qnil, 0);
589
+ call_info_table_insert(method_data->child_call_infos, key, call_info_data);
590
+ }
591
+
592
+ VALUE allocations = rb_hash_aref(data, ID2SYM(rb_intern("allocations")));
593
+ for (int i = 0; i < rb_array_len(allocations); i++)
594
+ {
595
+ VALUE allocation = rb_ary_entry(allocations, i);
596
+ prof_allocation_t* allocation_data = prof_allocation_get(allocation);
597
+
598
+ st_insert(method_data->allocations_table, allocation_data->key, (st_data_t)allocation_data);
599
+ }
600
+ return data;
601
+ }
602
+
603
+ void rp_init_method_info()
604
+ {
605
+ /* MethodInfo */
606
+ cRpMethodInfo = rb_define_class_under(mProf, "MethodInfo", rb_cData);
607
+ rb_undef_method(CLASS_OF(cRpMethodInfo), "new");
608
+ rb_define_alloc_func(cRpMethodInfo, prof_method_allocate);
609
+
610
+ rb_define_method(cRpMethodInfo, "klass_name", prof_method_klass_name, 0);
611
+ rb_define_method(cRpMethodInfo, "klass_flags", prof_method_klass_flags, 0);
612
+
613
+ rb_define_method(cRpMethodInfo, "method_name", prof_method_name, 0);
614
+
615
+ rb_define_method(cRpMethodInfo, "callers", prof_method_callers, 0);
616
+ rb_define_method(cRpMethodInfo, "callees", prof_method_callees, 0);
617
+ rb_define_method(cRpMethodInfo, "allocations", prof_method_allocations, 0);
618
+
619
+ rb_define_method(cRpMethodInfo, "measurement", prof_method_measurement, 0);
620
+
621
+ rb_define_method(cRpMethodInfo, "source_file", prof_method_source_file, 0);
622
+ rb_define_method(cRpMethodInfo, "line", prof_method_line, 0);
623
+
624
+ rb_define_method(cRpMethodInfo, "root?", prof_method_root, 0);
625
+ rb_define_method(cRpMethodInfo, "recursive?", prof_method_recursive, 0);
626
+ rb_define_method(cRpMethodInfo, "excluded?", prof_method_excluded, 0);
627
+
628
+ rb_define_method(cRpMethodInfo, "_dump_data", prof_method_dump, 0);
629
+ rb_define_method(cRpMethodInfo, "_load_data", prof_method_load, 1);
630
+ }