ruby-prof 1.4.4-x64-mingw-ucrt

Sign up to get free protection for your applications and to get access to all the features.
Files changed (106) hide show
  1. checksums.yaml +7 -0
  2. data/CHANGES +608 -0
  3. data/LICENSE +25 -0
  4. data/README.md +5 -0
  5. data/Rakefile +98 -0
  6. data/bin/ruby-prof +328 -0
  7. data/bin/ruby-prof-check-trace +45 -0
  8. data/ext/ruby_prof/extconf.rb +22 -0
  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 +367 -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 +47 -0
  18. data/ext/ruby_prof/rp_measure_memory.c +46 -0
  19. data/ext/ruby_prof/rp_measure_process_time.c +66 -0
  20. data/ext/ruby_prof/rp_measure_wall_time.c +64 -0
  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 -0
  24. data/ext/ruby_prof/rp_method.h +62 -0
  25. data/ext/ruby_prof/rp_profile.c +915 -0
  26. data/ext/ruby_prof/rp_profile.h +35 -0
  27. data/ext/ruby_prof/rp_stack.c +212 -0
  28. data/ext/ruby_prof/rp_stack.h +53 -0
  29. data/ext/ruby_prof/rp_thread.c +362 -0
  30. data/ext/ruby_prof/rp_thread.h +39 -0
  31. data/ext/ruby_prof/ruby_prof.c +52 -0
  32. data/ext/ruby_prof/ruby_prof.h +26 -0
  33. data/ext/ruby_prof/vc/ruby_prof.sln +39 -0
  34. data/ext/ruby_prof/vc/ruby_prof.vcxproj +160 -0
  35. data/lib/3.1/ruby_prof.so +0 -0
  36. data/lib/ruby-prof/assets/call_stack_printer.html.erb +711 -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 -0
  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 -0
  45. data/lib/ruby-prof/printers/abstract_printer.rb +137 -0
  46. data/lib/ruby-prof/printers/call_info_printer.rb +53 -0
  47. data/lib/ruby-prof/printers/call_stack_printer.rb +180 -0
  48. data/lib/ruby-prof/printers/call_tree_printer.rb +147 -0
  49. data/lib/ruby-prof/printers/dot_printer.rb +132 -0
  50. data/lib/ruby-prof/printers/flat_printer.rb +53 -0
  51. data/lib/ruby-prof/printers/graph_html_printer.rb +63 -0
  52. data/lib/ruby-prof/printers/graph_printer.rb +113 -0
  53. data/lib/ruby-prof/printers/multi_printer.rb +127 -0
  54. data/lib/ruby-prof/profile.rb +37 -0
  55. data/lib/ruby-prof/rack.rb +95 -0
  56. data/lib/ruby-prof/task.rb +147 -0
  57. data/lib/ruby-prof/thread.rb +20 -0
  58. data/lib/ruby-prof/version.rb +3 -0
  59. data/lib/ruby-prof.rb +52 -0
  60. data/lib/unprof.rb +10 -0
  61. data/ruby-prof.gemspec +64 -0
  62. data/test/abstract_printer_test.rb +26 -0
  63. data/test/alias_test.rb +122 -0
  64. data/test/basic_test.rb +43 -0
  65. data/test/call_tree_visitor_test.rb +32 -0
  66. data/test/call_trees_test.rb +66 -0
  67. data/test/duplicate_names_test.rb +32 -0
  68. data/test/dynamic_method_test.rb +67 -0
  69. data/test/enumerable_test.rb +21 -0
  70. data/test/exceptions_test.rb +24 -0
  71. data/test/exclude_methods_test.rb +151 -0
  72. data/test/exclude_threads_test.rb +53 -0
  73. data/test/fiber_test.rb +129 -0
  74. data/test/gc_test.rb +100 -0
  75. data/test/inverse_call_tree_test.rb +175 -0
  76. data/test/line_number_test.rb +158 -0
  77. data/test/marshal_test.rb +145 -0
  78. data/test/measure_allocations.rb +26 -0
  79. data/test/measure_allocations_test.rb +333 -0
  80. data/test/measure_memory_test.rb +688 -0
  81. data/test/measure_process_time_test.rb +1614 -0
  82. data/test/measure_times.rb +56 -0
  83. data/test/measure_wall_time_test.rb +426 -0
  84. data/test/multi_printer_test.rb +71 -0
  85. data/test/no_method_class_test.rb +15 -0
  86. data/test/pause_resume_test.rb +175 -0
  87. data/test/prime.rb +54 -0
  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 -0
  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 +430 -0
  99. data/test/singleton_test.rb +38 -0
  100. data/test/stack_printer_test.rb +64 -0
  101. data/test/start_stop_test.rb +109 -0
  102. data/test/test_helper.rb +13 -0
  103. data/test/thread_test.rb +144 -0
  104. data/test/unique_call_path_test.rb +136 -0
  105. data/test/yarv_test.rb +60 -0
  106. metadata +187 -0
@@ -0,0 +1,491 @@
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
+ }
@@ -0,0 +1,62 @@
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_METHOD_INFO__
5
+ #define __RP_METHOD_INFO__
6
+
7
+ #include "ruby_prof.h"
8
+ #include "rp_measurement.h"
9
+
10
+ extern VALUE cRpMethodInfo;
11
+
12
+ // Source relation bit offsets.
13
+ enum {
14
+ kModuleIncludee = 0x1, // Included in module
15
+ kClassSingleton = 0x2, // Singleton of a class
16
+ kModuleSingleton = 0x4, // Singleton of a module
17
+ kObjectSingleton = 0x8, // Singleton of an object
18
+ kOtherSingleton = 0x10 // Singleton of unkown object
19
+ };
20
+
21
+ // Profiling information for each method.
22
+ // Excluded methods have no call_trees, source_klass, or source_file.
23
+ typedef struct prof_method_t
24
+ {
25
+ VALUE profile; // Profile this method is associated with - needed for mark phase
26
+ struct prof_call_trees_t* call_trees; // Call infos that call this method
27
+ st_table* allocations_table; // Tracks object allocations
28
+
29
+ st_data_t key; // Table key
30
+ unsigned int klass_flags; // Information about the type of class
31
+ VALUE klass; // Resolved klass
32
+ VALUE klass_name; // Resolved klass name for this method
33
+ VALUE method_name; // Resolved method name for this method
34
+
35
+ VALUE object; // Cached ruby object
36
+
37
+ bool recursive;
38
+ int visits; // Current visits on the stack
39
+ VALUE source_file; // Source file
40
+ int source_line; // Line number
41
+
42
+ prof_measurement_t* measurement; // Stores measurement data for this method
43
+ } prof_method_t;
44
+
45
+ void rp_init_method_info(void);
46
+
47
+ st_data_t method_key(VALUE klass, VALUE msym);
48
+
49
+ st_table* method_table_create(void);
50
+ prof_method_t* method_table_lookup(st_table* table, st_data_t key);
51
+ size_t method_table_insert(st_table* table, st_data_t key, prof_method_t* val);
52
+ void method_table_free(st_table* table);
53
+ prof_method_t* prof_method_create(VALUE profile, VALUE klass, VALUE msym, VALUE source_file, int source_line);
54
+ prof_method_t* prof_get_method(VALUE self);
55
+
56
+ VALUE prof_method_wrap(prof_method_t* result);
57
+ void prof_method_mark(void* data);
58
+
59
+ VALUE resolve_klass(VALUE klass, unsigned int* klass_flags);
60
+ VALUE resolve_klass_name(VALUE klass, unsigned int* klass_flags);
61
+
62
+ #endif //__RP_METHOD_INFO__