airbnb-ruby-prof 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (116) hide show
  1. data/CHANGES +483 -0
  2. data/LICENSE +25 -0
  3. data/README.rdoc +426 -0
  4. data/Rakefile +51 -0
  5. data/bin/ruby-prof +279 -0
  6. data/bin/ruby-prof-check-trace +45 -0
  7. data/examples/flat.txt +50 -0
  8. data/examples/graph.dot +84 -0
  9. data/examples/graph.html +823 -0
  10. data/examples/graph.txt +139 -0
  11. data/examples/multi.flat.txt +23 -0
  12. data/examples/multi.graph.html +760 -0
  13. data/examples/multi.grind.dat +114 -0
  14. data/examples/multi.stack.html +547 -0
  15. data/examples/stack.html +547 -0
  16. data/ext/ruby_prof/extconf.rb +67 -0
  17. data/ext/ruby_prof/rp_call_info.c +374 -0
  18. data/ext/ruby_prof/rp_call_info.h +59 -0
  19. data/ext/ruby_prof/rp_fast_call_tree_printer.c +247 -0
  20. data/ext/ruby_prof/rp_fast_call_tree_printer.h +10 -0
  21. data/ext/ruby_prof/rp_measure.c +71 -0
  22. data/ext/ruby_prof/rp_measure.h +56 -0
  23. data/ext/ruby_prof/rp_measure_allocations.c +74 -0
  24. data/ext/ruby_prof/rp_measure_cpu_time.c +134 -0
  25. data/ext/ruby_prof/rp_measure_gc_runs.c +71 -0
  26. data/ext/ruby_prof/rp_measure_gc_time.c +58 -0
  27. data/ext/ruby_prof/rp_measure_memory.c +75 -0
  28. data/ext/ruby_prof/rp_measure_process_time.c +69 -0
  29. data/ext/ruby_prof/rp_measure_wall_time.c +43 -0
  30. data/ext/ruby_prof/rp_method.c +717 -0
  31. data/ext/ruby_prof/rp_method.h +79 -0
  32. data/ext/ruby_prof/rp_stack.c +221 -0
  33. data/ext/ruby_prof/rp_stack.h +81 -0
  34. data/ext/ruby_prof/rp_thread.c +312 -0
  35. data/ext/ruby_prof/rp_thread.h +36 -0
  36. data/ext/ruby_prof/ruby_prof.c +800 -0
  37. data/ext/ruby_prof/ruby_prof.h +64 -0
  38. data/ext/ruby_prof/vc/ruby_prof.sln +32 -0
  39. data/ext/ruby_prof/vc/ruby_prof_18.vcxproj +108 -0
  40. data/ext/ruby_prof/vc/ruby_prof_19.vcxproj +110 -0
  41. data/ext/ruby_prof/vc/ruby_prof_20.vcxproj +110 -0
  42. data/lib/ruby-prof.rb +63 -0
  43. data/lib/ruby-prof/aggregate_call_info.rb +76 -0
  44. data/lib/ruby-prof/assets/call_stack_printer.css.html +117 -0
  45. data/lib/ruby-prof/assets/call_stack_printer.js.html +385 -0
  46. data/lib/ruby-prof/assets/call_stack_printer.png +0 -0
  47. data/lib/ruby-prof/assets/flame_graph_printer.lib.css.html +149 -0
  48. data/lib/ruby-prof/assets/flame_graph_printer.lib.js.html +707 -0
  49. data/lib/ruby-prof/assets/flame_graph_printer.page.js.html +56 -0
  50. data/lib/ruby-prof/assets/flame_graph_printer.tmpl.html.erb +39 -0
  51. data/lib/ruby-prof/call_info.rb +111 -0
  52. data/lib/ruby-prof/call_info_visitor.rb +40 -0
  53. data/lib/ruby-prof/compatibility.rb +186 -0
  54. data/lib/ruby-prof/method_info.rb +109 -0
  55. data/lib/ruby-prof/printers/abstract_printer.rb +85 -0
  56. data/lib/ruby-prof/printers/call_info_printer.rb +41 -0
  57. data/lib/ruby-prof/printers/call_stack_printer.rb +260 -0
  58. data/lib/ruby-prof/printers/call_tree_printer.rb +130 -0
  59. data/lib/ruby-prof/printers/dot_printer.rb +132 -0
  60. data/lib/ruby-prof/printers/fast_call_tree_printer.rb +87 -0
  61. data/lib/ruby-prof/printers/flame_graph_html_printer.rb +59 -0
  62. data/lib/ruby-prof/printers/flame_graph_json_printer.rb +157 -0
  63. data/lib/ruby-prof/printers/flat_printer.rb +70 -0
  64. data/lib/ruby-prof/printers/flat_printer_with_line_numbers.rb +64 -0
  65. data/lib/ruby-prof/printers/graph_html_printer.rb +244 -0
  66. data/lib/ruby-prof/printers/graph_printer.rb +116 -0
  67. data/lib/ruby-prof/printers/multi_printer.rb +58 -0
  68. data/lib/ruby-prof/profile.rb +22 -0
  69. data/lib/ruby-prof/profile/exclude_common_methods.rb +201 -0
  70. data/lib/ruby-prof/rack.rb +95 -0
  71. data/lib/ruby-prof/task.rb +147 -0
  72. data/lib/ruby-prof/thread.rb +35 -0
  73. data/lib/ruby-prof/version.rb +4 -0
  74. data/lib/ruby-prof/walker.rb +95 -0
  75. data/lib/unprof.rb +10 -0
  76. data/ruby-prof.gemspec +56 -0
  77. data/test/aggregate_test.rb +136 -0
  78. data/test/basic_test.rb +128 -0
  79. data/test/block_test.rb +74 -0
  80. data/test/call_info_test.rb +78 -0
  81. data/test/call_info_visitor_test.rb +31 -0
  82. data/test/duplicate_names_test.rb +32 -0
  83. data/test/dynamic_method_test.rb +55 -0
  84. data/test/enumerable_test.rb +21 -0
  85. data/test/exceptions_test.rb +16 -0
  86. data/test/exclude_methods_test.rb +146 -0
  87. data/test/exclude_threads_test.rb +53 -0
  88. data/test/fiber_test.rb +79 -0
  89. data/test/issue137_test.rb +63 -0
  90. data/test/line_number_test.rb +71 -0
  91. data/test/measure_allocations_test.rb +26 -0
  92. data/test/measure_cpu_time_test.rb +213 -0
  93. data/test/measure_gc_runs_test.rb +32 -0
  94. data/test/measure_gc_time_test.rb +36 -0
  95. data/test/measure_memory_test.rb +33 -0
  96. data/test/measure_process_time_test.rb +63 -0
  97. data/test/measure_wall_time_test.rb +255 -0
  98. data/test/module_test.rb +45 -0
  99. data/test/multi_measure_test.rb +38 -0
  100. data/test/multi_printer_test.rb +83 -0
  101. data/test/no_method_class_test.rb +15 -0
  102. data/test/pause_resume_test.rb +166 -0
  103. data/test/prime.rb +54 -0
  104. data/test/printers_test.rb +255 -0
  105. data/test/printing_recursive_graph_test.rb +127 -0
  106. data/test/rack_test.rb +93 -0
  107. data/test/recursive_test.rb +212 -0
  108. data/test/singleton_test.rb +38 -0
  109. data/test/stack_printer_test.rb +65 -0
  110. data/test/stack_test.rb +138 -0
  111. data/test/start_stop_test.rb +112 -0
  112. data/test/test_helper.rb +264 -0
  113. data/test/thread_test.rb +187 -0
  114. data/test/unique_call_path_test.rb +202 -0
  115. data/test/yarv_test.rb +55 -0
  116. metadata +211 -0
