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.
- data/CHANGES +483 -0
- data/LICENSE +25 -0
- data/README.rdoc +426 -0
- data/Rakefile +51 -0
- data/bin/ruby-prof +279 -0
- data/bin/ruby-prof-check-trace +45 -0
- data/examples/flat.txt +50 -0
- data/examples/graph.dot +84 -0
- data/examples/graph.html +823 -0
- data/examples/graph.txt +139 -0
- data/examples/multi.flat.txt +23 -0
- data/examples/multi.graph.html +760 -0
- data/examples/multi.grind.dat +114 -0
- data/examples/multi.stack.html +547 -0
- data/examples/stack.html +547 -0
- data/ext/ruby_prof/extconf.rb +67 -0
- data/ext/ruby_prof/rp_call_info.c +374 -0
- data/ext/ruby_prof/rp_call_info.h +59 -0
- data/ext/ruby_prof/rp_fast_call_tree_printer.c +247 -0
- data/ext/ruby_prof/rp_fast_call_tree_printer.h +10 -0
- data/ext/ruby_prof/rp_measure.c +71 -0
- data/ext/ruby_prof/rp_measure.h +56 -0
- data/ext/ruby_prof/rp_measure_allocations.c +74 -0
- data/ext/ruby_prof/rp_measure_cpu_time.c +134 -0
- data/ext/ruby_prof/rp_measure_gc_runs.c +71 -0
- data/ext/ruby_prof/rp_measure_gc_time.c +58 -0
- data/ext/ruby_prof/rp_measure_memory.c +75 -0
- data/ext/ruby_prof/rp_measure_process_time.c +69 -0
- data/ext/ruby_prof/rp_measure_wall_time.c +43 -0
- data/ext/ruby_prof/rp_method.c +717 -0
- data/ext/ruby_prof/rp_method.h +79 -0
- data/ext/ruby_prof/rp_stack.c +221 -0
- data/ext/ruby_prof/rp_stack.h +81 -0
- data/ext/ruby_prof/rp_thread.c +312 -0
- data/ext/ruby_prof/rp_thread.h +36 -0
- data/ext/ruby_prof/ruby_prof.c +800 -0
- data/ext/ruby_prof/ruby_prof.h +64 -0
- data/ext/ruby_prof/vc/ruby_prof.sln +32 -0
- data/ext/ruby_prof/vc/ruby_prof_18.vcxproj +108 -0
- data/ext/ruby_prof/vc/ruby_prof_19.vcxproj +110 -0
- data/ext/ruby_prof/vc/ruby_prof_20.vcxproj +110 -0
- data/lib/ruby-prof.rb +63 -0
- data/lib/ruby-prof/aggregate_call_info.rb +76 -0
- data/lib/ruby-prof/assets/call_stack_printer.css.html +117 -0
- data/lib/ruby-prof/assets/call_stack_printer.js.html +385 -0
- data/lib/ruby-prof/assets/call_stack_printer.png +0 -0
- data/lib/ruby-prof/assets/flame_graph_printer.lib.css.html +149 -0
- data/lib/ruby-prof/assets/flame_graph_printer.lib.js.html +707 -0
- data/lib/ruby-prof/assets/flame_graph_printer.page.js.html +56 -0
- data/lib/ruby-prof/assets/flame_graph_printer.tmpl.html.erb +39 -0
- data/lib/ruby-prof/call_info.rb +111 -0
- data/lib/ruby-prof/call_info_visitor.rb +40 -0
- data/lib/ruby-prof/compatibility.rb +186 -0
- data/lib/ruby-prof/method_info.rb +109 -0
- data/lib/ruby-prof/printers/abstract_printer.rb +85 -0
- data/lib/ruby-prof/printers/call_info_printer.rb +41 -0
- data/lib/ruby-prof/printers/call_stack_printer.rb +260 -0
- data/lib/ruby-prof/printers/call_tree_printer.rb +130 -0
- data/lib/ruby-prof/printers/dot_printer.rb +132 -0
- data/lib/ruby-prof/printers/fast_call_tree_printer.rb +87 -0
- data/lib/ruby-prof/printers/flame_graph_html_printer.rb +59 -0
- data/lib/ruby-prof/printers/flame_graph_json_printer.rb +157 -0
- data/lib/ruby-prof/printers/flat_printer.rb +70 -0
- data/lib/ruby-prof/printers/flat_printer_with_line_numbers.rb +64 -0
- data/lib/ruby-prof/printers/graph_html_printer.rb +244 -0
- data/lib/ruby-prof/printers/graph_printer.rb +116 -0
- data/lib/ruby-prof/printers/multi_printer.rb +58 -0
- data/lib/ruby-prof/profile.rb +22 -0
- data/lib/ruby-prof/profile/exclude_common_methods.rb +201 -0
- data/lib/ruby-prof/rack.rb +95 -0
- data/lib/ruby-prof/task.rb +147 -0
- data/lib/ruby-prof/thread.rb +35 -0
- data/lib/ruby-prof/version.rb +4 -0
- data/lib/ruby-prof/walker.rb +95 -0
- data/lib/unprof.rb +10 -0
- data/ruby-prof.gemspec +56 -0
- data/test/aggregate_test.rb +136 -0
- data/test/basic_test.rb +128 -0
- data/test/block_test.rb +74 -0
- data/test/call_info_test.rb +78 -0
- data/test/call_info_visitor_test.rb +31 -0
- data/test/duplicate_names_test.rb +32 -0
- data/test/dynamic_method_test.rb +55 -0
- data/test/enumerable_test.rb +21 -0
- data/test/exceptions_test.rb +16 -0
- data/test/exclude_methods_test.rb +146 -0
- data/test/exclude_threads_test.rb +53 -0
- data/test/fiber_test.rb +79 -0
- data/test/issue137_test.rb +63 -0
- data/test/line_number_test.rb +71 -0
- data/test/measure_allocations_test.rb +26 -0
- data/test/measure_cpu_time_test.rb +213 -0
- data/test/measure_gc_runs_test.rb +32 -0
- data/test/measure_gc_time_test.rb +36 -0
- data/test/measure_memory_test.rb +33 -0
- data/test/measure_process_time_test.rb +63 -0
- data/test/measure_wall_time_test.rb +255 -0
- data/test/module_test.rb +45 -0
- data/test/multi_measure_test.rb +38 -0
- data/test/multi_printer_test.rb +83 -0
- data/test/no_method_class_test.rb +15 -0
- data/test/pause_resume_test.rb +166 -0
- data/test/prime.rb +54 -0
- data/test/printers_test.rb +255 -0
- data/test/printing_recursive_graph_test.rb +127 -0
- data/test/rack_test.rb +93 -0
- data/test/recursive_test.rb +212 -0
- data/test/singleton_test.rb +38 -0
- data/test/stack_printer_test.rb +65 -0
- data/test/stack_test.rb +138 -0
- data/test/start_stop_test.rb +112 -0
- data/test/test_helper.rb +264 -0
- data/test/thread_test.rb +187 -0
- data/test/unique_call_path_test.rb +202 -0
- data/test/yarv_test.rb +55 -0
- 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__
|