ruby-prof 1.1.0 → 1.2.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 +12 -1
- data/bin/ruby-prof +100 -152
- data/ext/ruby_prof/rp_aggregate_call_tree.c +41 -0
- data/ext/ruby_prof/rp_aggregate_call_tree.h +13 -0
- data/ext/ruby_prof/rp_allocation.c +31 -51
- data/ext/ruby_prof/rp_allocation.h +2 -2
- data/ext/ruby_prof/rp_call_tree.c +353 -0
- data/ext/ruby_prof/rp_call_tree.h +43 -0
- data/ext/ruby_prof/rp_call_trees.c +266 -0
- data/ext/ruby_prof/rp_call_trees.h +29 -0
- data/ext/ruby_prof/rp_measure_allocations.c +11 -13
- data/ext/ruby_prof/rp_measure_process_time.c +11 -13
- data/ext/ruby_prof/rp_measure_wall_time.c +17 -15
- data/ext/ruby_prof/rp_measurement.c +27 -36
- data/ext/ruby_prof/rp_measurement.h +6 -6
- data/ext/ruby_prof/rp_method.c +88 -248
- data/ext/ruby_prof/rp_method.h +12 -19
- data/ext/ruby_prof/rp_profile.c +277 -270
- data/ext/ruby_prof/rp_profile.h +0 -1
- data/ext/ruby_prof/rp_stack.c +113 -105
- data/ext/ruby_prof/rp_stack.h +15 -18
- data/ext/ruby_prof/rp_thread.c +115 -107
- data/ext/ruby_prof/rp_thread.h +9 -8
- data/ext/ruby_prof/ruby_prof.c +27 -23
- data/ext/ruby_prof/ruby_prof.h +9 -0
- data/ext/ruby_prof/vc/ruby_prof.vcxproj +11 -7
- data/lib/ruby-prof.rb +2 -3
- data/lib/ruby-prof/assets/call_stack_printer.html.erb +4 -7
- data/lib/ruby-prof/assets/graph_printer.html.erb +5 -6
- data/lib/ruby-prof/{call_info.rb → call_tree.rb} +6 -6
- data/lib/ruby-prof/call_tree_visitor.rb +36 -0
- data/lib/ruby-prof/measurement.rb +5 -2
- data/lib/ruby-prof/method_info.rb +3 -15
- data/lib/ruby-prof/printers/call_info_printer.rb +12 -10
- data/lib/ruby-prof/printers/call_stack_printer.rb +19 -22
- data/lib/ruby-prof/printers/call_tree_printer.rb +1 -1
- data/lib/ruby-prof/printers/dot_printer.rb +3 -3
- data/lib/ruby-prof/printers/graph_printer.rb +3 -4
- data/lib/ruby-prof/printers/multi_printer.rb +2 -2
- data/lib/ruby-prof/rack.rb +3 -0
- data/lib/ruby-prof/thread.rb +3 -18
- data/lib/ruby-prof/version.rb +1 -1
- data/ruby-prof.gemspec +7 -0
- data/test/alias_test.rb +42 -45
- data/test/basic_test.rb +0 -86
- data/test/{call_info_visitor_test.rb → call_tree_visitor_test.rb} +6 -5
- data/test/call_trees_test.rb +66 -0
- data/test/exclude_methods_test.rb +17 -12
- data/test/fiber_test.rb +203 -6
- data/test/gc_test.rb +32 -23
- data/test/inverse_call_tree_test.rb +175 -0
- data/test/line_number_test.rb +64 -67
- data/test/marshal_test.rb +7 -11
- data/test/measure_allocations_test.rb +224 -234
- data/test/measure_allocations_trace_test.rb +224 -234
- data/test/measure_memory_trace_test.rb +814 -469
- data/test/measure_process_time_test.rb +0 -64
- data/test/measure_times.rb +2 -0
- data/test/measure_wall_time_test.rb +34 -58
- data/test/pause_resume_test.rb +19 -10
- data/test/prime.rb +1 -3
- data/test/prime_script.rb +6 -0
- data/test/printers_test.rb +1 -1
- data/test/recursive_test.rb +50 -54
- data/test/start_stop_test.rb +19 -19
- data/test/test_helper.rb +3 -15
- data/test/thread_test.rb +11 -11
- data/test/unique_call_path_test.rb +25 -95
- metadata +19 -9
- data/ext/ruby_prof/rp_call_info.c +0 -271
- data/ext/ruby_prof/rp_call_info.h +0 -35
- data/lib/ruby-prof/call_info_visitor.rb +0 -38
- data/test/parser_timings.rb +0 -24
data/ext/ruby_prof/rp_method.h
CHANGED
@@ -18,20 +18,15 @@ enum {
|
|
18
18
|
kOtherSingleton = 0x10 /* Singleton of unkown object */
|
19
19
|
};
|
20
20
|
|
21
|
-
/* Forward declaration, see rp_call_info.h */
|
22
|
-
struct prof_call_infos_t;
|
23
|
-
|
24
21
|
/* Profiling information for each method. */
|
25
|
-
/* Excluded methods have no
|
22
|
+
/* Excluded methods have no call_trees, source_klass, or source_file. */
|
26
23
|
typedef struct
|
27
24
|
{
|
28
25
|
st_data_t key; /* Table key */
|
29
26
|
|
30
27
|
int visits; /* Current visits on the stack */
|
31
|
-
bool excluded; /* Exclude from profile? */
|
32
28
|
|
33
|
-
|
34
|
-
st_table* child_call_infos; /* Call infos that this method calls */
|
29
|
+
struct prof_call_trees_t* call_trees; /* Call infos that call this method */
|
35
30
|
st_table* allocations_table; /* Tracks object allocations */
|
36
31
|
|
37
32
|
unsigned int klass_flags; /* Information about the type of class */
|
@@ -41,30 +36,28 @@ typedef struct
|
|
41
36
|
|
42
37
|
VALUE object; /* Cached ruby object */
|
43
38
|
|
44
|
-
bool root; /* Is this a root method */
|
45
39
|
bool recursive;
|
46
40
|
VALUE source_file; /* Source file */
|
47
41
|
int source_line; /* Line number */
|
48
42
|
|
49
|
-
prof_measurement_t
|
43
|
+
prof_measurement_t* measurement;
|
50
44
|
} prof_method_t;
|
51
45
|
|
52
46
|
void rp_init_method_info(void);
|
53
47
|
|
54
48
|
st_data_t method_key(VALUE klass, VALUE msym);
|
55
49
|
|
56
|
-
st_table
|
57
|
-
prof_method_t*
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
prof_method_t
|
62
|
-
prof_method_t *prof_method_get(VALUE self);
|
50
|
+
st_table* method_table_create(void);
|
51
|
+
prof_method_t* method_table_lookup(st_table* table, st_data_t key);
|
52
|
+
size_t method_table_insert(st_table* table, st_data_t key, prof_method_t* val);
|
53
|
+
void method_table_free(st_table* table);
|
54
|
+
prof_method_t* prof_method_create(VALUE klass, VALUE msym, VALUE source_file, int source_line);
|
55
|
+
prof_method_t* prof_get_method(VALUE self);
|
63
56
|
|
64
|
-
VALUE prof_method_wrap(prof_method_t
|
65
|
-
void prof_method_mark(void
|
57
|
+
VALUE prof_method_wrap(prof_method_t* result);
|
58
|
+
void prof_method_mark(void* data);
|
66
59
|
|
67
|
-
VALUE resolve_klass(VALUE klass, unsigned int
|
60
|
+
VALUE resolve_klass(VALUE klass, unsigned int* klass_flags);
|
68
61
|
VALUE resolve_klass_name(VALUE klass, unsigned int* klass_flags);
|
69
62
|
|
70
63
|
#endif //__RP_METHOD_INFO__
|
data/ext/ruby_prof/rp_profile.c
CHANGED
@@ -1,28 +1,29 @@
|
|
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
|
-
/* Document-class: RubyProf::Profile
|
4
|
+
/* Document-class: RubyProf::Profile
|
5
5
|
|
6
|
-
The Profile class represents a single profiling run and provides the main API for using ruby-prof.
|
7
|
-
After creating a Profile instance, start profiling code by calling the Profile#start method. To finish profiling,
|
8
|
-
call Profile#stop. Once profiling is completed, the Profile instance contains the results.
|
6
|
+
The Profile class represents a single profiling run and provides the main API for using ruby-prof.
|
7
|
+
After creating a Profile instance, start profiling code by calling the Profile#start method. To finish profiling,
|
8
|
+
call Profile#stop. Once profiling is completed, the Profile instance contains the results.
|
9
9
|
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
10
|
+
profile = RubyProf::Profile.new
|
11
|
+
profile.start
|
12
|
+
...
|
13
|
+
result = profile.stop
|
14
14
|
|
15
|
-
Alternatively, you can use the block syntax:
|
15
|
+
Alternatively, you can use the block syntax:
|
16
16
|
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
*/
|
17
|
+
profile = RubyProf::Profile.profile do
|
18
|
+
...
|
19
|
+
end
|
20
|
+
*/
|
21
21
|
|
22
22
|
#include <assert.h>
|
23
23
|
|
24
24
|
#include "rp_allocation.h"
|
25
|
-
#include "
|
25
|
+
#include "rp_call_trees.h"
|
26
|
+
#include "rp_call_tree.h"
|
26
27
|
#include "rp_profile.h"
|
27
28
|
#include "rp_method.h"
|
28
29
|
|
@@ -35,69 +36,37 @@ VALUE cProfile;
|
|
35
36
|
*/
|
36
37
|
FILE* trace_file = NULL;
|
37
38
|
|
38
|
-
static
|
39
|
-
excludes_method(st_data_t key, prof_profile_t* profile)
|
40
|
-
{
|
41
|
-
return (profile->exclude_methods_tbl &&
|
42
|
-
method_table_lookup(profile->exclude_methods_tbl, key) != NULL);
|
43
|
-
}
|
44
|
-
|
45
|
-
static prof_method_t*
|
46
|
-
create_method(prof_profile_t* profile, st_data_t key, VALUE klass, VALUE msym, VALUE source_file, int source_line)
|
47
|
-
{
|
48
|
-
prof_method_t* result = NULL;
|
49
|
-
|
50
|
-
if (excludes_method(key, profile))
|
51
|
-
{
|
52
|
-
/* We found a exclusion sentinel so propagate it into the thread's local hash table. */
|
53
|
-
/* TODO(nelgau): Is there a way to avoid this allocation completely so that all these
|
54
|
-
tables share the same exclusion method struct? The first attempt failed due to my
|
55
|
-
ignorance of the whims of the GC. */
|
56
|
-
result = prof_method_create_excluded(klass, msym);
|
57
|
-
}
|
58
|
-
else
|
59
|
-
{
|
60
|
-
result = prof_method_create(klass, msym, source_file, source_line);
|
61
|
-
}
|
62
|
-
|
63
|
-
/* Insert the newly created method, or the exlcusion sentinel. */
|
64
|
-
method_table_insert(profile->last_thread_data->method_table, result->key, result);
|
65
|
-
|
66
|
-
return result;
|
67
|
-
}
|
68
|
-
|
69
|
-
static const char *
|
70
|
-
get_event_name(rb_event_flag_t event)
|
39
|
+
static const char* get_event_name(rb_event_flag_t event)
|
71
40
|
{
|
72
41
|
switch (event) {
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
|
42
|
+
case RUBY_EVENT_LINE:
|
43
|
+
return "line";
|
44
|
+
case RUBY_EVENT_CLASS:
|
45
|
+
return "class";
|
46
|
+
case RUBY_EVENT_END:
|
47
|
+
return "end";
|
48
|
+
case RUBY_EVENT_CALL:
|
49
|
+
return "call";
|
50
|
+
case RUBY_EVENT_RETURN:
|
51
|
+
return "return";
|
52
|
+
case RUBY_EVENT_B_CALL:
|
53
|
+
return "b-call";
|
54
|
+
case RUBY_EVENT_B_RETURN:
|
55
|
+
return "b-return";
|
56
|
+
case RUBY_EVENT_C_CALL:
|
57
|
+
return "c-call";
|
58
|
+
case RUBY_EVENT_C_RETURN:
|
59
|
+
return "c-return";
|
60
|
+
case RUBY_EVENT_THREAD_BEGIN:
|
61
|
+
return "thread-begin";
|
62
|
+
case RUBY_EVENT_THREAD_END:
|
63
|
+
return "thread-end";
|
64
|
+
case RUBY_EVENT_FIBER_SWITCH:
|
65
|
+
return "fiber-switch";
|
66
|
+
case RUBY_EVENT_RAISE:
|
67
|
+
return "raise";
|
68
|
+
default:
|
69
|
+
return "unknown";
|
101
70
|
}
|
102
71
|
}
|
103
72
|
|
@@ -108,14 +77,14 @@ VALUE get_fiber(prof_profile_t* profile)
|
|
108
77
|
else
|
109
78
|
return rb_fiber_current();
|
110
79
|
}
|
111
|
-
|
112
|
-
thread_data_t* check_fiber(prof_profile_t
|
80
|
+
|
81
|
+
thread_data_t* check_fiber(prof_profile_t* profile, double measurement)
|
113
82
|
{
|
114
83
|
thread_data_t* result = NULL;
|
115
|
-
|
84
|
+
|
116
85
|
/* Get the current thread and fiber information. */
|
117
86
|
VALUE fiber = get_fiber(profile);
|
118
|
-
|
87
|
+
|
119
88
|
/* We need to switch the profiling context if we either had none before,
|
120
89
|
we don't merge fibers and the fiber ids differ, or the thread ids differ. */
|
121
90
|
if (profile->last_thread_data->fiber != fiber)
|
@@ -134,160 +103,210 @@ thread_data_t* check_fiber(prof_profile_t *profile, double measurement)
|
|
134
103
|
return result;
|
135
104
|
}
|
136
105
|
|
137
|
-
static
|
138
|
-
|
106
|
+
static int excludes_method(st_data_t key, prof_profile_t* profile)
|
107
|
+
{
|
108
|
+
return (profile->exclude_methods_tbl &&
|
109
|
+
method_table_lookup(profile->exclude_methods_tbl, key) != NULL);
|
110
|
+
}
|
111
|
+
|
112
|
+
static prof_method_t* create_method(prof_profile_t* profile, st_data_t key, VALUE klass, VALUE msym, VALUE source_file, int source_line)
|
113
|
+
{
|
114
|
+
prof_method_t* result = prof_method_create(klass, msym, source_file, source_line);
|
115
|
+
method_table_insert(profile->last_thread_data->method_table, result->key, result);
|
116
|
+
|
117
|
+
return result;
|
118
|
+
}
|
119
|
+
|
120
|
+
static prof_method_t* check_parent_method(prof_profile_t* profile, thread_data_t* thread_data)
|
121
|
+
{
|
122
|
+
VALUE msym = ID2SYM(rb_intern("_inserted_parent_"));
|
123
|
+
st_data_t key = method_key(cProfile, msym);
|
124
|
+
|
125
|
+
prof_method_t* result = method_table_lookup(thread_data->method_table, key);
|
126
|
+
|
127
|
+
if (!result)
|
128
|
+
{
|
129
|
+
result = create_method(profile, key, cProfile, msym, Qnil, 0);
|
130
|
+
}
|
131
|
+
|
132
|
+
return result;
|
133
|
+
}
|
134
|
+
|
135
|
+
prof_method_t* check_method(prof_profile_t* profile, rb_trace_arg_t* trace_arg, rb_event_flag_t event, thread_data_t* thread_data)
|
136
|
+
{
|
137
|
+
VALUE klass = rb_tracearg_defined_class(trace_arg);
|
138
|
+
|
139
|
+
/* Special case - skip any methods from the mProf
|
140
|
+
module or cProfile class since they clutter
|
141
|
+
the results but aren't important to them results. */
|
142
|
+
if (klass == cProfile)
|
143
|
+
return NULL;
|
144
|
+
|
145
|
+
#ifdef HAVE_RB_TRACEARG_CALLEE_ID
|
146
|
+
VALUE msym = rb_tracearg_callee_id(trace_arg);
|
147
|
+
#else
|
148
|
+
VALUE msym = rb_tracearg_method_id(trace_arg);
|
149
|
+
#endif
|
150
|
+
|
151
|
+
st_data_t key = method_key(klass, msym);
|
152
|
+
|
153
|
+
if (excludes_method(key, profile))
|
154
|
+
return NULL;
|
155
|
+
|
156
|
+
prof_method_t* result = method_table_lookup(thread_data->method_table, key);
|
157
|
+
|
158
|
+
if (!result)
|
159
|
+
{
|
160
|
+
VALUE source_file = (event != RUBY_EVENT_C_CALL ? rb_tracearg_path(trace_arg) : Qnil);
|
161
|
+
int source_line = (event != RUBY_EVENT_C_CALL ? FIX2INT(rb_tracearg_lineno(trace_arg)) : 0);
|
162
|
+
result = create_method(profile, key, klass, msym, source_file, source_line);
|
163
|
+
}
|
164
|
+
|
165
|
+
return result;
|
166
|
+
}
|
167
|
+
|
168
|
+
/* =========== Profiling ================= */
|
169
|
+
static void prof_trace(prof_profile_t* profile, rb_trace_arg_t* trace_arg, double measurement)
|
139
170
|
{
|
140
171
|
static VALUE last_fiber = Qnil;
|
141
172
|
VALUE fiber = get_fiber(profile);
|
142
|
-
|
173
|
+
|
143
174
|
rb_event_flag_t event = rb_tracearg_event_flag(trace_arg);
|
144
175
|
const char* event_name = get_event_name(event);
|
145
|
-
|
176
|
+
|
146
177
|
VALUE source_file = rb_tracearg_path(trace_arg);
|
147
178
|
int source_line = FIX2INT(rb_tracearg_lineno(trace_arg));
|
148
|
-
|
149
|
-
|
179
|
+
|
180
|
+
#ifdef HAVE_RB_TRACEARG_CALLEE_ID
|
150
181
|
VALUE msym = rb_tracearg_callee_id(trace_arg);
|
151
|
-
|
182
|
+
#else
|
152
183
|
VALUE msym = rb_tracearg_method_id(trace_arg);
|
153
|
-
|
154
|
-
|
184
|
+
#endif
|
185
|
+
|
155
186
|
unsigned int klass_flags;
|
156
187
|
VALUE klass = rb_tracearg_defined_class(trace_arg);
|
157
188
|
VALUE resolved_klass = resolve_klass(klass, &klass_flags);
|
158
189
|
const char* class_name = "";
|
159
|
-
|
190
|
+
|
160
191
|
if (resolved_klass != Qnil)
|
161
192
|
class_name = rb_class2name(resolved_klass);
|
162
|
-
|
193
|
+
|
163
194
|
if (last_fiber != fiber)
|
164
195
|
{
|
165
196
|
fprintf(trace_file, "\n");
|
166
197
|
}
|
167
|
-
|
198
|
+
|
168
199
|
const char* method_name_char = (msym != Qnil ? rb_id2name(SYM2ID(msym)) : "");
|
169
200
|
const char* source_file_char = (source_file != Qnil ? StringValuePtr(source_file) : "");
|
170
|
-
|
201
|
+
|
171
202
|
fprintf(trace_file, "%2lu:%2f %-8s %s#%s %s:%2d\n",
|
172
|
-
FIX2ULONG(fiber), (double)
|
203
|
+
FIX2ULONG(fiber), (double)measurement,
|
173
204
|
event_name, class_name, method_name_char, source_file_char, source_line);
|
174
205
|
fflush(trace_file);
|
175
206
|
last_fiber = fiber;
|
176
207
|
}
|
177
208
|
|
178
|
-
static void
|
179
|
-
prof_event_hook(VALUE trace_point, void* data)
|
209
|
+
static void prof_event_hook(VALUE trace_point, void* data)
|
180
210
|
{
|
181
211
|
prof_profile_t* profile = (prof_profile_t*)data;
|
182
|
-
thread_data_t* thread_data = NULL;
|
183
|
-
prof_frame_t *frame = NULL;
|
184
212
|
rb_trace_arg_t* trace_arg = rb_tracearg_from_tracepoint(trace_point);
|
185
213
|
double measurement = prof_measure(profile->measurer, trace_arg);
|
186
214
|
rb_event_flag_t event = rb_tracearg_event_flag(trace_arg);
|
187
215
|
VALUE self = rb_tracearg_self(trace_arg);
|
188
|
-
|
216
|
+
|
189
217
|
if (trace_file != NULL)
|
190
218
|
{
|
191
219
|
prof_trace(profile, trace_arg, measurement);
|
192
220
|
}
|
193
|
-
|
221
|
+
|
194
222
|
/* Special case - skip any methods from the mProf
|
195
223
|
module since they clutter the results but aren't important to them results. */
|
196
224
|
if (self == mProf)
|
197
225
|
return;
|
198
|
-
|
199
|
-
thread_data = check_fiber(profile, measurement);
|
200
|
-
|
226
|
+
|
227
|
+
thread_data_t* thread_data = check_fiber(profile, measurement);
|
228
|
+
|
201
229
|
if (!thread_data->trace)
|
202
230
|
return;
|
203
|
-
|
204
|
-
/* Get the current frame for the current thread. */
|
205
|
-
frame = thread_data->stack->ptr;
|
206
|
-
|
231
|
+
|
207
232
|
switch (event)
|
208
233
|
{
|
209
234
|
case RUBY_EVENT_LINE:
|
210
235
|
{
|
211
|
-
|
212
|
-
|
213
|
-
|
214
|
-
if (frame->call_info)
|
236
|
+
prof_frame_t* frame = prof_frame_current(thread_data->stack);
|
237
|
+
|
238
|
+
if (!frame)
|
215
239
|
{
|
216
|
-
|
240
|
+
prof_method_t* method = check_method(profile, trace_arg, event, thread_data);
|
241
|
+
|
242
|
+
if (!method)
|
243
|
+
break;
|
244
|
+
|
245
|
+
prof_call_tree_t* call_tree = prof_call_tree_create(method, NULL, method->source_file, method->source_line);
|
246
|
+
prof_add_call_tree(method->call_trees, call_tree);
|
247
|
+
|
248
|
+
if (thread_data->call_tree)
|
217
249
|
{
|
218
|
-
|
219
|
-
frame
|
250
|
+
prof_call_tree_add_parent(thread_data->call_tree, call_tree);
|
251
|
+
frame = prof_frame_unshift(thread_data->stack, call_tree, thread_data->call_tree, measurement);
|
220
252
|
}
|
221
|
-
|
253
|
+
else
|
254
|
+
{
|
255
|
+
frame = prof_frame_push(thread_data->stack, call_tree, measurement, RTEST(profile->paused));
|
256
|
+
}
|
257
|
+
|
258
|
+
thread_data->call_tree = call_tree;
|
222
259
|
}
|
223
260
|
|
224
|
-
|
225
|
-
|
226
|
-
|
261
|
+
frame->source_file = rb_tracearg_path(trace_arg);
|
262
|
+
frame->source_line = FIX2INT(rb_tracearg_lineno(trace_arg));
|
263
|
+
|
264
|
+
break;
|
227
265
|
}
|
228
266
|
case RUBY_EVENT_CALL:
|
229
267
|
case RUBY_EVENT_C_CALL:
|
230
268
|
{
|
231
|
-
|
232
|
-
prof_call_info_t* call_info;
|
233
|
-
prof_method_t* method;
|
269
|
+
prof_method_t* method = check_method(profile, trace_arg, event, thread_data);
|
234
270
|
|
235
|
-
|
236
|
-
|
271
|
+
if (!method)
|
272
|
+
break;
|
237
273
|
|
238
|
-
|
239
|
-
|
240
|
-
|
241
|
-
module or cProfile class since they clutter
|
242
|
-
the results but aren't important to them results. */
|
243
|
-
if (klass == cProfile)
|
244
|
-
return;
|
245
|
-
|
246
|
-
#ifdef HAVE_RB_TRACEARG_CALLEE_ID
|
247
|
-
VALUE msym = rb_tracearg_callee_id(trace_arg);
|
248
|
-
#else
|
249
|
-
VALUE msym = rb_tracearg_method_id(trace_arg);
|
250
|
-
#endif
|
274
|
+
prof_frame_t* frame = prof_frame_current(thread_data->stack);
|
275
|
+
prof_call_tree_t* parent_call_tree = NULL;
|
276
|
+
prof_call_tree_t* call_tree = NULL;
|
251
277
|
|
252
|
-
|
253
|
-
|
254
|
-
method = method_table_lookup(thread_data->method_table, key);
|
255
|
-
|
256
|
-
if (!method)
|
278
|
+
// Frame can be NULL if we are switching from one fiber to another (see FiberTest#fiber_test)
|
279
|
+
if (frame)
|
257
280
|
{
|
258
|
-
|
259
|
-
|
260
|
-
method = create_method(profile, key, klass, msym, source_file, source_line);
|
281
|
+
parent_call_tree = frame->call_tree;
|
282
|
+
call_tree = call_tree_table_lookup(parent_call_tree->children, method->key);
|
261
283
|
}
|
262
|
-
|
263
|
-
if (method->excluded)
|
284
|
+
else if (!frame && thread_data->call_tree)
|
264
285
|
{
|
265
|
-
|
266
|
-
|
286
|
+
// There is no current parent - likely we have returned out of the highest level method we have profiled so far.
|
287
|
+
// This can happen with enumerators (see fiber_test.rb). So create a new dummy parent.
|
288
|
+
prof_method_t* parent_method = check_parent_method(profile, thread_data);
|
289
|
+
parent_call_tree = prof_call_tree_create(parent_method, NULL, Qnil, 0);
|
290
|
+
prof_add_call_tree(parent_method->call_trees, parent_call_tree);
|
291
|
+
prof_call_tree_add_parent(thread_data->call_tree, parent_call_tree);
|
292
|
+
frame = prof_frame_unshift(thread_data->stack, parent_call_tree, thread_data->call_tree, measurement);
|
293
|
+
thread_data->call_tree = parent_call_tree;
|
267
294
|
}
|
268
|
-
|
269
|
-
if (!
|
270
|
-
{
|
271
|
-
method->root = true;
|
272
|
-
call_info = prof_call_info_create(method, NULL, method->source_file, method->source_line);
|
273
|
-
st_insert(method->parent_call_infos, (st_data_t)&key, (st_data_t)call_info);
|
274
|
-
}
|
275
|
-
else
|
295
|
+
|
296
|
+
if (!call_tree)
|
276
297
|
{
|
277
|
-
|
278
|
-
|
279
|
-
|
280
|
-
|
281
|
-
|
282
|
-
it to previous callinfo's children and to the current method .*/
|
283
|
-
call_info = prof_call_info_create(method, frame->call_info->method, frame->source_file, frame->source_line);
|
284
|
-
call_info_table_insert(method->parent_call_infos, frame->call_info->method->key, call_info);
|
285
|
-
call_info_table_insert(frame->call_info->method->child_call_infos, method->key, call_info);
|
286
|
-
}
|
298
|
+
// This call info does not yet exist. So create it and add it to previous CallTree's children and the current method.
|
299
|
+
call_tree = prof_call_tree_create(method, parent_call_tree, frame ? frame->source_file : Qnil, frame? frame->source_line : 0);
|
300
|
+
prof_add_call_tree(method->call_trees, call_tree);
|
301
|
+
if (parent_call_tree)
|
302
|
+
prof_call_tree_add_child(parent_call_tree, call_tree);
|
287
303
|
}
|
288
304
|
|
289
|
-
|
290
|
-
|
305
|
+
if (!thread_data->call_tree)
|
306
|
+
thread_data->call_tree = call_tree;
|
307
|
+
|
308
|
+
// Push a new frame onto the stack for a new c-call or ruby call (into a method)
|
309
|
+
prof_frame_t* next_frame = prof_frame_push(thread_data->stack, call_tree, measurement, RTEST(profile->paused));
|
291
310
|
next_frame->source_file = method->source_file;
|
292
311
|
next_frame->source_line = method->source_line;
|
293
312
|
break;
|
@@ -295,8 +314,13 @@ prof_event_hook(VALUE trace_point, void* data)
|
|
295
314
|
case RUBY_EVENT_RETURN:
|
296
315
|
case RUBY_EVENT_C_RETURN:
|
297
316
|
{
|
298
|
-
|
299
|
-
|
317
|
+
// We need to check for excluded methods so that we don't pop them off the stack
|
318
|
+
prof_method_t* method = check_method(profile, trace_arg, event, thread_data);
|
319
|
+
|
320
|
+
if (!method)
|
321
|
+
break;
|
322
|
+
|
323
|
+
prof_frame_pop(thread_data->stack, measurement);
|
300
324
|
break;
|
301
325
|
}
|
302
326
|
case RUBY_INTERNAL_EVENT_NEWOBJ:
|
@@ -315,35 +339,33 @@ prof_event_hook(VALUE trace_point, void* data)
|
|
315
339
|
}
|
316
340
|
}
|
317
341
|
|
318
|
-
void
|
319
|
-
prof_install_hook(VALUE self)
|
342
|
+
void prof_install_hook(VALUE self)
|
320
343
|
{
|
321
344
|
prof_profile_t* profile = prof_get_profile(self);
|
322
|
-
|
345
|
+
|
323
346
|
VALUE event_tracepoint = rb_tracepoint_new(Qnil,
|
324
347
|
RUBY_EVENT_CALL | RUBY_EVENT_RETURN |
|
325
348
|
RUBY_EVENT_C_CALL | RUBY_EVENT_C_RETURN |
|
326
349
|
RUBY_EVENT_LINE,
|
327
350
|
prof_event_hook, profile);
|
328
351
|
rb_ary_push(profile->tracepoints, event_tracepoint);
|
329
|
-
|
352
|
+
|
330
353
|
if (profile->measurer->track_allocations)
|
331
354
|
{
|
332
355
|
VALUE allocation_tracepoint = rb_tracepoint_new(Qnil, RUBY_INTERNAL_EVENT_NEWOBJ, prof_event_hook, profile);
|
333
356
|
rb_ary_push(profile->tracepoints, allocation_tracepoint);
|
334
357
|
}
|
335
|
-
|
358
|
+
|
336
359
|
for (int i = 0; i < RARRAY_LEN(profile->tracepoints); i++)
|
337
360
|
{
|
338
361
|
rb_tracepoint_enable(rb_ary_entry(profile->tracepoints, i));
|
339
362
|
}
|
340
363
|
}
|
341
364
|
|
342
|
-
void
|
343
|
-
prof_remove_hook(VALUE self)
|
365
|
+
void prof_remove_hook(VALUE self)
|
344
366
|
{
|
345
367
|
prof_profile_t* profile = prof_get_profile(self);
|
346
|
-
|
368
|
+
|
347
369
|
for (int i = 0; i < RARRAY_LEN(profile->tracepoints); i++)
|
348
370
|
{
|
349
371
|
rb_tracepoint_disable(rb_ary_entry(profile->tracepoints, i));
|
@@ -351,18 +373,16 @@ prof_remove_hook(VALUE self)
|
|
351
373
|
rb_ary_clear(profile->tracepoints);
|
352
374
|
}
|
353
375
|
|
354
|
-
prof_profile_t*
|
355
|
-
prof_get_profile(VALUE self)
|
376
|
+
prof_profile_t* prof_get_profile(VALUE self)
|
356
377
|
{
|
357
378
|
/* Can't use Data_Get_Struct because that triggers the event hook
|
358
379
|
ending up in endless recursion. */
|
359
380
|
return DATA_PTR(self);
|
360
381
|
}
|
361
382
|
|
362
|
-
static int
|
363
|
-
collect_threads(st_data_t key, st_data_t value, st_data_t result)
|
383
|
+
static int collect_threads(st_data_t key, st_data_t value, st_data_t result)
|
364
384
|
{
|
365
|
-
thread_data_t* thread_data = (thread_data_t*)
|
385
|
+
thread_data_t* thread_data = (thread_data_t*)value;
|
366
386
|
if (thread_data->trace)
|
367
387
|
{
|
368
388
|
VALUE threads_array = (VALUE)result;
|
@@ -372,35 +392,40 @@ collect_threads(st_data_t key, st_data_t value, st_data_t result)
|
|
372
392
|
}
|
373
393
|
|
374
394
|
/* ======== Profile Class ====== */
|
375
|
-
static int
|
376
|
-
mark_threads(st_data_t key, st_data_t value, st_data_t result)
|
395
|
+
static int mark_threads(st_data_t key, st_data_t value, st_data_t result)
|
377
396
|
{
|
378
|
-
thread_data_t
|
397
|
+
thread_data_t* thread = (thread_data_t*)value;
|
379
398
|
prof_thread_mark(thread);
|
380
399
|
return ST_CONTINUE;
|
381
400
|
}
|
382
401
|
|
383
|
-
static int
|
384
|
-
mark_methods(st_data_t key, st_data_t value, st_data_t result)
|
402
|
+
static int mark_methods(st_data_t key, st_data_t value, st_data_t result)
|
385
403
|
{
|
386
|
-
prof_method_t
|
404
|
+
prof_method_t* method = (prof_method_t*)value;
|
387
405
|
prof_method_mark(method);
|
388
406
|
return ST_CONTINUE;
|
389
407
|
}
|
390
408
|
|
391
|
-
static void
|
392
|
-
prof_mark(prof_profile_t *profile)
|
409
|
+
static void prof_mark(prof_profile_t* profile)
|
393
410
|
{
|
394
411
|
rb_gc_mark(profile->tracepoints);
|
395
|
-
|
396
|
-
|
412
|
+
rb_gc_mark(profile->running);
|
413
|
+
rb_gc_mark(profile->paused);
|
414
|
+
rb_gc_mark(profile->tracepoints);
|
415
|
+
|
416
|
+
// If GC stress is true (useful for debugging), when threads_table_create is called in the
|
417
|
+
// allocate method Ruby will immediately call this mark method. Thus the threads_tbl will be NULL.
|
418
|
+
if (profile->threads_tbl)
|
419
|
+
rb_st_foreach(profile->threads_tbl, mark_threads, 0);
|
420
|
+
|
421
|
+
if (profile->exclude_methods_tbl)
|
422
|
+
rb_st_foreach(profile->exclude_methods_tbl, mark_methods, 0);
|
397
423
|
}
|
398
424
|
|
399
425
|
/* Freeing the profile creates a cascade of freeing.
|
400
426
|
It fress the thread table, which frees its methods,
|
401
427
|
which frees its call infos. */
|
402
|
-
static void
|
403
|
-
prof_free(prof_profile_t *profile)
|
428
|
+
static void prof_free(prof_profile_t* profile)
|
404
429
|
{
|
405
430
|
profile->last_thread_data = NULL;
|
406
431
|
|
@@ -409,13 +434,13 @@ prof_free(prof_profile_t *profile)
|
|
409
434
|
|
410
435
|
if (profile->exclude_threads_tbl)
|
411
436
|
{
|
412
|
-
|
437
|
+
rb_st_free_table(profile->exclude_threads_tbl);
|
413
438
|
profile->exclude_threads_tbl = NULL;
|
414
439
|
}
|
415
440
|
|
416
441
|
if (profile->include_threads_tbl)
|
417
442
|
{
|
418
|
-
|
443
|
+
rb_st_free_table(profile->include_threads_tbl);
|
419
444
|
profile->include_threads_tbl = NULL;
|
420
445
|
}
|
421
446
|
|
@@ -429,8 +454,7 @@ prof_free(prof_profile_t *profile)
|
|
429
454
|
xfree(profile);
|
430
455
|
}
|
431
456
|
|
432
|
-
static VALUE
|
433
|
-
prof_allocate(VALUE klass)
|
457
|
+
static VALUE prof_allocate(VALUE klass)
|
434
458
|
{
|
435
459
|
VALUE result;
|
436
460
|
prof_profile_t* profile;
|
@@ -447,14 +471,12 @@ prof_allocate(VALUE klass)
|
|
447
471
|
return result;
|
448
472
|
}
|
449
473
|
|
450
|
-
static void
|
451
|
-
prof_exclude_common_methods(VALUE profile)
|
474
|
+
static void prof_exclude_common_methods(VALUE profile)
|
452
475
|
{
|
453
476
|
rb_funcall(profile, rb_intern("exclude_common_methods!"), 0);
|
454
477
|
}
|
455
478
|
|
456
|
-
static int
|
457
|
-
pop_frames(VALUE key, st_data_t value, st_data_t data)
|
479
|
+
static int pop_frames(VALUE key, st_data_t value, st_data_t data)
|
458
480
|
{
|
459
481
|
thread_data_t* thread_data = (thread_data_t*)value;
|
460
482
|
prof_profile_t* profile = (prof_profile_t*)data;
|
@@ -463,7 +485,7 @@ pop_frames(VALUE key, st_data_t value, st_data_t data)
|
|
463
485
|
if (profile->last_thread_data->fiber != thread_data->fiber)
|
464
486
|
switch_thread(profile, thread_data, measurement);
|
465
487
|
|
466
|
-
while (
|
488
|
+
while (prof_frame_pop(thread_data->stack, measurement));
|
467
489
|
|
468
490
|
return ST_CONTINUE;
|
469
491
|
}
|
@@ -471,7 +493,7 @@ pop_frames(VALUE key, st_data_t value, st_data_t data)
|
|
471
493
|
static void
|
472
494
|
prof_stop_threads(prof_profile_t* profile)
|
473
495
|
{
|
474
|
-
|
496
|
+
rb_st_foreach(profile->threads_tbl, pop_frames, (st_data_t)profile);
|
475
497
|
}
|
476
498
|
|
477
499
|
/* call-seq:
|
@@ -480,19 +502,19 @@ prof_stop_threads(prof_profile_t* profile)
|
|
480
502
|
|
481
503
|
Returns a new profiler. Possible options for the options hash are:
|
482
504
|
|
483
|
-
measure_mode
|
505
|
+
measure_mode: Measure mode. Specifies the profile measure mode.
|
484
506
|
If not specified, defaults to RubyProf::WALL_TIME.
|
485
|
-
|
486
|
-
include_threads:: Focus profiling on only the given threads. This will ignore
|
487
|
-
all other threads.
|
488
|
-
allow_exceptions:: Whether to raise exceptions encountered during profiling,
|
507
|
+
allow_exceptions: Whether to raise exceptions encountered during profiling,
|
489
508
|
or to suppress all exceptions during profiling
|
490
|
-
merge_fibers
|
509
|
+
merge_fibers: Whether profiling data for a given thread's fibers should all be
|
491
510
|
subsumed under a single entry. Basically only useful to produce
|
492
511
|
callgrind profiles.
|
493
|
-
|
494
|
-
|
495
|
-
|
512
|
+
track_allocations: Whether to track object allocations while profiling. True or false.
|
513
|
+
exclude_common: Exclude common methods from the profile. True or false.
|
514
|
+
exclude_threads: Threads to exclude from the profiling results.
|
515
|
+
include_threads: Focus profiling on only the given threads. This will ignore
|
516
|
+
all other threads. */
|
517
|
+
static VALUE prof_initialize(int argc, VALUE* argv, VALUE self)
|
496
518
|
{
|
497
519
|
prof_profile_t* profile = prof_get_profile(self);
|
498
520
|
VALUE mode_or_options;
|
@@ -552,7 +574,7 @@ prof_initialize(int argc, VALUE *argv, VALUE self)
|
|
552
574
|
for (i = 0; i < RARRAY_LEN(exclude_threads); i++)
|
553
575
|
{
|
554
576
|
VALUE thread = rb_ary_entry(exclude_threads, i);
|
555
|
-
|
577
|
+
rb_st_insert(profile->exclude_threads_tbl, thread, Qtrue);
|
556
578
|
}
|
557
579
|
}
|
558
580
|
|
@@ -564,7 +586,7 @@ prof_initialize(int argc, VALUE *argv, VALUE self)
|
|
564
586
|
for (i = 0; i < RARRAY_LEN(include_threads); i++)
|
565
587
|
{
|
566
588
|
VALUE thread = rb_ary_entry(include_threads, i);
|
567
|
-
|
589
|
+
rb_st_insert(profile->include_threads_tbl, thread, Qtrue);
|
568
590
|
}
|
569
591
|
}
|
570
592
|
|
@@ -580,8 +602,7 @@ prof_initialize(int argc, VALUE *argv, VALUE self)
|
|
580
602
|
paused? -> boolean
|
581
603
|
|
582
604
|
Returns whether a profile is currently paused.*/
|
583
|
-
static VALUE
|
584
|
-
prof_paused(VALUE self)
|
605
|
+
static VALUE prof_paused(VALUE self)
|
585
606
|
{
|
586
607
|
prof_profile_t* profile = prof_get_profile(self);
|
587
608
|
return profile->paused;
|
@@ -602,8 +623,7 @@ prof_running(VALUE self)
|
|
602
623
|
mode -> measure_mode
|
603
624
|
|
604
625
|
Returns the measure mode used in this profile.*/
|
605
|
-
static VALUE
|
606
|
-
prof_profile_measure_mode(VALUE self)
|
626
|
+
static VALUE prof_profile_measure_mode(VALUE self)
|
607
627
|
{
|
608
628
|
prof_profile_t* profile = prof_get_profile(self);
|
609
629
|
return INT2NUM(profile->measurer->mode);
|
@@ -613,8 +633,7 @@ prof_profile_measure_mode(VALUE self)
|
|
613
633
|
track_allocations -> boolean
|
614
634
|
|
615
635
|
Returns if object allocations were tracked in this profile.*/
|
616
|
-
static VALUE
|
617
|
-
prof_profile_track_allocations(VALUE self)
|
636
|
+
static VALUE prof_profile_track_allocations(VALUE self)
|
618
637
|
{
|
619
638
|
prof_profile_t* profile = prof_get_profile(self);
|
620
639
|
return profile->measurer->track_allocations ? Qtrue : Qfalse;
|
@@ -624,8 +643,7 @@ prof_profile_track_allocations(VALUE self)
|
|
624
643
|
start -> self
|
625
644
|
|
626
645
|
Starts recording profile data.*/
|
627
|
-
static VALUE
|
628
|
-
prof_start(VALUE self)
|
646
|
+
static VALUE prof_start(VALUE self)
|
629
647
|
{
|
630
648
|
char* trace_file_name;
|
631
649
|
|
@@ -642,20 +660,21 @@ prof_start(VALUE self)
|
|
642
660
|
|
643
661
|
/* open trace file if environment wants it */
|
644
662
|
trace_file_name = getenv("RUBY_PROF_TRACE");
|
645
|
-
|
646
|
-
|
647
|
-
|
648
|
-
|
649
|
-
|
650
|
-
|
651
|
-
|
652
|
-
|
653
|
-
|
654
|
-
|
655
|
-
|
656
|
-
|
657
|
-
|
658
|
-
|
663
|
+
|
664
|
+
if (trace_file_name != NULL)
|
665
|
+
{
|
666
|
+
if (strcmp(trace_file_name, "stdout") == 0)
|
667
|
+
{
|
668
|
+
trace_file = stdout;
|
669
|
+
}
|
670
|
+
else if (strcmp(trace_file_name, "stderr") == 0)
|
671
|
+
{
|
672
|
+
trace_file = stderr;
|
673
|
+
}
|
674
|
+
else
|
675
|
+
{
|
676
|
+
trace_file = fopen(trace_file_name, "w");
|
677
|
+
}
|
659
678
|
}
|
660
679
|
|
661
680
|
prof_install_hook(self);
|
@@ -666,8 +685,7 @@ prof_start(VALUE self)
|
|
666
685
|
pause -> self
|
667
686
|
|
668
687
|
Pauses collecting profile data. */
|
669
|
-
static VALUE
|
670
|
-
prof_pause(VALUE self)
|
688
|
+
static VALUE prof_pause(VALUE self)
|
671
689
|
{
|
672
690
|
prof_profile_t* profile = prof_get_profile(self);
|
673
691
|
if (profile->running == Qfalse)
|
@@ -679,7 +697,7 @@ prof_pause(VALUE self)
|
|
679
697
|
{
|
680
698
|
profile->paused = Qtrue;
|
681
699
|
profile->measurement_at_pause_resume = prof_measure(profile->measurer, NULL);
|
682
|
-
|
700
|
+
rb_st_foreach(profile->threads_tbl, pause_thread, (st_data_t)profile);
|
683
701
|
}
|
684
702
|
|
685
703
|
return self;
|
@@ -690,8 +708,7 @@ prof_pause(VALUE self)
|
|
690
708
|
resume(&block) -> self
|
691
709
|
|
692
710
|
Resumes recording profile data.*/
|
693
|
-
static VALUE
|
694
|
-
prof_resume(VALUE self)
|
711
|
+
static VALUE prof_resume(VALUE self)
|
695
712
|
{
|
696
713
|
prof_profile_t* profile = prof_get_profile(self);
|
697
714
|
if (profile->running == Qfalse)
|
@@ -703,7 +720,7 @@ prof_resume(VALUE self)
|
|
703
720
|
{
|
704
721
|
profile->paused = Qfalse;
|
705
722
|
profile->measurement_at_pause_resume = prof_measure(profile->measurer, NULL);
|
706
|
-
|
723
|
+
rb_st_foreach(profile->threads_tbl, unpause_thread, (st_data_t)profile);
|
707
724
|
}
|
708
725
|
|
709
726
|
return rb_block_given_p() ? rb_ensure(rb_yield, self, prof_pause, self) : self;
|
@@ -713,8 +730,7 @@ prof_resume(VALUE self)
|
|
713
730
|
stop -> self
|
714
731
|
|
715
732
|
Stops collecting profile data.*/
|
716
|
-
static VALUE
|
717
|
-
prof_stop(VALUE self)
|
733
|
+
static VALUE prof_stop(VALUE self)
|
718
734
|
{
|
719
735
|
prof_profile_t* profile = prof_get_profile(self);
|
720
736
|
|
@@ -728,15 +744,15 @@ prof_stop(VALUE self)
|
|
728
744
|
/* close trace file if open */
|
729
745
|
if (trace_file != NULL)
|
730
746
|
{
|
731
|
-
|
732
|
-
|
747
|
+
if (trace_file != stderr && trace_file != stdout)
|
748
|
+
{
|
733
749
|
#ifdef _MSC_VER
|
734
|
-
|
750
|
+
_fcloseall();
|
735
751
|
#else
|
736
|
-
|
752
|
+
fclose(trace_file);
|
737
753
|
#endif
|
738
|
-
|
739
|
-
|
754
|
+
}
|
755
|
+
trace_file = NULL;
|
740
756
|
}
|
741
757
|
|
742
758
|
prof_stop_threads(profile);
|
@@ -753,12 +769,11 @@ prof_stop(VALUE self)
|
|
753
769
|
threads -> Array of RubyProf::Thread
|
754
770
|
|
755
771
|
Returns an array of RubyProf::Thread instances that were profiled. */
|
756
|
-
static VALUE
|
757
|
-
prof_threads(VALUE self)
|
772
|
+
static VALUE prof_threads(VALUE self)
|
758
773
|
{
|
759
774
|
VALUE result = rb_ary_new();
|
760
775
|
prof_profile_t* profile = prof_get_profile(self);
|
761
|
-
|
776
|
+
rb_st_foreach(profile->threads_tbl, collect_threads, result);
|
762
777
|
return result;
|
763
778
|
}
|
764
779
|
|
@@ -773,8 +788,7 @@ prof_threads(VALUE self)
|
|
773
788
|
..
|
774
789
|
end
|
775
790
|
*/
|
776
|
-
static VALUE
|
777
|
-
prof_profile_object(VALUE self)
|
791
|
+
static VALUE prof_profile_object(VALUE self)
|
778
792
|
{
|
779
793
|
int result;
|
780
794
|
prof_profile_t* profile = prof_get_profile(self);
|
@@ -794,7 +808,6 @@ prof_profile_object(VALUE self)
|
|
794
808
|
}
|
795
809
|
|
796
810
|
return self;
|
797
|
-
|
798
811
|
}
|
799
812
|
|
800
813
|
/* Document-method: RubyProf::Profile::Profile
|
@@ -809,8 +822,7 @@ prof_profile_object(VALUE self)
|
|
809
822
|
..
|
810
823
|
end
|
811
824
|
*/
|
812
|
-
static VALUE
|
813
|
-
prof_profile_class(int argc, VALUE *argv, VALUE klass)
|
825
|
+
static VALUE prof_profile_class(int argc, VALUE* argv, VALUE klass)
|
814
826
|
{
|
815
827
|
return prof_profile_object(rb_class_new_instance(argc, argv, cProfile));
|
816
828
|
}
|
@@ -820,25 +832,22 @@ prof_profile_class(int argc, VALUE *argv, VALUE klass)
|
|
820
832
|
|
821
833
|
Excludes the method from profiling results.
|
822
834
|
*/
|
823
|
-
static VALUE
|
824
|
-
prof_exclude_method(VALUE self, VALUE klass, VALUE msym)
|
835
|
+
static VALUE prof_exclude_method(VALUE self, VALUE klass, VALUE msym)
|
825
836
|
{
|
826
837
|
prof_profile_t* profile = prof_get_profile(self);
|
827
838
|
|
828
|
-
st_data_t key = method_key(klass, msym);
|
829
|
-
prof_method_t *method;
|
830
|
-
|
831
839
|
if (profile->running == Qtrue)
|
832
840
|
{
|
833
841
|
rb_raise(rb_eRuntimeError, "RubyProf.start was already called");
|
834
842
|
}
|
835
843
|
|
836
|
-
|
844
|
+
st_data_t key = method_key(klass, msym);
|
845
|
+
prof_method_t* method = method_table_lookup(profile->exclude_methods_tbl, key);
|
837
846
|
|
838
847
|
if (!method)
|
839
848
|
{
|
840
|
-
|
841
|
-
|
849
|
+
method = prof_method_create(klass, msym, Qnil, 0);
|
850
|
+
method_table_insert(profile->exclude_methods_tbl, method->key, method);
|
842
851
|
}
|
843
852
|
|
844
853
|
return self;
|
@@ -862,7 +871,7 @@ VALUE prof_profile_load(VALUE self, VALUE data)
|
|
862
871
|
{
|
863
872
|
VALUE thread = rb_ary_entry(threads, i);
|
864
873
|
thread_data_t* thread_data = DATA_PTR(thread);
|
865
|
-
|
874
|
+
rb_st_insert(profile->threads_tbl, (st_data_t)thread_data->fiber_id, (st_data_t)thread_data);
|
866
875
|
}
|
867
876
|
|
868
877
|
return data;
|
@@ -870,8 +879,6 @@ VALUE prof_profile_load(VALUE self, VALUE data)
|
|
870
879
|
|
871
880
|
void rp_init_profile(void)
|
872
881
|
{
|
873
|
-
mProf = rb_define_module("RubyProf");
|
874
|
-
|
875
882
|
cProfile = rb_define_class_under(mProf, "Profile", rb_cObject);
|
876
883
|
rb_define_alloc_func(cProfile, prof_allocate);
|
877
884
|
|