airbnb-ruby-prof 0.0.1

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 (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__