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,247 @@
|
|
1
|
+
#include "ruby_prof.h"
|
2
|
+
#include "math.h"
|
3
|
+
|
4
|
+
VALUE cFastCallTreePrinter;
|
5
|
+
static ID id_addstr;
|
6
|
+
|
7
|
+
/* Utility struct to mirror the require ivars in the ruby class.
|
8
|
+
|
9
|
+
output is a ruby IO object
|
10
|
+
|
11
|
+
value_scale is the conversion factor used to scale the result for rounding.
|
12
|
+
This is set based on the measure mode. */
|
13
|
+
typedef struct call_tree_printer_vars
|
14
|
+
{
|
15
|
+
VALUE output;
|
16
|
+
size_t len;
|
17
|
+
double value_scales[];
|
18
|
+
} call_tree_printer_vars;
|
19
|
+
|
20
|
+
static call_tree_printer_vars *
|
21
|
+
call_tree_printer_vars_allocate(size_t len)
|
22
|
+
{
|
23
|
+
call_tree_printer_vars *result =
|
24
|
+
(call_tree_printer_vars*) ruby_xmalloc(
|
25
|
+
sizeof(call_tree_printer_vars) + len * sizeof(double));
|
26
|
+
result->len = len;
|
27
|
+
return result;
|
28
|
+
}
|
29
|
+
|
30
|
+
/* Converts the recorded value to a fixed point number based on value scale */
|
31
|
+
static long int
|
32
|
+
convert(double value, double value_scale)
|
33
|
+
{
|
34
|
+
return lround(value * value_scale);
|
35
|
+
}
|
36
|
+
|
37
|
+
static VALUE
|
38
|
+
addstr(VALUE io, VALUE str)
|
39
|
+
{
|
40
|
+
return rb_funcall(io, id_addstr, 1, str);
|
41
|
+
}
|
42
|
+
|
43
|
+
static void
|
44
|
+
print_header(
|
45
|
+
call_tree_printer_vars *vars,
|
46
|
+
prof_method_t *method,
|
47
|
+
char *name)
|
48
|
+
{
|
49
|
+
/* Format is file and method name followed by line and self time */
|
50
|
+
addstr(
|
51
|
+
vars->output,
|
52
|
+
rb_sprintf(
|
53
|
+
"fl=%s\nfn=%s\n%d",
|
54
|
+
prof_method_t_source_file(method),
|
55
|
+
name,
|
56
|
+
method->line));
|
57
|
+
}
|
58
|
+
|
59
|
+
/* Returns the index of the callee in the call_infos list. */
|
60
|
+
static int
|
61
|
+
call_info_index(prof_call_infos_t *call_infos, prof_call_info_t *callee)
|
62
|
+
{
|
63
|
+
prof_call_info_t **i;
|
64
|
+
for (i = call_infos->start; i < call_infos->ptr; i++) {
|
65
|
+
if ((*i) == callee) {
|
66
|
+
return i - call_infos->start;
|
67
|
+
}
|
68
|
+
}
|
69
|
+
|
70
|
+
return -1;
|
71
|
+
}
|
72
|
+
|
73
|
+
static void
|
74
|
+
print_child(call_tree_printer_vars *vars, prof_call_info_t *callee)
|
75
|
+
{
|
76
|
+
prof_method_t *target = callee->target;
|
77
|
+
VALUE name = prof_method_t_calltree_name(target);
|
78
|
+
|
79
|
+
if (target->recursive) {
|
80
|
+
int index = call_info_index(target->call_infos, callee);
|
81
|
+
name = rb_sprintf("%s [%d]", RSTRING_PTR(name), index);
|
82
|
+
}
|
83
|
+
|
84
|
+
addstr(
|
85
|
+
vars->output,
|
86
|
+
rb_sprintf(
|
87
|
+
"cfl=%s\ncfn=%s\ncalls=%d %d\n%d",
|
88
|
+
prof_method_t_source_file(target),
|
89
|
+
RSTRING_PTR(name),
|
90
|
+
callee->called,
|
91
|
+
callee->line,
|
92
|
+
callee->line));
|
93
|
+
|
94
|
+
for(size_t i = 0; i < callee->measures_len; i++) {
|
95
|
+
addstr(
|
96
|
+
vars->output,
|
97
|
+
rb_sprintf(
|
98
|
+
" %ld",
|
99
|
+
convert(callee->measure_values[i].total, vars->value_scales[i])));
|
100
|
+
}
|
101
|
+
addstr(vars->output, rb_str_new2("\n"));
|
102
|
+
|
103
|
+
RB_GC_GUARD(name);
|
104
|
+
}
|
105
|
+
|
106
|
+
/* Function to be called by st_foreach to print each child call info */
|
107
|
+
static int
|
108
|
+
print_child_iter(st_data_t key, st_data_t value, st_data_t vars)
|
109
|
+
{
|
110
|
+
print_child((call_tree_printer_vars *) vars, (prof_call_info_t *) value);
|
111
|
+
return ST_CONTINUE;
|
112
|
+
}
|
113
|
+
|
114
|
+
static void
|
115
|
+
print_simple_method(call_tree_printer_vars *vars, prof_method_t *method)
|
116
|
+
{
|
117
|
+
VALUE calltree_name = prof_method_t_calltree_name(method);
|
118
|
+
size_t measures_len = (*method->call_infos->start)->measures_len;
|
119
|
+
|
120
|
+
print_header(vars, method, RSTRING_PTR(calltree_name));
|
121
|
+
for(size_t j = 0; j < measures_len; j++) {
|
122
|
+
addstr(vars->output,
|
123
|
+
rb_sprintf(" %ld", convert(prof_method_t_self_time(method, j), vars->value_scales[j])));
|
124
|
+
}
|
125
|
+
addstr(vars->output, rb_str_new2("\n"));
|
126
|
+
|
127
|
+
prof_call_info_t **i;
|
128
|
+
for(i = method->call_infos->start; i < method->call_infos->ptr; i++) {
|
129
|
+
st_foreach((*i)->call_infos, print_child_iter, (uintptr_t) vars);
|
130
|
+
}
|
131
|
+
|
132
|
+
RB_GC_GUARD(calltree_name);
|
133
|
+
}
|
134
|
+
|
135
|
+
static void
|
136
|
+
print_recursive_method(call_tree_printer_vars *vars, prof_method_t *method)
|
137
|
+
{
|
138
|
+
VALUE calltree_name = prof_method_t_calltree_name(method);
|
139
|
+
|
140
|
+
prof_call_info_t **i;
|
141
|
+
for(i = method->call_infos->start; i < method->call_infos->ptr; i++) {
|
142
|
+
int index = i - method->call_infos->start;
|
143
|
+
VALUE name = rb_sprintf("%s [%d]", RSTRING_PTR(calltree_name), index);
|
144
|
+
|
145
|
+
print_header(vars, method, RSTRING_PTR(name));
|
146
|
+
for(size_t j = 0; j < (*i)->measures_len; j++) {
|
147
|
+
addstr(vars->output,
|
148
|
+
rb_sprintf(" %ld", convert((*i)->measure_values[j].self, vars->value_scales[j])));
|
149
|
+
}
|
150
|
+
addstr(vars->output, rb_str_new2("\n"));
|
151
|
+
|
152
|
+
st_foreach((*i)->call_infos, print_child_iter, (uintptr_t) vars);
|
153
|
+
|
154
|
+
RB_GC_GUARD(name);
|
155
|
+
}
|
156
|
+
|
157
|
+
RB_GC_GUARD(calltree_name);
|
158
|
+
}
|
159
|
+
|
160
|
+
static int
|
161
|
+
print_method(call_tree_printer_vars *vars, prof_method_t *method)
|
162
|
+
{
|
163
|
+
if(!method->excluded) {
|
164
|
+
if (method->recursive) {
|
165
|
+
print_recursive_method(vars, method);
|
166
|
+
} else {
|
167
|
+
print_simple_method(vars, method);
|
168
|
+
}
|
169
|
+
|
170
|
+
addstr(vars->output, rb_str_new2("\n"));
|
171
|
+
}
|
172
|
+
|
173
|
+
return ST_CONTINUE;
|
174
|
+
}
|
175
|
+
|
176
|
+
/* Iterator to handle reversing an st_table of methods into a provided array */
|
177
|
+
static int
|
178
|
+
reverse_methods(st_data_t key, st_data_t value, st_data_t arg)
|
179
|
+
{
|
180
|
+
prof_method_t ***methods = (prof_method_t ***) arg;
|
181
|
+
|
182
|
+
prof_method_t *method = (prof_method_t *) value;
|
183
|
+
|
184
|
+
*methods = *methods - 1;
|
185
|
+
**methods = method;
|
186
|
+
|
187
|
+
return ST_CONTINUE;
|
188
|
+
}
|
189
|
+
|
190
|
+
static void
|
191
|
+
print_methods_in_reverse(call_tree_printer_vars *vars, st_table *method_table)
|
192
|
+
{
|
193
|
+
st_index_t num_entries = method_table->num_entries;
|
194
|
+
|
195
|
+
prof_method_t **reversed = ALLOC_N(prof_method_t*, num_entries);
|
196
|
+
prof_method_t **end = reversed + num_entries;
|
197
|
+
|
198
|
+
prof_method_t **iterator = end;
|
199
|
+
|
200
|
+
st_foreach(method_table, reverse_methods, (uintptr_t) &iterator);
|
201
|
+
|
202
|
+
prof_method_t **i;
|
203
|
+
for(i = reversed; i < end; i++) {
|
204
|
+
print_method(vars, *i);
|
205
|
+
}
|
206
|
+
|
207
|
+
xfree(reversed);
|
208
|
+
}
|
209
|
+
|
210
|
+
|
211
|
+
/* call-seq:
|
212
|
+
print_thread(thread) -> nil
|
213
|
+
|
214
|
+
Prints to @output the call tree of a thread
|
215
|
+
*/
|
216
|
+
VALUE
|
217
|
+
prof_fast_call_tree_printer_print_thread(VALUE self, VALUE thread) {
|
218
|
+
thread_data_t *thread_data = prof_get_thread(thread);
|
219
|
+
|
220
|
+
VALUE output = rb_iv_get(self, "@output");
|
221
|
+
VALUE value_scales_val = rb_iv_get(self, "@value_scales");
|
222
|
+
|
223
|
+
Check_Type(value_scales_val, T_ARRAY);
|
224
|
+
size_t value_scales_len = RARRAY_LEN(value_scales_val);
|
225
|
+
|
226
|
+
call_tree_printer_vars *vars = call_tree_printer_vars_allocate(value_scales_len);
|
227
|
+
vars->output = output;
|
228
|
+
for(size_t i = 0; i < value_scales_len; i++) {
|
229
|
+
vars->value_scales[i] = NUM2DBL(rb_ary_entry(value_scales_val, i));
|
230
|
+
}
|
231
|
+
|
232
|
+
print_methods_in_reverse(vars, thread_data->method_table);
|
233
|
+
|
234
|
+
xfree(vars);
|
235
|
+
|
236
|
+
return Qnil;
|
237
|
+
}
|
238
|
+
|
239
|
+
void rp_init_fast_call_tree_printer()
|
240
|
+
{
|
241
|
+
id_addstr = rb_intern("<<");
|
242
|
+
|
243
|
+
cFastCallTreePrinter = rb_define_class_under(mProf,
|
244
|
+
"FastCallTreePrinter", rb_cObject);
|
245
|
+
rb_define_method(cFastCallTreePrinter, "print_thread",
|
246
|
+
prof_fast_call_tree_printer_print_thread, 1);
|
247
|
+
}
|
@@ -0,0 +1,71 @@
|
|
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
|
+
VALUE mMeasure;
|
7
|
+
|
8
|
+
prof_measurer_t*
|
9
|
+
prof_measurer_allocate(size_t len)
|
10
|
+
{
|
11
|
+
prof_measurer_t* result =
|
12
|
+
(prof_measurer_t*) ruby_xmalloc(
|
13
|
+
sizeof(prof_measurer_t) + len * sizeof(get_measurement));
|
14
|
+
result->len = len;
|
15
|
+
return result;
|
16
|
+
}
|
17
|
+
|
18
|
+
prof_measurer_t* prof_get_measurer(prof_measure_mode_t* measures, size_t len)
|
19
|
+
{
|
20
|
+
prof_measurer_t* measurer = prof_measurer_allocate(len);
|
21
|
+
measurer->measure_modes = measures;
|
22
|
+
|
23
|
+
for (size_t i = 0; i < len; i++) {
|
24
|
+
switch (measures[i]) {
|
25
|
+
case MEASURE_WALL_TIME:
|
26
|
+
measurer->measures[i] = prof_measurer_wall_time();
|
27
|
+
break;
|
28
|
+
case MEASURE_PROCESS_TIME:
|
29
|
+
measurer->measures[i] = prof_measurer_process_time();
|
30
|
+
break;
|
31
|
+
case MEASURE_CPU_TIME:
|
32
|
+
measurer->measures[i] = prof_measurer_cpu_time();
|
33
|
+
break;
|
34
|
+
case MEASURE_ALLOCATIONS:
|
35
|
+
measurer->measures[i] = prof_measurer_allocations();
|
36
|
+
break;
|
37
|
+
case MEASURE_MEMORY:
|
38
|
+
measurer->measures[i] = prof_measurer_memory();
|
39
|
+
break;
|
40
|
+
case MEASURE_GC_TIME:
|
41
|
+
measurer->measures[i] = prof_measurer_gc_time();
|
42
|
+
break;
|
43
|
+
case MEASURE_GC_RUNS:
|
44
|
+
measurer->measures[i] = prof_measurer_gc_runs();
|
45
|
+
break;
|
46
|
+
default:
|
47
|
+
rb_raise(rb_eArgError, "Unknown measure mode: %d", measures[i]);
|
48
|
+
}
|
49
|
+
}
|
50
|
+
|
51
|
+
return measurer;
|
52
|
+
};
|
53
|
+
|
54
|
+
void prof_measurer_take_measurements(prof_measurer_t* measurer, prof_measurements_t* dest)
|
55
|
+
{
|
56
|
+
for (size_t i = 0; i < measurer->len; i++) {
|
57
|
+
dest->values[i] = measurer->measures[i]();
|
58
|
+
}
|
59
|
+
}
|
60
|
+
|
61
|
+
void rp_init_measure()
|
62
|
+
{
|
63
|
+
mMeasure = rb_define_module_under(mProf, "Measure");
|
64
|
+
rp_init_measure_wall_time();
|
65
|
+
rp_init_measure_cpu_time();
|
66
|
+
rp_init_measure_process_time();
|
67
|
+
rp_init_measure_allocations();
|
68
|
+
rp_init_measure_memory();
|
69
|
+
rp_init_measure_gc_time();
|
70
|
+
rp_init_measure_gc_runs();
|
71
|
+
}
|
@@ -0,0 +1,56 @@
|
|
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_MEASUREMENT_H__
|
5
|
+
#define __RP_MEASUREMENT_H__
|
6
|
+
|
7
|
+
extern VALUE mMeasure;
|
8
|
+
|
9
|
+
typedef struct
|
10
|
+
{
|
11
|
+
size_t len;
|
12
|
+
double values[];
|
13
|
+
} prof_measurements_t;
|
14
|
+
|
15
|
+
typedef double (*get_measurement)();
|
16
|
+
|
17
|
+
typedef enum
|
18
|
+
{
|
19
|
+
MEASURE_WALL_TIME,
|
20
|
+
MEASURE_PROCESS_TIME,
|
21
|
+
MEASURE_CPU_TIME,
|
22
|
+
MEASURE_ALLOCATIONS,
|
23
|
+
MEASURE_MEMORY,
|
24
|
+
MEASURE_GC_TIME,
|
25
|
+
MEASURE_GC_RUNS,
|
26
|
+
} prof_measure_mode_t;
|
27
|
+
|
28
|
+
typedef struct
|
29
|
+
{
|
30
|
+
size_t len;
|
31
|
+
prof_measure_mode_t* measure_modes;
|
32
|
+
get_measurement measures[];
|
33
|
+
} prof_measurer_t;
|
34
|
+
|
35
|
+
|
36
|
+
prof_measurer_t* prof_get_measurer(prof_measure_mode_t* measures, size_t len);
|
37
|
+
get_measurement prof_measurer_allocations();
|
38
|
+
get_measurement prof_measurer_cpu_time();
|
39
|
+
get_measurement prof_measurer_gc_runs();
|
40
|
+
get_measurement prof_measurer_gc_time();
|
41
|
+
get_measurement prof_measurer_memory();
|
42
|
+
get_measurement prof_measurer_process_time();
|
43
|
+
get_measurement prof_measurer_wall_time();
|
44
|
+
|
45
|
+
void prof_measurer_take_measurements(prof_measurer_t* measurer, prof_measurements_t* dest);
|
46
|
+
|
47
|
+
void rp_init_measure();
|
48
|
+
void rp_init_measure_allocations();
|
49
|
+
void rp_init_measure_cpu_time();
|
50
|
+
void rp_init_measure_gc_runs();
|
51
|
+
void rp_init_measure_gc_time();
|
52
|
+
void rp_init_measure_memory();
|
53
|
+
void rp_init_measure_process_time();
|
54
|
+
void rp_init_measure_wall_time();
|
55
|
+
|
56
|
+
#endif //__RP_MEASUREMENT_H__
|
@@ -0,0 +1,74 @@
|
|
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
|
+
/* :nodoc: */
|
5
|
+
|
6
|
+
#include "ruby_prof.h"
|
7
|
+
|
8
|
+
static VALUE cMeasureAllocations;
|
9
|
+
|
10
|
+
#if defined(HAVE_RB_OS_ALLOCATED_OBJECTS)
|
11
|
+
unsigned LONG_LONG rb_os_allocated_objects();
|
12
|
+
#endif
|
13
|
+
|
14
|
+
#if defined(HAVE_RB_GC_STAT)
|
15
|
+
size_t rb_gc_stat(VALUE key);
|
16
|
+
|
17
|
+
#if RUBY_PROF_RUBY_VERSION >= 20200
|
18
|
+
#define TOTAL_ALLOCATED_OBJECTS_STRING "total_allocated_objects"
|
19
|
+
#else
|
20
|
+
#define TOTAL_ALLOCATED_OBJECTS_STRING "total_allocated_object"
|
21
|
+
#endif
|
22
|
+
|
23
|
+
#endif
|
24
|
+
|
25
|
+
static double
|
26
|
+
measure_allocations()
|
27
|
+
{
|
28
|
+
#if defined(HAVE_RB_OS_ALLOCATED_OBJECTS)
|
29
|
+
#define MEASURE_ALLOCATIONS_ENABLED Qtrue
|
30
|
+
return rb_os_allocated_objects();
|
31
|
+
|
32
|
+
#elif defined(HAVE_RB_GC_STAT) && RUBY_PROF_RUBY_VERSION >= 20100
|
33
|
+
#define MEASURE_ALLOCATIONS_ENABLED Qtrue
|
34
|
+
static VALUE total_alloc_symbol = 0;
|
35
|
+
if (!total_alloc_symbol) {
|
36
|
+
total_alloc_symbol = ID2SYM(rb_intern_const(TOTAL_ALLOCATED_OBJECTS_STRING));
|
37
|
+
}
|
38
|
+
return rb_gc_stat(total_alloc_symbol);
|
39
|
+
|
40
|
+
#else
|
41
|
+
#define MEASURE_ALLOCATIONS_ENABLED Qfalse
|
42
|
+
return 0;
|
43
|
+
#endif
|
44
|
+
}
|
45
|
+
|
46
|
+
|
47
|
+
get_measurement prof_measurer_allocations()
|
48
|
+
{
|
49
|
+
return measure_allocations;
|
50
|
+
}
|
51
|
+
|
52
|
+
/* call-seq:
|
53
|
+
measure -> int
|
54
|
+
|
55
|
+
Returns the number of Ruby object allocations. */
|
56
|
+
|
57
|
+
static VALUE
|
58
|
+
prof_measure_allocations(VALUE self)
|
59
|
+
{
|
60
|
+
#if defined(HAVE_LONG_LONG)
|
61
|
+
return ULL2NUM(measure_allocations());
|
62
|
+
#else
|
63
|
+
return ULONG2NUM(measure_allocations());
|
64
|
+
#endif
|
65
|
+
}
|
66
|
+
|
67
|
+
void rp_init_measure_allocations()
|
68
|
+
{
|
69
|
+
rb_define_const(mProf, "ALLOCATIONS", INT2NUM(MEASURE_ALLOCATIONS));
|
70
|
+
rb_define_const(mProf, "ALLOCATIONS_ENABLED", MEASURE_ALLOCATIONS_ENABLED);
|
71
|
+
|
72
|
+
cMeasureAllocations = rb_define_class_under(mMeasure, "Allocations", rb_cObject);
|
73
|
+
rb_define_singleton_method(cMeasureAllocations, "measure", prof_measure_allocations, 0);
|
74
|
+
}
|