@@ -0,0 +1,67 @@
1
+ require "mkmf"
2
+
3
+ if RUBY_ENGINE != "ruby"
4
+ STDERR.puts("\n\n***** This gem is MRI-specific. It does not support #{RUBY_ENGINE}. *****\n\n")
5
+ exit(1)
6
+ end
7
+
8
+ if RUBY_VERSION < "1.9.3"
9
+ STDERR.puts("\n\n***** Ruby version #{RUBY_VERSION} is no longer supported. Please upgrade to 1.9.3 or higher. *****\n\n")
10
+ exit(1)
11
+ end
12
+
13
+ # For the love of bitfields...
14
+ $CFLAGS += ' -std=c99'
15
+
16
+ # standard ruby methods
17
+ have_func("rb_gc_stat")
18
+ have_func("rb_gc_count")
19
+
20
+ # Alexander Dymo GC patch
21
+ have_func("rb_os_allocated_objects")
22
+ have_func("rb_gc_allocated_size")
23
+
24
+ # Stefan Kaes GC patches
25
+ have_func("rb_gc_collections")
26
+ have_func("rb_gc_time")
27
+ # for ruby 2.1
28
+ have_func("rb_gc_total_time")
29
+ have_func("rb_gc_total_mallocs")
30
+ have_func("rb_gc_total_malloced_bytes")
31
+
32
+ # Lloyd Hilaiel's heap info patch
33
+ have_func("rb_heap_total_mem")
34
+ have_func("rb_gc_heap_info")
35
+
36
+ def add_define(name, value = nil)
37
+ if value
38
+ $defs.push("-D#{name}=#{value}")
39
+ else
40
+ $defs.push("-D#{name}")
41
+ end
42
+ end
43
+
44
+ def windows?
45
+ RbConfig::CONFIG['host_os'] =~ /mswin|mingw/
46
+ end
47
+
48
+ if !windows? && RUBY_PLATFORM !~ /(darwin|openbsd)/
49
+ $LDFLAGS += " -lrt" # for clock_gettime
50
+ end
51
+ add_define("RUBY_PROF_RUBY_VERSION", RUBY_VERSION.split('.')[0..2].inject(0){|v,d| v*100+d.to_i})
52
+
53
+ # for ruby 1.9, determine whether threads inherit trace flags (latest 1.9.2 and later should work correctly)
54
+ if RUBY_VERSION > "1.9"
55
+ require 'set'
56
+ threads = Set.new
57
+ set_trace_func lambda { |*args| threads << Thread.current.object_id }
58
+ Thread.new{1}.join
59
+ set_trace_func nil
60
+ if threads.size < 2
61
+ # if we end up here, ruby does not automatically activate tracing in spawned threads
62
+ STDERR.puts("Ruby #{RUBY_VERSION} does not activate tracing in spawned threads. Consider upgrading.")
63
+ exit(1)
64
+ end
65
+ end
66
+
67
+ create_makefile("ruby_prof")
@@ -0,0 +1,374 @@
1
+ /* Copyright (C) 2005-2013 Shugo Maeda <shugo@ruby-lang.org> and Charlie Savage <cfis@savagexi.com>
2
+ Please see the LICENSE file for copyright and distribution information */
3
+
4
+ #include "ruby_prof.h"
5
+
6
+ #define INITIAL_CALL_INFOS_SIZE 2
7
+
8
+ VALUE cCallInfo;
9
+
10
+
11
+ // Forward declarations
12
+ st_table * call_info_table_create();
13
+
14
+
15
+ static prof_call_info_t *
16
+ prof_call_info_allocate(size_t len)
17
+ {
18
+ prof_call_info_t *result =
19
+ (prof_call_info_t*) ruby_xmalloc(
20
+ sizeof(prof_call_info_t) + len * sizeof(prof_measure_value_t));
21
+ result->measures_len = len;
22
+ return result;
23
+ }
24
+
25
+ /* ======= prof_call_info_t ========*/
26
+ prof_call_info_t *
27
+ prof_call_info_create(prof_method_t* method, prof_call_info_t* parent, size_t measurements_len)
28
+ {
29
+ prof_call_info_t *result = prof_call_info_allocate(measurements_len);
30
+ result->object = Qnil;
31
+ result->target = method;
32
+ result->parent = parent;
33
+ result->call_infos = call_info_table_create();
34
+ result->children = Qnil;
35
+
36
+ result->called = 0;
37
+
38
+ result->recursive = 0;
39
+ result->depth = 0;
40
+ result->line = 0;
41
+
42
+ for(size_t i = 0; i < measurements_len; i++) {
43
+ result->measure_values[i].total = 0.0;
44
+ result->measure_values[i].self = 0.0;
45
+ result->measure_values[i].wait = 0.0;
46
+ }
47
+
48
+ return result;
49
+ }
50
+ static void
51
+ prof_call_info_ruby_gc_free(prof_call_info_t *call_info)
52
+ {
53
+ /* Has this thread object been accessed by Ruby? If
54
+ yes clean it up so to avoid a segmentation fault. */
55
+ if (call_info->object != Qnil)
56
+ {
57
+ RDATA(call_info->object)->data = NULL;
58
+ RDATA(call_info->object)->dfree = NULL;
59
+ RDATA(call_info->object)->dmark = NULL;
60
+ }
61
+ call_info->object = Qnil;
62
+ }
63
+
64
+ static void
65
+ prof_call_info_free(prof_call_info_t *call_info)
66
+ {
67
+ prof_call_info_ruby_gc_free(call_info);
68
+ st_free_table(call_info->call_infos);
69
+ xfree(call_info);
70
+ }
71
+
72
+ static void
73
+ prof_call_info_mark(prof_call_info_t *call_info)
74
+ {
75
+ if (call_info->object)
76
+ rb_gc_mark(call_info->object);
77
+
78
+ if (call_info->children)
79
+ rb_gc_mark(call_info->children);
80
+
81
+ /* We don't mark the call info child table since that will be done
82
+ via the appropriate method */
83
+ }
84
+
85
+ VALUE
86
+ prof_call_info_wrap(prof_call_info_t *call_info)
87
+ {
88
+ if (call_info->object == Qnil)
89
+ {
90
+ call_info->object = Data_Wrap_Struct(cCallInfo, prof_call_info_mark, prof_call_info_ruby_gc_free, call_info);
91
+ }
92
+ return call_info->object;
93
+ }
94
+
95
+ static prof_call_info_t *
96
+ prof_get_call_info(VALUE self)
97
+ {
98
+ /* Can't use Data_Get_Struct because that triggers the event hook
99
+ ending up in endless recursion. */
100
+ prof_call_info_t* result = DATA_PTR(self);
101
+
102
+ if (!result)
103
+ rb_raise(rb_eRuntimeError, "This RubyProf::CallInfo instance has already been freed, likely because its profile has been freed.");
104
+
105
+ return result;
106
+ }
107
+
108
+ /* ======= Call Info Table ========*/
109
+ st_table *
110
+ call_info_table_create()
111
+ {
112
+ return st_init_table(&type_method_hash);
113
+ }
114
+
115
+ size_t
116
+ call_info_table_insert(st_table *table, const prof_method_key_t *key, prof_call_info_t *val)
117
+ {
118
+ return st_insert(table, (st_data_t) key, (st_data_t) val);
119
+ }
120
+
121
+ prof_call_info_t *
122
+ call_info_table_lookup(st_table *table, const prof_method_key_t *key)
123
+ {
124
+ st_data_t val;
125
+ if (st_lookup(table, (st_data_t) key, &val))
126
+ {
127
+ return (prof_call_info_t *) val;
128
+ }
129
+ else
130
+ {
131
+ return NULL;
132
+ }
133
+ }
134
+
135
+
136
+ /* ======= RubyProf::CallInfo ========*/
137
+
138
+ /* Document-class: RubyProf::CallInfo
139
+ RubyProf::CallInfo is a helper class used by RubyProf::MethodInfo
140
+ to keep track of which child methods were called and how long
141
+ they took to execute. */
142
+
143
+
144
+ /* call-seq:
145
+ called -> MethodInfo
146
+
147
+ Returns the target method. */
148
+ static VALUE
149
+ prof_call_info_target(VALUE self)
150
+ {
151
+ /* Target is a pointer to a method_info - so we have to be careful
152
+ about the GC. We will wrap the method_info but provide no
153
+ free method so the underlying object is not freed twice! */
154
+
155
+ prof_call_info_t *result = prof_get_call_info(self);
156
+ return prof_method_wrap(result->target);
157
+ }
158
+
159
+ /* call-seq:
160
+ called -> int
161
+
162
+ Returns the total amount of times this method was called. */
163
+ static VALUE
164
+ prof_call_info_called(VALUE self)
165
+ {
166
+ prof_call_info_t *result = prof_get_call_info(self);
167
+ return INT2NUM(result->called);
168
+ }
169
+
170
+ /* call-seq:
171
+ called=n -> n
172
+
173
+ Sets the call count to n. */
174
+ static VALUE
175
+ prof_call_info_set_called(VALUE self, VALUE called)
176
+ {
177
+ prof_call_info_t *result = prof_get_call_info(self);
178
+ result->called = NUM2INT(called);
179
+ return called;
180
+ }
181
+
182
+ /* call-seq:
183
+ recursive? -> boolean
184
+
185
+ Returns the true if this call info is a recursive invocation */
186
+ static VALUE
187
+ prof_call_info_recursive(VALUE self)
188
+ {
189
+ prof_call_info_t *result = prof_get_call_info(self);
190
+ return result->recursive ? Qtrue : Qfalse;
191
+ }
192
+
193
+ /* call-seq:
194
+ depth -> int
195
+
196
+ returns the depth of this call info in the call graph */
197
+ static VALUE
198
+ prof_call_info_depth(VALUE self)
199
+ {
200
+ prof_call_info_t *result = prof_get_call_info(self);
201
+ return rb_int_new(result->depth);
202
+ }
203
+
204
+ /* call-seq:
205
+ line_no -> int
206
+
207
+ returns the line number of the method */
208
+ static VALUE
209
+ prof_call_info_line(VALUE self)
210
+ {
211
+ prof_call_info_t *result = prof_get_call_info(self);
212
+ return rb_int_new(result->line);
213
+ }
214
+
215
+ /* call-seq:
216
+ parent -> call_info
217
+
218
+ Returns the call_infos parent call_info object (the method that called this method).*/
219
+ static VALUE
220
+ prof_call_info_parent(VALUE self)
221
+ {
222
+ prof_call_info_t *result = prof_get_call_info(self);
223
+ if (result->parent)
224
+ return prof_call_info_wrap(result->parent);
225
+ else
226
+ return Qnil;
227
+ }
228
+
229
+ /* call-seq:
230
+ parent=new_parent -> new_parent
231
+
232
+ Changes the parent of self to new_parent and returns it.*/
233
+ static VALUE
234
+ prof_call_info_set_parent(VALUE self, VALUE new_parent)
235
+ {
236
+ prof_call_info_t *result = prof_get_call_info(self);
237
+ if (new_parent == Qnil)
238
+ result->parent = NULL;
239
+ else
240
+ result->parent = prof_get_call_info(new_parent);
241
+ return prof_call_info_parent(self);
242
+ }
243
+
244
+ static int
245
+ prof_call_info_collect_children(st_data_t key, st_data_t value, st_data_t result)
246
+ {
247
+ prof_call_info_t *call_info = (prof_call_info_t *) value;
248
+ VALUE arr = (VALUE) result;
249
+ rb_ary_push(arr, prof_call_info_wrap(call_info));
250
+ return ST_CONTINUE;
251
+ }
252
+
253
+ /* call-seq:
254
+ children -> hash
255
+
256
+ Returns an array of call info objects of methods that this method
257
+ called (ie, children).*/
258
+ static VALUE
259
+ prof_call_info_children(VALUE self)
260
+ {
261
+ prof_call_info_t *call_info = prof_get_call_info(self);
262
+ if (call_info->children == Qnil)
263
+ {
264
+ call_info->children = rb_ary_new();
265
+ st_foreach(call_info->call_infos, prof_call_info_collect_children, call_info->children);
266
+ }
267
+ return call_info->children;
268
+ }
269
+
270
+ /* ======= Call Infos ========*/
271
+ prof_call_infos_t*
272
+ prof_call_infos_create()
273
+ {
274
+ prof_call_infos_t *result = ALLOC(prof_call_infos_t);
275
+ result->start = ALLOC_N(prof_call_info_t*, INITIAL_CALL_INFOS_SIZE);
276
+ result->end = result->start + INITIAL_CALL_INFOS_SIZE;
277
+ result->ptr = result->start;
278
+ result->object = Qnil;
279
+ return result;
280
+ }
281
+
282
+ void
283
+ prof_call_infos_mark(prof_call_infos_t *call_infos)
284
+ {
285
+ prof_call_info_t **call_info;
286
+
287
+ if (call_infos->object)
288
+ rb_gc_mark(call_infos->object);
289
+
290
+ for(call_info=call_infos->start; call_info<call_infos->ptr; call_info++)
291
+ {
292
+ prof_call_info_mark(*call_info);
293
+ }
294
+ }
295
+
296
+ void
297
+ prof_call_infos_free(prof_call_infos_t *call_infos)
298
+ {
299
+ prof_call_info_t **call_info;
300
+
301
+ for(call_info=call_infos->start; call_info<call_infos->ptr; call_info++)
302
+ {
303
+ prof_call_info_free(*call_info);
304
+ }
305
+ }
306
+
307
+ void
308
+ prof_add_call_info(prof_call_infos_t *call_infos, prof_call_info_t *call_info)
309
+ {
310
+ if (call_infos->ptr == call_infos->end)
311
+ {
312
+ size_t len = call_infos->ptr - call_infos->start;
313
+ size_t new_capacity = (call_infos->end - call_infos->start) * 2;
314
+ REALLOC_N(call_infos->start, prof_call_info_t*, new_capacity);
315
+ call_infos->ptr = call_infos->start + len;
316
+ call_infos->end = call_infos->start + new_capacity;
317
+ }
318
+ *call_infos->ptr = call_info;
319
+ call_infos->ptr++;
320
+ }
321
+
322
+ VALUE
323
+ prof_call_infos_wrap(prof_call_infos_t *call_infos)
324
+ {
325
+ if (call_infos->object == Qnil)
326
+ {
327
+ prof_call_info_t **i;
328
+ call_infos->object = rb_ary_new();
329
+ for(i=call_infos->start; i<call_infos->ptr; i++)
330
+ {
331
+ VALUE call_info = prof_call_info_wrap(*i);
332
+ rb_ary_push(call_infos->object, call_info);
333
+ }
334
+ }
335
+ return call_infos->object;
336
+ }
337
+
338
+ VALUE
339
+ prof_call_info_measure_values(VALUE self)
340
+ {
341
+ prof_call_info_t *call_info = prof_get_call_info(self);
342
+
343
+ VALUE ary = rb_ary_new2(call_info->measures_len);
344
+ for(size_t i = 0; i < call_info->measures_len; i++) {
345
+ VALUE sub_ary = rb_ary_new2(3);
346
+
347
+ rb_ary_store(sub_ary, 0, DBL2NUM(call_info->measure_values[i].total));
348
+ rb_ary_store(sub_ary, 1, DBL2NUM(call_info->measure_values[i].self));
349
+ rb_ary_store(sub_ary, 2, DBL2NUM(call_info->measure_values[i].wait));
350
+
351
+ rb_ary_store(ary, i, sub_ary);
352
+ }
353
+
354
+ return ary;
355
+ }
356
+
357
+
358
+ void rp_init_call_info()
359
+ {
360
+ /* CallInfo */
361
+ cCallInfo = rb_define_class_under(mProf, "CallInfo", rb_cObject);
362
+ rb_undef_method(CLASS_OF(cCallInfo), "new");
363
+ rb_define_method(cCallInfo, "parent", prof_call_info_parent, 0);
364
+ rb_define_method(cCallInfo, "parent=", prof_call_info_set_parent, 1);
365
+ rb_define_method(cCallInfo, "children", prof_call_info_children, 0);
366
+ rb_define_method(cCallInfo, "target", prof_call_info_target, 0);
367
+ rb_define_method(cCallInfo, "called", prof_call_info_called, 0);
368
+ rb_define_method(cCallInfo, "called=", prof_call_info_set_called, 1);
369
+
370
+ rb_define_method(cCallInfo, "recursive?", prof_call_info_recursive, 0);
371
+ rb_define_method(cCallInfo, "depth", prof_call_info_depth, 0);
372
+ rb_define_method(cCallInfo, "line", prof_call_info_line, 0);
373
+ rb_define_method(cCallInfo, "measure_values", prof_call_info_measure_values, 0);
374
+ }
@@ -0,0 +1,59 @@
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
+ #ifndef __RP_CALL_INFO_H__
5
+ #define __RP_CALL_INFO_H__
6
+
7
+ #include "rp_measure.h"
8
+ #include "rp_method.h"
9
+
10
+ extern VALUE cCallInfo;
11
+
12
+ typedef struct prof_measure_value_t
13
+ {
14
+ double total;
15
+ double self;
16
+ double wait;
17
+ } prof_measure_value_t;
18
+
19
+ /* Callers and callee information for a method. */
20
+ typedef struct prof_call_info_t
21
+ {
22
+ prof_method_t *target; /* Use target instead of method to avoid conflict with Ruby method */
23
+ struct prof_call_info_t *parent;
24
+ st_table *call_infos;
25
+
26
+ VALUE object;
27
+ VALUE children;
28
+
29
+ int called;
30
+
31
+ unsigned int recursive : 1;
32
+ unsigned int depth : 15;
33
+ unsigned int line : 16;
34
+
35
+ size_t measures_len;
36
+ prof_measure_value_t measure_values[];
37
+ } prof_call_info_t;
38
+
39
+ /* Array of call_info objects */
40
+ typedef struct prof_call_infos_t
41
+ {
42
+ prof_call_info_t **start;
43
+ prof_call_info_t **end;
44
+ prof_call_info_t **ptr;
45
+ VALUE object;
46
+ } prof_call_infos_t;
47
+
48
+
49
+ void rp_init_call_info(void);
50
+ prof_call_infos_t* prof_call_infos_create();
51
+ void prof_call_infos_mark(prof_call_infos_t *call_infos);
52
+ void prof_call_infos_free(prof_call_infos_t *call_infos);
53
+ void prof_add_call_info(prof_call_infos_t *call_infos, prof_call_info_t *call_info);
54
+ VALUE prof_call_infos_wrap(prof_call_infos_t *call_infos);
55
+ prof_call_info_t * prof_call_info_create(prof_method_t* method, prof_call_info_t* parent, size_t measurements_len);
56
+ prof_call_info_t * call_info_table_lookup(st_table *table, const prof_method_key_t *key);
57
+ size_t call_info_table_insert(st_table *table, const prof_method_key_t *key, prof_call_info_t *val);
58
+
59
+ #endif //__RP_CALL_INFO_H__