ruby-prof 0.18.0 → 1.0.0
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.
- checksums.yaml +4 -4
- data/CHANGES +23 -0
- data/LICENSE +2 -2
- data/README.rdoc +1 -483
- data/Rakefile +3 -6
- data/bin/ruby-prof +65 -30
- data/ext/ruby_prof/extconf.rb +6 -38
- data/ext/ruby_prof/rp_allocation.c +292 -0
- data/ext/ruby_prof/rp_allocation.h +31 -0
- data/ext/ruby_prof/rp_call_info.c +137 -279
- data/ext/ruby_prof/rp_call_info.h +16 -34
- data/ext/ruby_prof/rp_measure_allocations.c +25 -49
- data/ext/ruby_prof/rp_measure_memory.c +21 -56
- data/ext/ruby_prof/rp_measure_process_time.c +28 -36
- data/ext/ruby_prof/rp_measure_wall_time.c +36 -19
- data/ext/ruby_prof/rp_measurement.c +236 -0
- data/ext/ruby_prof/rp_measurement.h +49 -0
- data/ext/ruby_prof/rp_method.c +395 -383
- data/ext/ruby_prof/rp_method.h +34 -39
- data/ext/ruby_prof/rp_profile.c +881 -0
- data/ext/ruby_prof/rp_profile.h +36 -0
- data/ext/ruby_prof/rp_stack.c +103 -80
- data/ext/ruby_prof/rp_stack.h +5 -12
- data/ext/ruby_prof/rp_thread.c +149 -88
- data/ext/ruby_prof/rp_thread.h +15 -6
- data/ext/ruby_prof/ruby_prof.c +11 -757
- data/ext/ruby_prof/ruby_prof.h +4 -47
- data/ext/ruby_prof/vc/ruby_prof.vcxproj +10 -8
- data/lib/ruby-prof.rb +2 -17
- data/lib/ruby-prof/assets/graph_printer.html.erb +356 -0
- data/lib/ruby-prof/call_info.rb +35 -93
- data/lib/ruby-prof/call_info_visitor.rb +19 -21
- data/lib/ruby-prof/compatibility.rb +37 -107
- data/lib/ruby-prof/exclude_common_methods.rb +198 -0
- data/lib/ruby-prof/measurement.rb +14 -0
- data/lib/ruby-prof/method_info.rb +52 -83
- data/lib/ruby-prof/printers/abstract_printer.rb +66 -52
- data/lib/ruby-prof/printers/call_info_printer.rb +13 -3
- data/lib/ruby-prof/printers/call_stack_printer.rb +32 -28
- data/lib/ruby-prof/printers/call_tree_printer.rb +20 -12
- data/lib/ruby-prof/printers/dot_printer.rb +5 -5
- data/lib/ruby-prof/printers/flat_printer.rb +6 -24
- data/lib/ruby-prof/printers/graph_html_printer.rb +7 -192
- data/lib/ruby-prof/printers/graph_printer.rb +13 -15
- data/lib/ruby-prof/printers/multi_printer.rb +66 -23
- data/lib/ruby-prof/profile.rb +10 -3
- data/lib/ruby-prof/rack.rb +0 -3
- data/lib/ruby-prof/thread.rb +12 -12
- data/lib/ruby-prof/version.rb +1 -1
- data/ruby-prof.gemspec +2 -2
- data/test/abstract_printer_test.rb +0 -27
- data/test/alias_test.rb +129 -0
- data/test/basic_test.rb +41 -40
- data/test/call_info_visitor_test.rb +3 -3
- data/test/dynamic_method_test.rb +0 -2
- data/test/line_number_test.rb +120 -39
- data/test/marshal_test.rb +119 -0
- data/test/measure_allocations.rb +30 -0
- data/test/measure_allocations_test.rb +371 -12
- data/test/measure_allocations_trace_test.rb +385 -0
- data/test/measure_memory_trace_test.rb +756 -0
- data/test/measure_process_time_test.rb +821 -33
- data/test/measure_times.rb +54 -0
- data/test/measure_wall_time_test.rb +349 -145
- data/test/multi_printer_test.rb +1 -34
- data/test/parser_timings.rb +24 -0
- data/test/pause_resume_test.rb +5 -5
- data/test/prime.rb +2 -0
- data/test/printer_call_tree_test.rb +31 -0
- data/test/printer_flat_test.rb +68 -0
- data/test/printer_graph_html_test.rb +60 -0
- data/test/printer_graph_test.rb +41 -0
- data/test/printers_test.rb +32 -166
- data/test/printing_recursive_graph_test.rb +26 -72
- data/test/recursive_test.rb +72 -77
- data/test/stack_printer_test.rb +2 -15
- data/test/start_stop_test.rb +22 -25
- data/test/test_helper.rb +5 -248
- data/test/thread_test.rb +11 -54
- data/test/unique_call_path_test.rb +16 -28
- data/test/yarv_test.rb +1 -0
- metadata +24 -34
- data/examples/flat.txt +0 -50
- data/examples/graph.dot +0 -84
- data/examples/graph.html +0 -823
- data/examples/graph.txt +0 -139
- data/examples/multi.flat.txt +0 -23
- data/examples/multi.graph.html +0 -760
- data/examples/multi.grind.dat +0 -114
- data/examples/multi.stack.html +0 -547
- data/examples/stack.html +0 -547
- data/ext/ruby_prof/rp_measure.c +0 -40
- data/ext/ruby_prof/rp_measure.h +0 -45
- data/ext/ruby_prof/rp_measure_cpu_time.c +0 -136
- data/ext/ruby_prof/rp_measure_gc_runs.c +0 -73
- data/ext/ruby_prof/rp_measure_gc_time.c +0 -60
- data/lib/ruby-prof/aggregate_call_info.rb +0 -76
- data/lib/ruby-prof/printers/flat_printer_with_line_numbers.rb +0 -83
- data/lib/ruby-prof/profile/exclude_common_methods.rb +0 -207
- data/lib/ruby-prof/profile/legacy_method_elimination.rb +0 -50
- data/test/aggregate_test.rb +0 -136
- data/test/block_test.rb +0 -74
- data/test/call_info_test.rb +0 -78
- data/test/fiber_test.rb +0 -79
- data/test/issue137_test.rb +0 -63
- data/test/measure_cpu_time_test.rb +0 -212
- data/test/measure_gc_runs_test.rb +0 -32
- data/test/measure_gc_time_test.rb +0 -36
- data/test/measure_memory_test.rb +0 -33
- data/test/method_elimination_test.rb +0 -84
- data/test/module_test.rb +0 -45
- data/test/stack_test.rb +0 -138
@@ -0,0 +1,49 @@
|
|
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_measurementMENT_H__
|
5
|
+
#define __rp_measurementMENT_H__
|
6
|
+
|
7
|
+
#include "ruby_prof.h"
|
8
|
+
|
9
|
+
extern VALUE mMeasure;
|
10
|
+
|
11
|
+
typedef double (*get_measurement)(rb_trace_arg_t *trace_arg);
|
12
|
+
|
13
|
+
typedef enum
|
14
|
+
{
|
15
|
+
MEASURE_WALL_TIME,
|
16
|
+
MEASURE_PROCESS_TIME,
|
17
|
+
MEASURE_ALLOCATIONS,
|
18
|
+
MEASURE_MEMORY
|
19
|
+
} prof_measure_mode_t;
|
20
|
+
|
21
|
+
typedef struct
|
22
|
+
{
|
23
|
+
get_measurement measure;
|
24
|
+
prof_measure_mode_t mode;
|
25
|
+
double multiplier;
|
26
|
+
bool track_allocations;
|
27
|
+
} prof_measurer_t;
|
28
|
+
|
29
|
+
/* Callers and callee information for a method. */
|
30
|
+
typedef struct prof_measurement_t
|
31
|
+
{
|
32
|
+
double total_time;
|
33
|
+
double self_time;
|
34
|
+
double wait_time;
|
35
|
+
int called;
|
36
|
+
VALUE object;
|
37
|
+
} prof_measurement_t;
|
38
|
+
|
39
|
+
prof_measurer_t *prof_get_measurer(prof_measure_mode_t measure, bool track_allocations);
|
40
|
+
double prof_measure(prof_measurer_t *measurer, rb_trace_arg_t* trace_arg);
|
41
|
+
|
42
|
+
prof_measurement_t *prof_measurement_create(void);
|
43
|
+
VALUE prof_measurement_wrap(prof_measurement_t *measurement);
|
44
|
+
prof_measurement_t* prof_get_measurement(VALUE self);
|
45
|
+
void prof_measurement_mark(void *data);
|
46
|
+
|
47
|
+
void rp_init_measure(void);
|
48
|
+
|
49
|
+
#endif //__rp_measurementMENT_H__
|
data/ext/ruby_prof/rp_method.c
CHANGED
@@ -1,250 +1,229 @@
|
|
1
1
|
/* Copyright (C) 2005-2019 Shugo Maeda <shugo@ruby-lang.org> and Charlie Savage <cfis@savagexi.com>
|
2
2
|
Please see the LICENSE file for copyright and distribution information */
|
3
3
|
|
4
|
-
#include "
|
4
|
+
#include "rp_allocation.h"
|
5
|
+
#include "rp_call_info.h"
|
6
|
+
#include "rp_method.h"
|
5
7
|
|
6
|
-
|
7
|
-
#define RP_REL_SET(r, off) \
|
8
|
-
do { \
|
9
|
-
r |= (1 << (off)); \
|
10
|
-
} while (0)
|
11
|
-
|
12
|
-
VALUE cMethodInfo;
|
8
|
+
VALUE cRpMethodInfo;
|
13
9
|
|
14
10
|
/* ================ Helper Functions =================*/
|
15
|
-
|
16
|
-
|
11
|
+
VALUE
|
12
|
+
resolve_klass(VALUE klass, unsigned int *klass_flags)
|
17
13
|
{
|
18
|
-
|
19
|
-
volatile VALUE attached_str, super_str;
|
20
|
-
volatile VALUE result = Qnil;
|
21
|
-
|
22
|
-
/* We have come across a singleton object. First
|
23
|
-
figure out what it is attached to.*/
|
24
|
-
attached = rb_iv_get(klass, "__attached__");
|
14
|
+
VALUE result = klass;
|
25
15
|
|
26
|
-
|
27
|
-
if (BUILTIN_TYPE(attached) == T_CLASS)
|
16
|
+
if (klass == 0 || klass == Qnil)
|
28
17
|
{
|
29
|
-
|
30
|
-
result = rb_str_new2("<Class::");
|
31
|
-
rb_str_append(result, attached_str);
|
32
|
-
rb_str_cat2(result, ">");
|
18
|
+
result = Qnil;
|
33
19
|
}
|
34
|
-
|
35
|
-
/* Is this for singleton methods on a module? */
|
36
|
-
else if (BUILTIN_TYPE(attached) == T_MODULE)
|
20
|
+
else if (BUILTIN_TYPE(klass) == T_CLASS && FL_TEST(klass, FL_SINGLETON))
|
37
21
|
{
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
rb_str_cat2(result, ">");
|
42
|
-
}
|
22
|
+
/* We have come across a singleton object. First
|
23
|
+
figure out what it is attached to.*/
|
24
|
+
VALUE attached = rb_iv_get(klass, "__attached__");
|
43
25
|
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
26
|
+
/* Is this a singleton class acting as a metaclass? */
|
27
|
+
if (BUILTIN_TYPE(attached) == T_CLASS)
|
28
|
+
{
|
29
|
+
*klass_flags |= kClassSingleton;
|
30
|
+
result = attached;
|
31
|
+
}
|
32
|
+
/* Is this for singleton methods on a module? */
|
33
|
+
else if (BUILTIN_TYPE(attached) == T_MODULE)
|
34
|
+
{
|
35
|
+
*klass_flags |= kModuleSingleton;
|
36
|
+
result = attached;
|
37
|
+
}
|
38
|
+
/* Is this for singleton methods on an object? */
|
39
|
+
else if (BUILTIN_TYPE(attached) == T_OBJECT)
|
40
|
+
{
|
41
|
+
*klass_flags |= kObjectSingleton;
|
42
|
+
result = rb_class_superclass(klass);
|
43
|
+
}
|
44
|
+
/* Ok, this could be other things like an array made put onto
|
45
|
+
a singleton object (yeah, it happens, see the singleton
|
46
|
+
objects test case). */
|
47
|
+
else
|
48
|
+
{
|
49
|
+
*klass_flags |= kOtherSingleton;
|
50
|
+
result = klass;
|
51
|
+
}
|
55
52
|
}
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
else
|
53
|
+
/* Is this an include for a module? If so get the actual
|
54
|
+
module class since we want to combine all profiling
|
55
|
+
results for that module. */
|
56
|
+
else if (BUILTIN_TYPE(klass) == T_ICLASS)
|
61
57
|
{
|
62
|
-
|
58
|
+
unsigned int dummy;
|
59
|
+
*klass_flags |= kModuleIncludee;
|
60
|
+
result = resolve_klass(RBASIC(klass)->klass, &dummy);
|
63
61
|
}
|
64
|
-
|
65
62
|
return result;
|
66
63
|
}
|
67
64
|
|
68
|
-
|
69
|
-
|
65
|
+
VALUE
|
66
|
+
resolve_klass_name(VALUE klass, unsigned int* klass_flags)
|
70
67
|
{
|
71
|
-
|
68
|
+
VALUE result = Qnil;
|
72
69
|
|
73
|
-
if (klass ==
|
70
|
+
if (klass == Qnil)
|
74
71
|
{
|
75
72
|
result = rb_str_new2("[global]");
|
76
73
|
}
|
77
|
-
else if (
|
74
|
+
else if (*klass_flags & kOtherSingleton)
|
78
75
|
{
|
79
|
-
result =
|
80
|
-
}
|
81
|
-
else if (BUILTIN_TYPE(klass) == T_CLASS && FL_TEST(klass, FL_SINGLETON))
|
82
|
-
{
|
83
|
-
result = figure_singleton_name(klass);
|
84
|
-
}
|
85
|
-
else if (BUILTIN_TYPE(klass) == T_CLASS)
|
86
|
-
{
|
87
|
-
result = rb_class_name(klass);
|
76
|
+
result = rb_any_to_s(klass);
|
88
77
|
}
|
89
78
|
else
|
90
79
|
{
|
91
|
-
|
92
|
-
result = rb_str_new2("[unknown]");
|
80
|
+
result = rb_class_name(klass);
|
93
81
|
}
|
94
82
|
|
95
83
|
return result;
|
96
84
|
}
|
97
85
|
|
98
|
-
|
99
|
-
|
86
|
+
st_data_t
|
87
|
+
method_key(VALUE klass, VALUE msym)
|
100
88
|
{
|
101
|
-
|
89
|
+
VALUE resolved_klass = klass;
|
102
90
|
|
103
|
-
|
104
|
-
|
105
|
-
|
106
|
-
|
107
|
-
|
91
|
+
/* Is this an include for a module? If so get the actual
|
92
|
+
module class since we want to combine all profiling
|
93
|
+
results for that module. */
|
94
|
+
if (klass == 0 || klass == Qnil)
|
95
|
+
{
|
96
|
+
resolved_klass = Qnil;
|
108
97
|
}
|
98
|
+
else if (BUILTIN_TYPE(klass) == T_ICLASS)
|
99
|
+
{
|
100
|
+
resolved_klass = RBASIC(klass)->klass;
|
101
|
+
}
|
102
|
+
|
103
|
+
return (resolved_klass << 4) + (msym);
|
109
104
|
}
|
110
105
|
|
111
|
-
|
112
|
-
|
106
|
+
/* ====== Allocation Table ====== */
|
107
|
+
st_table*
|
108
|
+
allocations_table_create()
|
113
109
|
{
|
114
|
-
|
115
|
-
|
116
|
-
|
117
|
-
klass_str = klass_name(klass);
|
118
|
-
method_str = method_name(mid);
|
119
|
-
|
120
|
-
result = rb_str_dup(klass_str);
|
121
|
-
rb_str_cat2(result, "#");
|
122
|
-
rb_str_append(result, method_str);
|
110
|
+
return st_init_numtable();
|
111
|
+
}
|
123
112
|
|
124
|
-
|
113
|
+
static int
|
114
|
+
allocations_table_free_iterator(st_data_t key, st_data_t value, st_data_t dummy)
|
115
|
+
{
|
116
|
+
prof_allocation_free((prof_allocation_t*)value);
|
117
|
+
return ST_CONTINUE;
|
125
118
|
}
|
126
119
|
|
127
|
-
static
|
128
|
-
|
120
|
+
static int
|
121
|
+
prof_method_collect_allocations(st_data_t key, st_data_t value, st_data_t result)
|
129
122
|
{
|
130
|
-
|
131
|
-
|
132
|
-
|
133
|
-
|
134
|
-
klass_str = rb_class_name(source_klass);
|
135
|
-
result = rb_str_dup(klass_str);
|
136
|
-
} else {
|
137
|
-
result = rb_str_new2("[global]");
|
138
|
-
}
|
139
|
-
|
140
|
-
return result;
|
123
|
+
prof_allocation_t* allocation = (prof_allocation_t*)value;
|
124
|
+
VALUE arr = (VALUE)result;
|
125
|
+
rb_ary_push(arr, prof_allocation_wrap(allocation));
|
126
|
+
return ST_CONTINUE;
|
141
127
|
}
|
142
128
|
|
143
|
-
static
|
144
|
-
|
129
|
+
static int
|
130
|
+
prof_method_mark_allocations(st_data_t key, st_data_t value, st_data_t data)
|
145
131
|
{
|
146
|
-
|
147
|
-
|
148
|
-
|
149
|
-
|
150
|
-
klass_str = source_klass_name(source_klass);
|
151
|
-
method_str = method_name(mid);
|
152
|
-
|
153
|
-
klass_path = rb_str_split(klass_str, "::");
|
154
|
-
joiner = rb_str_new2("/");
|
155
|
-
result = rb_ary_join(klass_path, joiner);
|
156
|
-
|
157
|
-
rb_str_cat2(result, "::");
|
158
|
-
|
159
|
-
if (RP_REL_GET(relation, kObjectSingleton)) {
|
160
|
-
rb_str_cat2(result, "*");
|
161
|
-
}
|
162
|
-
|
163
|
-
if (RP_REL_GET(relation, kModuleSingleton)) {
|
164
|
-
rb_str_cat2(result, "^");
|
165
|
-
}
|
166
|
-
|
167
|
-
rb_str_append(result, method_str);
|
168
|
-
|
169
|
-
return result;
|
132
|
+
prof_allocation_t* allocation = (prof_allocation_t*)value;
|
133
|
+
prof_allocation_mark(allocation);
|
134
|
+
return ST_CONTINUE;
|
170
135
|
}
|
171
136
|
|
172
137
|
void
|
173
|
-
|
138
|
+
allocations_table_free(st_table* table)
|
174
139
|
{
|
175
|
-
|
176
|
-
|
177
|
-
results for that module. */
|
178
|
-
if (klass != 0 && BUILTIN_TYPE(klass) == T_ICLASS) {
|
179
|
-
klass = RBASIC(klass)->klass;
|
180
|
-
}
|
181
|
-
|
182
|
-
key->klass = klass;
|
183
|
-
key->mid = mid;
|
184
|
-
key->key = (klass << 4) + (mid << 2);
|
140
|
+
st_foreach(table, allocations_table_free_iterator, 0);
|
141
|
+
st_free_table(table);
|
185
142
|
}
|
186
143
|
|
187
144
|
/* ================ prof_method_t =================*/
|
188
|
-
|
189
|
-
|
190
|
-
prof_method_create(VALUE klass, ID mid, const char* source_file, int line)
|
145
|
+
static prof_method_t*
|
146
|
+
prof_get_method(VALUE self)
|
191
147
|
{
|
192
|
-
|
148
|
+
/* Can't use Data_Get_Struct because that triggers the event hook
|
149
|
+
ending up in endless recursion. */
|
150
|
+
prof_method_t* result = DATA_PTR(self);
|
193
151
|
|
194
|
-
|
195
|
-
|
152
|
+
if (!result)
|
153
|
+
rb_raise(rb_eRuntimeError, "This RubyProf::MethodInfo instance has already been freed, likely because its profile has been freed.");
|
196
154
|
|
197
|
-
result
|
198
|
-
|
155
|
+
return result;
|
156
|
+
}
|
199
157
|
|
200
|
-
|
158
|
+
prof_method_t*
|
159
|
+
prof_method_create(VALUE klass, VALUE msym, VALUE source_file, int source_line)
|
160
|
+
{
|
161
|
+
prof_method_t *result = ALLOC(prof_method_t);
|
162
|
+
result->key = method_key(klass, msym);
|
163
|
+
result->klass_flags = 0;
|
164
|
+
|
165
|
+
/* Note we do not call resolve_klass_name now because that causes an object allocation that shows up
|
166
|
+
in the allocation results so we want to avoid it until after the profile run is complete. */
|
167
|
+
result->klass = resolve_klass(klass, &result->klass_flags);
|
168
|
+
result->klass_name = Qnil;
|
169
|
+
result->method_name = msym;
|
170
|
+
result->measurement = prof_measurement_create();
|
171
|
+
|
172
|
+
result->root = false;
|
173
|
+
result->excluded = false;
|
174
|
+
|
175
|
+
result->parent_call_infos = method_table_create();
|
176
|
+
result->child_call_infos = method_table_create();
|
177
|
+
result->allocations_table = allocations_table_create();
|
178
|
+
|
201
179
|
result->visits = 0;
|
180
|
+
result->recursive = false;
|
202
181
|
|
203
182
|
result->object = Qnil;
|
204
183
|
|
205
|
-
|
206
|
-
|
207
|
-
size_t len = strlen(source_file) + 1;
|
208
|
-
char *buffer = ALLOC_N(char, len);
|
209
|
-
|
210
|
-
MEMCPY(buffer, source_file, char, len);
|
211
|
-
result->source_file = buffer;
|
212
|
-
} else {
|
213
|
-
result->source_file = source_file;
|
214
|
-
}
|
215
|
-
|
216
|
-
result->source_klass = Qnil;
|
217
|
-
result->line = line;
|
218
|
-
|
219
|
-
result->resolved = 0;
|
220
|
-
result->relation = 0;
|
184
|
+
result->source_file = source_file;
|
185
|
+
result->source_line = source_line;
|
221
186
|
|
222
187
|
return result;
|
223
188
|
}
|
224
189
|
|
225
190
|
prof_method_t*
|
226
|
-
prof_method_create_excluded(VALUE klass,
|
191
|
+
prof_method_create_excluded(VALUE klass, VALUE msym)
|
227
192
|
{
|
228
|
-
prof_method_t
|
229
|
-
|
230
|
-
result->key = ALLOC(prof_method_key_t);
|
231
|
-
method_key(result->key, klass, mid);
|
232
|
-
|
233
|
-
/* Invisible with this flag set. */
|
193
|
+
prof_method_t* result = prof_method_create(klass, msym, Qnil, 0);
|
234
194
|
result->excluded = 1;
|
235
|
-
result
|
195
|
+
return result;
|
196
|
+
}
|
236
197
|
|
237
|
-
|
238
|
-
|
198
|
+
static int
|
199
|
+
prof_method_collect_call_infos(st_data_t key, st_data_t value, st_data_t result)
|
200
|
+
{
|
201
|
+
prof_call_info_t* call_info = (prof_call_info_t*)value;
|
202
|
+
VALUE arr = (VALUE)result;
|
203
|
+
rb_ary_push(arr, prof_call_info_wrap(call_info));
|
204
|
+
return ST_CONTINUE;
|
205
|
+
}
|
239
206
|
|
240
|
-
|
241
|
-
|
242
|
-
|
207
|
+
static int
|
208
|
+
prof_method_mark_call_infos(st_data_t key, st_data_t value, st_data_t data)
|
209
|
+
{
|
210
|
+
prof_call_info_t* call_info = (prof_call_info_t*)value;
|
211
|
+
prof_call_info_mark(call_info);
|
212
|
+
return ST_CONTINUE;
|
213
|
+
}
|
243
214
|
|
244
|
-
|
245
|
-
|
215
|
+
static int
|
216
|
+
call_infos_free_iterator(st_data_t key, st_data_t value, st_data_t dummy)
|
217
|
+
{
|
218
|
+
prof_call_info_free((prof_call_info_t*)value);
|
219
|
+
return ST_CONTINUE;
|
220
|
+
}
|
246
221
|
|
247
|
-
|
222
|
+
void
|
223
|
+
call_info_table_free(st_table* table)
|
224
|
+
{
|
225
|
+
st_foreach(table, call_infos_free_iterator, 0);
|
226
|
+
st_free_table(table);
|
248
227
|
}
|
249
228
|
|
250
229
|
/* The underlying c structures are freed when the parent profile is freed.
|
@@ -254,9 +233,11 @@ prof_method_create_excluded(VALUE klass, ID mid)
|
|
254
233
|
for the garbage collector so that if it does get called will nil
|
255
234
|
out our Ruby object reference.*/
|
256
235
|
static void
|
257
|
-
prof_method_ruby_gc_free(
|
236
|
+
prof_method_ruby_gc_free(void *data)
|
258
237
|
{
|
259
|
-
|
238
|
+
prof_method_t* method = (prof_method_t*)data;
|
239
|
+
|
240
|
+
/* Has this thread object been accessed by Ruby? If
|
260
241
|
yes clean it up so to avoid a segmentation fault. */
|
261
242
|
if (method->object != Qnil)
|
262
243
|
{
|
@@ -265,169 +246,100 @@ prof_method_ruby_gc_free(prof_method_t* method)
|
|
265
246
|
RDATA(method->object)->dmark = NULL;
|
266
247
|
}
|
267
248
|
method->object = Qnil;
|
249
|
+
method->klass_name = Qnil;
|
250
|
+
method->method_name = Qnil;
|
268
251
|
}
|
269
252
|
|
270
253
|
static void
|
271
254
|
prof_method_free(prof_method_t* method)
|
272
255
|
{
|
273
256
|
prof_method_ruby_gc_free(method);
|
257
|
+
allocations_table_free(method->allocations_table);
|
274
258
|
|
275
|
-
|
276
|
-
|
277
|
-
|
278
|
-
|
279
|
-
|
280
|
-
xfree(method->key);
|
259
|
+
/* Remember call infos are referenced by their parent method and child method, so we only want
|
260
|
+
to iterate over one of them to avoid a double freeing */
|
261
|
+
call_info_table_free(method->parent_call_infos);
|
262
|
+
xfree(method->child_call_infos);
|
281
263
|
|
282
|
-
|
283
|
-
|
264
|
+
xfree(method);
|
265
|
+
}
|
284
266
|
|
285
|
-
|
267
|
+
size_t
|
268
|
+
prof_method_size(const void *data)
|
269
|
+
{
|
270
|
+
return sizeof(prof_method_t);
|
286
271
|
}
|
287
272
|
|
288
273
|
void
|
289
|
-
prof_method_mark(
|
274
|
+
prof_method_mark(void *data)
|
290
275
|
{
|
291
|
-
|
292
|
-
|
293
|
-
|
276
|
+
prof_method_t* method = (prof_method_t*)data;
|
277
|
+
rb_gc_mark(method->klass_name);
|
278
|
+
rb_gc_mark(method->method_name);
|
279
|
+
|
280
|
+
if (method->klass != Qnil)
|
281
|
+
rb_gc_mark(method->klass);
|
294
282
|
|
295
|
-
|
296
|
-
rb_gc_mark(method->source_klass);
|
297
|
-
}
|
298
|
-
|
299
|
-
if (method->object) {
|
283
|
+
if (method->object != Qnil)
|
300
284
|
rb_gc_mark(method->object);
|
301
|
-
}
|
302
285
|
|
303
|
-
|
304
|
-
|
305
|
-
|
286
|
+
prof_measurement_mark(method->measurement);
|
287
|
+
|
288
|
+
st_foreach(method->parent_call_infos, prof_method_mark_call_infos, 0);
|
289
|
+
st_foreach(method->child_call_infos, prof_method_mark_call_infos, 0);
|
290
|
+
st_foreach(method->allocations_table, prof_method_mark_allocations, 0);
|
306
291
|
}
|
307
292
|
|
308
|
-
static
|
309
|
-
resolve_source_klass(prof_method_t* method)
|
293
|
+
static const rb_data_type_t method_info_type =
|
310
294
|
{
|
311
|
-
|
312
|
-
|
313
|
-
unsigned int relation;
|
314
|
-
|
315
|
-
/* We want to group methods according to their source-level
|
316
|
-
definitions, not their implementation class. Follow module
|
317
|
-
inclusions and singleton classes back to a meaningful root
|
318
|
-
while keeping track of these relationships. */
|
319
|
-
|
320
|
-
if (method->resolved) {
|
321
|
-
return method->source_klass;
|
322
|
-
}
|
323
|
-
|
324
|
-
klass = method->key->klass;
|
325
|
-
relation = 0;
|
326
|
-
|
327
|
-
while (1)
|
295
|
+
.wrap_struct_name = "MethodInfo",
|
296
|
+
.function =
|
328
297
|
{
|
329
|
-
|
330
|
-
|
331
|
-
|
332
|
-
|
333
|
-
|
334
|
-
|
335
|
-
|
336
|
-
/* We have come across a singleton object. First
|
337
|
-
figure out what it is attached to.*/
|
338
|
-
attached = rb_iv_get(klass, "__attached__");
|
339
|
-
|
340
|
-
/* Is this a singleton class acting as a metaclass?
|
341
|
-
Or for singleton methods on a module? */
|
342
|
-
if (BUILTIN_TYPE(attached) == T_CLASS ||
|
343
|
-
BUILTIN_TYPE(attached) == T_MODULE)
|
344
|
-
{
|
345
|
-
RP_REL_SET(relation, kModuleSingleton);
|
346
|
-
klass = attached;
|
347
|
-
}
|
348
|
-
/* Is this for singleton methods on an object? */
|
349
|
-
else if (BUILTIN_TYPE(attached) == T_OBJECT)
|
350
|
-
{
|
351
|
-
RP_REL_SET(relation, kObjectSingleton);
|
352
|
-
next_klass = rb_class_superclass(klass);
|
353
|
-
klass = next_klass;
|
354
|
-
}
|
355
|
-
/* This is a singleton of an instance of a builtin type. */
|
356
|
-
else
|
357
|
-
{
|
358
|
-
RP_REL_SET(relation, kObjectSingleton);
|
359
|
-
next_klass = rb_class_superclass(klass);
|
360
|
-
klass = next_klass;
|
361
|
-
}
|
362
|
-
}
|
363
|
-
/* Is this an include for a module? If so get the actual
|
364
|
-
module class since we want to combine all profiling
|
365
|
-
results for that module. */
|
366
|
-
else if (BUILTIN_TYPE(klass) == T_ICLASS)
|
367
|
-
{
|
368
|
-
RP_REL_SET(relation, kModuleIncludee);
|
369
|
-
next_klass = RBASIC(klass)->klass;
|
370
|
-
klass = next_klass;
|
371
|
-
}
|
372
|
-
/* No transformations apply; so bail. */
|
373
|
-
else
|
374
|
-
{
|
375
|
-
break;
|
376
|
-
}
|
377
|
-
}
|
378
|
-
|
379
|
-
method->resolved = 1;
|
380
|
-
method->relation = relation;
|
381
|
-
method->source_klass = klass;
|
298
|
+
.dmark = prof_method_mark,
|
299
|
+
.dfree = prof_method_ruby_gc_free,
|
300
|
+
.dsize = prof_method_size,
|
301
|
+
},
|
302
|
+
.data = NULL,
|
303
|
+
.flags = RUBY_TYPED_FREE_IMMEDIATELY
|
304
|
+
};
|
382
305
|
|
383
|
-
|
306
|
+
static VALUE
|
307
|
+
prof_method_allocate(VALUE klass)
|
308
|
+
{
|
309
|
+
prof_method_t* method_data = prof_method_create(Qnil, Qnil, Qnil, 0);
|
310
|
+
method_data->object = prof_method_wrap(method_data);
|
311
|
+
return method_data->object;
|
384
312
|
}
|
385
313
|
|
386
314
|
VALUE
|
387
|
-
prof_method_wrap(prof_method_t *
|
315
|
+
prof_method_wrap(prof_method_t *method)
|
388
316
|
{
|
389
|
-
if (
|
390
|
-
|
317
|
+
if (method->object == Qnil)
|
318
|
+
{
|
319
|
+
method->object = TypedData_Wrap_Struct(cRpMethodInfo, &method_info_type, method);
|
391
320
|
}
|
392
|
-
return
|
321
|
+
return method->object;
|
393
322
|
}
|
394
323
|
|
395
|
-
|
396
|
-
|
324
|
+
prof_method_t *
|
325
|
+
prof_method_get(VALUE self)
|
397
326
|
{
|
398
327
|
/* Can't use Data_Get_Struct because that triggers the event hook
|
399
328
|
ending up in endless recursion. */
|
400
329
|
prof_method_t* result = DATA_PTR(self);
|
401
330
|
|
402
|
-
if (!result)
|
331
|
+
if (!result)
|
332
|
+
{
|
403
333
|
rb_raise(rb_eRuntimeError, "This RubyProf::MethodInfo instance has already been freed, likely because its profile has been freed.");
|
404
334
|
}
|
405
335
|
|
406
336
|
return result;
|
407
337
|
}
|
408
338
|
|
409
|
-
/* ================ Method Table =================*/
|
410
|
-
int
|
411
|
-
method_table_cmp(prof_method_key_t *key1, prof_method_key_t *key2)
|
412
|
-
{
|
413
|
-
return (key1->klass != key2->klass) || (key1->mid != key2->mid);
|
414
|
-
}
|
415
|
-
|
416
|
-
st_index_t
|
417
|
-
method_table_hash(prof_method_key_t *key)
|
418
|
-
{
|
419
|
-
return key->key;
|
420
|
-
}
|
421
|
-
|
422
|
-
struct st_hash_type type_method_hash = {
|
423
|
-
method_table_cmp,
|
424
|
-
method_table_hash
|
425
|
-
};
|
426
|
-
|
427
339
|
st_table *
|
428
340
|
method_table_create()
|
429
341
|
{
|
430
|
-
|
342
|
+
return st_init_numtable();
|
431
343
|
}
|
432
344
|
|
433
345
|
static int
|
@@ -445,18 +357,21 @@ method_table_free(st_table *table)
|
|
445
357
|
}
|
446
358
|
|
447
359
|
size_t
|
448
|
-
method_table_insert(st_table *table,
|
360
|
+
method_table_insert(st_table *table, st_data_t key, prof_method_t *val)
|
449
361
|
{
|
450
|
-
|
362
|
+
return st_insert(table, (st_data_t) key, (st_data_t) val);
|
451
363
|
}
|
452
364
|
|
453
365
|
prof_method_t *
|
454
|
-
method_table_lookup(st_table *table,
|
366
|
+
method_table_lookup(st_table *table, st_data_t key)
|
455
367
|
{
|
456
368
|
st_data_t val;
|
457
|
-
if (st_lookup(table, (st_data_t)key, &val))
|
369
|
+
if (st_lookup(table, (st_data_t)key, &val))
|
370
|
+
{
|
458
371
|
return (prof_method_t *) val;
|
459
|
-
}
|
372
|
+
}
|
373
|
+
else
|
374
|
+
{
|
460
375
|
return NULL;
|
461
376
|
}
|
462
377
|
}
|
@@ -472,52 +387,75 @@ the RubyProf::Profile object.
|
|
472
387
|
*/
|
473
388
|
|
474
389
|
/* call-seq:
|
475
|
-
|
390
|
+
callers -> array
|
476
391
|
|
477
|
-
|
392
|
+
Returns an array of call info objects that called this method (ie, parents).*/
|
478
393
|
static VALUE
|
479
|
-
|
394
|
+
prof_method_callers(VALUE self)
|
480
395
|
{
|
481
|
-
|
482
|
-
|
396
|
+
prof_method_t* method = prof_get_method(self);
|
397
|
+
VALUE result = rb_ary_new();
|
398
|
+
st_foreach(method->parent_call_infos, prof_method_collect_call_infos, result);
|
399
|
+
return result;
|
483
400
|
}
|
484
401
|
|
485
402
|
/* call-seq:
|
486
|
-
|
403
|
+
callees -> array
|
487
404
|
|
488
|
-
|
489
|
-
|
490
|
-
|
405
|
+
Returns an array of call info objects that this method called (ie, children).*/
|
406
|
+
static VALUE
|
407
|
+
prof_method_callees(VALUE self)
|
491
408
|
{
|
492
|
-
|
493
|
-
|
494
|
-
|
495
|
-
|
496
|
-
return rb_str_new2(sf);
|
497
|
-
}
|
409
|
+
prof_method_t* method = prof_get_method(self);
|
410
|
+
VALUE result = rb_ary_new();
|
411
|
+
st_foreach(method->child_call_infos, prof_method_collect_call_infos, result);
|
412
|
+
return result;
|
498
413
|
}
|
499
414
|
|
415
|
+
/* call-seq:
|
416
|
+
allocations -> array
|
417
|
+
|
418
|
+
Returns an array of allocation information.*/
|
419
|
+
static VALUE
|
420
|
+
prof_method_allocations(VALUE self)
|
421
|
+
{
|
422
|
+
prof_method_t* method = prof_get_method(self);
|
423
|
+
VALUE result = rb_ary_new();
|
424
|
+
st_foreach(method->allocations_table, prof_method_collect_allocations, result);
|
425
|
+
return result;
|
426
|
+
}
|
500
427
|
|
501
428
|
/* call-seq:
|
502
|
-
|
429
|
+
called -> Measurement
|
503
430
|
|
504
|
-
Returns the
|
431
|
+
Returns the measurement associated with this method. */
|
505
432
|
static VALUE
|
506
|
-
|
433
|
+
prof_method_measurement(VALUE self)
|
434
|
+
{
|
435
|
+
prof_method_t* method = prof_get_method(self);
|
436
|
+
return prof_measurement_wrap(method->measurement);
|
437
|
+
}
|
438
|
+
|
439
|
+
/* call-seq:
|
440
|
+
source_file => string
|
441
|
+
|
442
|
+
return the source file of the method
|
443
|
+
*/
|
444
|
+
static VALUE prof_method_source_file(VALUE self)
|
507
445
|
{
|
508
|
-
prof_method_t
|
509
|
-
return
|
446
|
+
prof_method_t* method = prof_method_get(self);
|
447
|
+
return method->source_file;
|
510
448
|
}
|
511
449
|
|
512
450
|
/* call-seq:
|
513
|
-
|
451
|
+
line_no -> int
|
514
452
|
|
515
|
-
|
453
|
+
returns the line number of the method */
|
516
454
|
static VALUE
|
517
|
-
|
455
|
+
prof_method_line(VALUE self)
|
518
456
|
{
|
519
|
-
prof_method_t
|
520
|
-
return
|
457
|
+
prof_method_t* method = prof_method_get(self);
|
458
|
+
return INT2FIX(method->source_line);
|
521
459
|
}
|
522
460
|
|
523
461
|
/* call-seq:
|
@@ -527,104 +465,178 @@ Returns the name of this method's class. Singleton classes
|
|
527
465
|
will have the form <Object::Object>. */
|
528
466
|
|
529
467
|
static VALUE
|
530
|
-
|
468
|
+
prof_method_klass_name(VALUE self)
|
531
469
|
{
|
532
|
-
prof_method_t *method =
|
533
|
-
|
470
|
+
prof_method_t *method = prof_method_get(self);
|
471
|
+
if (method->klass_name == Qnil)
|
472
|
+
method->klass_name = resolve_klass_name(method->klass, &method->klass_flags);
|
473
|
+
|
474
|
+
return method->klass_name;
|
534
475
|
}
|
535
476
|
|
536
477
|
/* call-seq:
|
537
|
-
|
478
|
+
klass_flags -> integer
|
538
479
|
|
539
|
-
Returns the
|
540
|
-
methods will be returned in the format <Object::Object>#method.*/
|
480
|
+
Returns the klass flags */
|
541
481
|
|
542
482
|
static VALUE
|
543
|
-
|
483
|
+
prof_method_klass_flags(VALUE self)
|
544
484
|
{
|
545
|
-
prof_method_t
|
546
|
-
return
|
485
|
+
prof_method_t* method = prof_method_get(self);
|
486
|
+
return INT2FIX(method->klass_flags);
|
547
487
|
}
|
548
488
|
|
549
489
|
/* call-seq:
|
550
|
-
|
490
|
+
method_name -> string
|
551
491
|
|
552
|
-
Returns the
|
492
|
+
Returns the name of this method in the format Object#method. Singletons
|
493
|
+
methods will be returned in the format <Object::Object>#method.*/
|
553
494
|
|
554
495
|
static VALUE
|
555
|
-
|
496
|
+
prof_method_name(VALUE self)
|
556
497
|
{
|
557
|
-
prof_method_t *method =
|
558
|
-
return
|
498
|
+
prof_method_t *method = prof_method_get(self);
|
499
|
+
return method->method_name;
|
559
500
|
}
|
560
501
|
|
561
502
|
/* call-seq:
|
562
|
-
|
503
|
+
root? -> boolean
|
563
504
|
|
564
|
-
Returns
|
565
|
-
about the current method.*/
|
505
|
+
Returns the true if this method is at the top of the call stack */
|
566
506
|
static VALUE
|
567
|
-
|
507
|
+
prof_method_root(VALUE self)
|
568
508
|
{
|
569
|
-
prof_method_t *method =
|
570
|
-
|
571
|
-
method->call_infos->object = prof_call_infos_wrap(method->call_infos);
|
572
|
-
}
|
573
|
-
return method->call_infos->object;
|
509
|
+
prof_method_t *method = prof_method_get(self);
|
510
|
+
return method->root ? Qtrue : Qfalse;
|
574
511
|
}
|
575
512
|
|
576
513
|
/* call-seq:
|
577
514
|
recursive? -> boolean
|
578
515
|
|
579
|
-
Returns the true if this method is
|
516
|
+
Returns the true if this method is recursively invoked */
|
580
517
|
static VALUE
|
581
518
|
prof_method_recursive(VALUE self)
|
582
519
|
{
|
583
|
-
|
584
|
-
|
520
|
+
prof_method_t* method = prof_method_get(self);
|
521
|
+
return method->recursive ? Qtrue : Qfalse;
|
585
522
|
}
|
586
523
|
|
587
524
|
/* call-seq:
|
588
|
-
|
525
|
+
excluded? -> boolean
|
589
526
|
|
590
|
-
Returns the
|
527
|
+
Returns the true if this method was excluded */
|
591
528
|
static VALUE
|
592
|
-
|
529
|
+
prof_method_excluded(VALUE self)
|
593
530
|
{
|
594
|
-
prof_method_t
|
595
|
-
return
|
531
|
+
prof_method_t* method = prof_method_get(self);
|
532
|
+
return method->excluded ? Qtrue : Qfalse;
|
596
533
|
}
|
597
534
|
|
598
|
-
/*
|
599
|
-
|
535
|
+
/* :nodoc: */
|
536
|
+
static VALUE
|
537
|
+
prof_method_dump(VALUE self)
|
538
|
+
{
|
539
|
+
prof_method_t* method_data = DATA_PTR(self);
|
540
|
+
VALUE result = rb_hash_new();
|
541
|
+
|
542
|
+
rb_hash_aset(result, ID2SYM(rb_intern("klass_name")), prof_method_klass_name(self));
|
543
|
+
rb_hash_aset(result, ID2SYM(rb_intern("klass_flags")), INT2FIX(method_data->klass_flags));
|
544
|
+
rb_hash_aset(result, ID2SYM(rb_intern("method_name")), method_data->method_name);
|
600
545
|
|
601
|
-
|
546
|
+
rb_hash_aset(result, ID2SYM(rb_intern("key")), INT2FIX(method_data->key));
|
547
|
+
rb_hash_aset(result, ID2SYM(rb_intern("root")), prof_method_root(self));
|
548
|
+
rb_hash_aset(result, ID2SYM(rb_intern("recursive")), prof_method_recursive(self));
|
549
|
+
rb_hash_aset(result, ID2SYM(rb_intern("excluded")), prof_method_excluded(self));
|
550
|
+
rb_hash_aset(result, ID2SYM(rb_intern("source_file")), method_data->source_file);
|
551
|
+
rb_hash_aset(result, ID2SYM(rb_intern("source_line")), INT2FIX(method_data->source_line));
|
602
552
|
|
553
|
+
rb_hash_aset(result, ID2SYM(rb_intern("measurement")), prof_measurement_wrap(method_data->measurement));
|
554
|
+
|
555
|
+
rb_hash_aset(result, ID2SYM(rb_intern("callers")), prof_method_callers(self));
|
556
|
+
rb_hash_aset(result, ID2SYM(rb_intern("callees")), prof_method_callees(self));
|
557
|
+
|
558
|
+
rb_hash_aset(result, ID2SYM(rb_intern("allocations")), prof_method_allocations(self));
|
559
|
+
|
560
|
+
return result;
|
561
|
+
}
|
562
|
+
|
563
|
+
/* :nodoc: */
|
603
564
|
static VALUE
|
604
|
-
|
565
|
+
prof_method_load(VALUE self, VALUE data)
|
605
566
|
{
|
606
|
-
prof_method_t
|
607
|
-
|
608
|
-
|
567
|
+
prof_method_t* method_data = RDATA(self)->data;
|
568
|
+
method_data->object = self;
|
569
|
+
|
570
|
+
method_data->klass_name = rb_hash_aref(data, ID2SYM(rb_intern("klass_name")));
|
571
|
+
method_data->klass_flags = FIX2INT(rb_hash_aref(data, ID2SYM(rb_intern("klass_flags"))));
|
572
|
+
method_data->method_name = rb_hash_aref(data, ID2SYM(rb_intern("method_name")));
|
573
|
+
method_data->key = FIX2LONG(rb_hash_aref(data, ID2SYM(rb_intern("key"))));
|
574
|
+
|
575
|
+
method_data->root = rb_hash_aref(data, ID2SYM(rb_intern("root"))) == Qtrue ? true : false;
|
576
|
+
method_data->recursive = rb_hash_aref(data, ID2SYM(rb_intern("recursive"))) == Qtrue ? true : false;
|
577
|
+
method_data->excluded = rb_hash_aref(data, ID2SYM(rb_intern("excluded"))) == Qtrue ? true : false;
|
578
|
+
|
579
|
+
method_data->source_file = rb_hash_aref(data, ID2SYM(rb_intern("source_file")));
|
580
|
+
method_data->source_line = FIX2INT(rb_hash_aref(data, ID2SYM(rb_intern("source_line"))));
|
581
|
+
|
582
|
+
VALUE measurement = rb_hash_aref(data, ID2SYM(rb_intern("measurement")));
|
583
|
+
method_data->measurement = prof_get_measurement(measurement);
|
584
|
+
|
585
|
+
VALUE callers = rb_hash_aref(data, ID2SYM(rb_intern("callers")));
|
586
|
+
for (int i = 0; i < rb_array_len(callers); i++)
|
587
|
+
{
|
588
|
+
VALUE call_info = rb_ary_entry(callers, i);
|
589
|
+
prof_call_info_t *call_info_data = prof_get_call_info(call_info);
|
590
|
+
st_data_t key = call_info_data->parent ? call_info_data->parent->key : method_key(Qnil, 0);
|
591
|
+
call_info_table_insert(method_data->parent_call_infos, key, call_info_data);
|
592
|
+
}
|
593
|
+
|
594
|
+
VALUE callees = rb_hash_aref(data, ID2SYM(rb_intern("callees")));
|
595
|
+
for (int i = 0; i < rb_array_len(callees); i++)
|
596
|
+
{
|
597
|
+
VALUE call_info = rb_ary_entry(callees, i);
|
598
|
+
prof_call_info_t *call_info_data = prof_get_call_info(call_info);
|
599
|
+
|
600
|
+
st_data_t key = call_info_data->method ? call_info_data->method->key : method_key(Qnil, 0);
|
601
|
+
call_info_table_insert(method_data->child_call_infos, key, call_info_data);
|
602
|
+
}
|
603
|
+
|
604
|
+
VALUE allocations = rb_hash_aref(data, ID2SYM(rb_intern("allocations")));
|
605
|
+
for (int i = 0; i < rb_array_len(allocations); i++)
|
606
|
+
{
|
607
|
+
VALUE allocation = rb_ary_entry(allocations, i);
|
608
|
+
prof_allocation_t* allocation_data = prof_allocation_get(allocation);
|
609
|
+
|
610
|
+
st_insert(method_data->allocations_table, allocation_data->key, (st_data_t)allocation_data);
|
611
|
+
}
|
612
|
+
return data;
|
609
613
|
}
|
610
614
|
|
611
615
|
void rp_init_method_info()
|
612
616
|
{
|
613
617
|
/* MethodInfo */
|
614
|
-
|
615
|
-
rb_undef_method(CLASS_OF(
|
616
|
-
|
617
|
-
|
618
|
-
rb_define_method(
|
619
|
-
rb_define_method(
|
620
|
-
|
621
|
-
rb_define_method(
|
622
|
-
|
623
|
-
rb_define_method(
|
624
|
-
rb_define_method(
|
625
|
-
rb_define_method(
|
626
|
-
|
627
|
-
|
628
|
-
|
629
|
-
rb_define_method(
|
618
|
+
cRpMethodInfo = rb_define_class_under(mProf, "MethodInfo", rb_cData);
|
619
|
+
rb_undef_method(CLASS_OF(cRpMethodInfo), "new");
|
620
|
+
rb_define_alloc_func(cRpMethodInfo, prof_method_allocate);
|
621
|
+
|
622
|
+
rb_define_method(cRpMethodInfo, "klass_name", prof_method_klass_name, 0);
|
623
|
+
rb_define_method(cRpMethodInfo, "klass_flags", prof_method_klass_flags, 0);
|
624
|
+
|
625
|
+
rb_define_method(cRpMethodInfo, "method_name", prof_method_name, 0);
|
626
|
+
|
627
|
+
rb_define_method(cRpMethodInfo, "callers", prof_method_callers, 0);
|
628
|
+
rb_define_method(cRpMethodInfo, "callees", prof_method_callees, 0);
|
629
|
+
rb_define_method(cRpMethodInfo, "allocations", prof_method_allocations, 0);
|
630
|
+
|
631
|
+
rb_define_method(cRpMethodInfo, "measurement", prof_method_measurement, 0);
|
632
|
+
|
633
|
+
rb_define_method(cRpMethodInfo, "source_file", prof_method_source_file, 0);
|
634
|
+
rb_define_method(cRpMethodInfo, "line", prof_method_line, 0);
|
635
|
+
|
636
|
+
rb_define_method(cRpMethodInfo, "root?", prof_method_root, 0);
|
637
|
+
rb_define_method(cRpMethodInfo, "recursive?", prof_method_recursive, 0);
|
638
|
+
rb_define_method(cRpMethodInfo, "excluded?", prof_method_excluded, 0);
|
639
|
+
|
640
|
+
rb_define_method(cRpMethodInfo, "_dump_data", prof_method_dump, 0);
|
641
|
+
rb_define_method(cRpMethodInfo, "_load_data", prof_method_load, 1);
|
630
642
|
}
|