ruby-prof 0.11.0.rc1 → 0.11.0.rc2
Sign up to get free protection for your applications and to get access to all the features.
- data/CHANGES +20 -5
- data/README.rdoc +10 -3
- data/ext/ruby_prof/rp_call_info.c +108 -79
- data/ext/ruby_prof/rp_call_info.h +1 -0
- data/ext/ruby_prof/rp_measure_cpu_time.c +111 -111
- data/ext/ruby_prof/rp_measure_gc_runs.c +1 -1
- data/ext/ruby_prof/rp_measure_memory.c +1 -1
- data/ext/ruby_prof/rp_measure_process_time.c +71 -71
- data/ext/ruby_prof/rp_measure_wall_time.c +1 -1
- data/ext/ruby_prof/rp_method.c +143 -73
- data/ext/ruby_prof/rp_method.h +7 -4
- data/ext/ruby_prof/rp_stack.c +16 -1
- data/ext/ruby_prof/rp_stack.h +4 -1
- data/ext/ruby_prof/rp_thread.c +165 -35
- data/ext/ruby_prof/rp_thread.h +8 -2
- data/ext/ruby_prof/ruby_prof.c +164 -171
- data/ext/ruby_prof/ruby_prof.h +53 -54
- data/ext/ruby_prof/vc/ruby_prof.sln +26 -0
- data/ext/ruby_prof/vc/ruby_prof.vcxproj +109 -0
- data/ext/ruby_prof/vc/ruby_prof_18.vcxproj +105 -0
- data/lib/ruby-prof/aggregate_call_info.rb +9 -7
- data/lib/ruby-prof/call_info.rb +2 -27
- data/lib/ruby-prof/call_info_visitor.rb +42 -0
- data/lib/ruby-prof/{empty.png → images/empty.png} +0 -0
- data/lib/ruby-prof/{minus.png → images/minus.png} +0 -0
- data/lib/ruby-prof/{plus.png → images/plus.png} +0 -0
- data/lib/ruby-prof/method_info.rb +13 -15
- data/lib/ruby-prof/{abstract_printer.rb → printers/abstract_printer.rb} +36 -2
- data/lib/ruby-prof/printers/call_info_printer.rb +40 -0
- data/lib/ruby-prof/{call_stack_printer.rb → printers/call_stack_printer.rb} +11 -16
- data/lib/ruby-prof/{call_tree_printer.rb → printers/call_tree_printer.rb} +4 -4
- data/lib/ruby-prof/{dot_printer.rb → printers/dot_printer.rb} +11 -31
- data/lib/ruby-prof/{flat_printer.rb → printers/flat_printer.rb} +26 -35
- data/lib/ruby-prof/{flat_printer_with_line_numbers.rb → printers/flat_printer_with_line_numbers.rb} +14 -25
- data/lib/ruby-prof/printers/graph_html_printer.rb +248 -0
- data/lib/ruby-prof/{graph_printer.rb → printers/graph_printer.rb} +31 -73
- data/lib/ruby-prof/{multi_printer.rb → printers/multi_printer.rb} +0 -0
- data/lib/ruby-prof/profile.rb +27 -22
- data/lib/ruby-prof/rack.rb +22 -12
- data/ruby-prof.gemspec +58 -0
- data/test/aggregate_test.rb +6 -6
- data/test/call_info_visitor_test.rb +31 -0
- data/test/duplicate_names_test.rb +1 -1
- data/test/dynamic_method_test.rb +1 -1
- data/test/enumerable_test.rb +1 -1
- data/test/exclude_threads_test.rb +2 -2
- data/test/gc_test.rb +35 -0
- data/test/line_number_test.rb +2 -2
- data/test/measure_cpu_time_test.rb +5 -5
- data/test/measure_process_time_test.rb +5 -5
- data/test/measure_wall_time_test.rb +5 -5
- data/test/method_elimination_test.rb +3 -3
- data/test/module_test.rb +1 -1
- data/test/no_method_class_test.rb +1 -1
- data/test/printers_test.rb +16 -8
- data/test/recursive_test.rb +115 -91
- data/test/stack_test.rb +1 -1
- data/test/start_stop_test.rb +13 -13
- data/test/summarize_test.rb +48 -0
- data/test/test_suite.rb +1 -0
- data/test/thread_test.rb +16 -12
- data/test/unique_call_path_test.rb +10 -10
- metadata +64 -85
- data/lib/1.8/ruby_prof.so +0 -0
- data/lib/1.9/ruby_prof.exp +0 -0
- data/lib/1.9/ruby_prof.ilk +0 -0
- data/lib/1.9/ruby_prof.lib +0 -0
- data/lib/1.9/ruby_prof.pdb +0 -0
- data/lib/1.9/ruby_prof.so +0 -0
- data/lib/ruby-prof.rb +0 -70
- data/lib/ruby-prof/graph_html_printer.rb +0 -286
- data/lib/ruby-prof/symbol_to_proc.rb +0 -10
- data/lib/ruby_prof.exp +0 -0
- data/lib/ruby_prof.ilk +0 -0
- data/lib/ruby_prof.lib +0 -0
- data/lib/ruby_prof.pdb +0 -0
- data/lib/ruby_prof.so +0 -0
- data/lib/unprof.rb +0 -10
- data/test/do_nothing.rb +0 -0
@@ -81,7 +81,7 @@ void rp_init_measure_gc_runs()
|
|
81
81
|
{
|
82
82
|
rb_define_const(mProf, "GC_RUNS", INT2NUM(MEASURE_GC_RUNS));
|
83
83
|
rb_define_const(mProf, "GC_RUNS_ENABLED", MEASURE_GC_RUNS_ENABLED);
|
84
|
-
|
84
|
+
|
85
85
|
cMeasureGcRuns = rb_define_class_under(mMeasure, "GcRuns", rb_cObject);
|
86
86
|
rb_define_singleton_method(cMeasureGcRuns, "measure", prof_measure_gc_runs, 0);
|
87
87
|
}
|
@@ -74,7 +74,7 @@ prof_measure_memory(VALUE self)
|
|
74
74
|
void rp_init_measure_memory()
|
75
75
|
{
|
76
76
|
rb_define_const(mProf, "MEMORY", INT2NUM(MEASURE_MEMORY));
|
77
|
-
|
77
|
+
rb_define_const(mProf, "MEMORY_ENABLED", MEASURE_MEMORY_ENABLED);
|
78
78
|
|
79
79
|
cMeasureMemory = rb_define_class_under(mMeasure, "Memory", rb_cObject);
|
80
80
|
rb_define_singleton_method(cMeasureMemory, "measure", prof_measure_memory, 0);
|
@@ -1,71 +1,71 @@
|
|
1
|
-
/* Copyright (C) 2005-2011 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
|
-
#include <time.h>
|
6
|
-
|
7
|
-
static VALUE cMeasureProcessTime;
|
8
|
-
|
9
|
-
static double
|
10
|
-
measure_process_time()
|
11
|
-
{
|
12
|
-
#if defined(__linux__)
|
13
|
-
struct timespec clock;
|
14
|
-
clock_gettime(CLOCK_PROCESS_CPUTIME_ID , &clock);
|
15
|
-
return (clock.tv_sec * 1000000000 + clock.tv_nsec) / 1000000000.0;
|
16
|
-
#elif defined(_win32)
|
17
|
-
FILETIME createTime;
|
18
|
-
FILETIME exitTime;
|
19
|
-
FILETIME sysTime;
|
20
|
-
FILETIME cpuTime;
|
21
|
-
|
22
|
-
ULARGE_INTEGER sysTimeInt;
|
23
|
-
ULARGE_INTEGER cpuTimeInt;
|
24
|
-
ULONGLONG totalTime;
|
25
|
-
|
26
|
-
GetProcessTimes(GetCurrentProcess(), &createTime, &exitTime, &sysTime, &cpuTime);
|
27
|
-
|
28
|
-
/* Doing this based on MSFT's recommendation in the FILETIME structure documentation at
|
29
|
-
http://msdn.microsoft.com/en-us/library/ms724284%28VS.85%29.aspx*/
|
30
|
-
|
31
|
-
sysTimeInt.LowPart = sysTime.dwLowDateTime;
|
32
|
-
sysTimeInt.HighPart = sysTime.dwHighDateTime;
|
33
|
-
cpuTimeInt.LowPart = cpuTime.dwLowDateTime;
|
34
|
-
cpuTimeInt.HighPart = cpuTime.dwHighDateTime;
|
35
|
-
|
36
|
-
totalTime = sysTimeInt.QuadPart + cpuTimeInt.QuadPart;
|
37
|
-
|
38
|
-
// Times are in 100-nanosecond time units. So instead of 10-9 use 10-7
|
39
|
-
return totalTime / 10000000.0;
|
40
|
-
#else
|
41
|
-
return ((double)clock()) / CLOCKS_PER_SEC;
|
42
|
-
#endif
|
43
|
-
}
|
44
|
-
|
45
|
-
/* call-seq:
|
46
|
-
measure_process_time -> float
|
47
|
-
|
48
|
-
Returns the process time.*/
|
49
|
-
static VALUE
|
50
|
-
prof_measure_process_time(VALUE self)
|
51
|
-
{
|
52
|
-
return rb_float_new(measure_process_time());
|
53
|
-
}
|
54
|
-
|
55
|
-
prof_measurer_t* prof_measurer_process_time()
|
56
|
-
{
|
57
|
-
prof_measurer_t* measure = ALLOC(prof_measurer_t);
|
58
|
-
measure->measure = measure_process_time;
|
59
|
-
return measure;
|
60
|
-
}
|
61
|
-
|
62
|
-
|
63
|
-
void rp_init_measure_process_time()
|
64
|
-
{
|
65
|
-
rb_define_const(mProf, "CLOCKS_PER_SEC", INT2NUM(CLOCKS_PER_SEC));
|
66
|
-
rb_define_const(mProf, "PROCESS_TIME", INT2NUM(MEASURE_PROCESS_TIME));
|
67
|
-
rb_define_const(mProf, "PROCESS_TIME_ENABLED", Qtrue);
|
68
|
-
|
69
|
-
cMeasureProcessTime = rb_define_class_under(mMeasure, "ProcessTime", rb_cObject);
|
70
|
-
rb_define_singleton_method(cMeasureProcessTime, "measure", prof_measure_process_time, 0);
|
71
|
-
}
|
1
|
+
/* Copyright (C) 2005-2011 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
|
+
#include <time.h>
|
6
|
+
|
7
|
+
static VALUE cMeasureProcessTime;
|
8
|
+
|
9
|
+
static double
|
10
|
+
measure_process_time()
|
11
|
+
{
|
12
|
+
#if defined(__linux__)
|
13
|
+
struct timespec clock;
|
14
|
+
clock_gettime(CLOCK_PROCESS_CPUTIME_ID , &clock);
|
15
|
+
return (clock.tv_sec * 1000000000 + clock.tv_nsec) / 1000000000.0;
|
16
|
+
#elif defined(_win32)
|
17
|
+
FILETIME createTime;
|
18
|
+
FILETIME exitTime;
|
19
|
+
FILETIME sysTime;
|
20
|
+
FILETIME cpuTime;
|
21
|
+
|
22
|
+
ULARGE_INTEGER sysTimeInt;
|
23
|
+
ULARGE_INTEGER cpuTimeInt;
|
24
|
+
ULONGLONG totalTime;
|
25
|
+
|
26
|
+
GetProcessTimes(GetCurrentProcess(), &createTime, &exitTime, &sysTime, &cpuTime);
|
27
|
+
|
28
|
+
/* Doing this based on MSFT's recommendation in the FILETIME structure documentation at
|
29
|
+
http://msdn.microsoft.com/en-us/library/ms724284%28VS.85%29.aspx*/
|
30
|
+
|
31
|
+
sysTimeInt.LowPart = sysTime.dwLowDateTime;
|
32
|
+
sysTimeInt.HighPart = sysTime.dwHighDateTime;
|
33
|
+
cpuTimeInt.LowPart = cpuTime.dwLowDateTime;
|
34
|
+
cpuTimeInt.HighPart = cpuTime.dwHighDateTime;
|
35
|
+
|
36
|
+
totalTime = sysTimeInt.QuadPart + cpuTimeInt.QuadPart;
|
37
|
+
|
38
|
+
// Times are in 100-nanosecond time units. So instead of 10-9 use 10-7
|
39
|
+
return totalTime / 10000000.0;
|
40
|
+
#else
|
41
|
+
return ((double)clock()) / CLOCKS_PER_SEC;
|
42
|
+
#endif
|
43
|
+
}
|
44
|
+
|
45
|
+
/* call-seq:
|
46
|
+
measure_process_time -> float
|
47
|
+
|
48
|
+
Returns the process time.*/
|
49
|
+
static VALUE
|
50
|
+
prof_measure_process_time(VALUE self)
|
51
|
+
{
|
52
|
+
return rb_float_new(measure_process_time());
|
53
|
+
}
|
54
|
+
|
55
|
+
prof_measurer_t* prof_measurer_process_time()
|
56
|
+
{
|
57
|
+
prof_measurer_t* measure = ALLOC(prof_measurer_t);
|
58
|
+
measure->measure = measure_process_time;
|
59
|
+
return measure;
|
60
|
+
}
|
61
|
+
|
62
|
+
|
63
|
+
void rp_init_measure_process_time()
|
64
|
+
{
|
65
|
+
rb_define_const(mProf, "CLOCKS_PER_SEC", INT2NUM(CLOCKS_PER_SEC));
|
66
|
+
rb_define_const(mProf, "PROCESS_TIME", INT2NUM(MEASURE_PROCESS_TIME));
|
67
|
+
rb_define_const(mProf, "PROCESS_TIME_ENABLED", Qtrue);
|
68
|
+
|
69
|
+
cMeasureProcessTime = rb_define_class_under(mMeasure, "ProcessTime", rb_cObject);
|
70
|
+
rb_define_singleton_method(cMeasureProcessTime, "measure", prof_measure_process_time, 0);
|
71
|
+
}
|
@@ -37,6 +37,6 @@ void rp_init_measure_wall_time()
|
|
37
37
|
rb_define_const(mProf, "WALL_TIME", INT2NUM(MEASURE_WALL_TIME));
|
38
38
|
rb_define_const(mProf, "WALL_TIME_ENABLED", Qtrue);
|
39
39
|
|
40
|
-
|
40
|
+
cMeasureWallTime = rb_define_class_under(mMeasure, "WallTime", rb_cObject);
|
41
41
|
rb_define_singleton_method(cMeasureWallTime, "measure", prof_measure_wall_time, 0);
|
42
42
|
}
|
data/ext/ruby_prof/rp_method.c
CHANGED
@@ -118,6 +118,129 @@ full_name(VALUE klass, ID mid)
|
|
118
118
|
return result;
|
119
119
|
}
|
120
120
|
|
121
|
+
void
|
122
|
+
method_key(prof_method_key_t* key, VALUE klass, ID mid)
|
123
|
+
{
|
124
|
+
/* Is this an include for a module? If so get the actual
|
125
|
+
module class since we want to combine all profiling
|
126
|
+
results for that module. */
|
127
|
+
if (klass != 0)
|
128
|
+
klass = (BUILTIN_TYPE(klass) == T_ICLASS ? RBASIC(klass)->klass : klass);
|
129
|
+
|
130
|
+
key->klass = klass;
|
131
|
+
key->mid = mid;
|
132
|
+
key->key = (klass << 4) + (mid << 2);
|
133
|
+
}
|
134
|
+
|
135
|
+
/* ================ prof_method_t =================*/
|
136
|
+
prof_method_t*
|
137
|
+
prof_method_create(VALUE klass, ID mid, const char* source_file, int line)
|
138
|
+
{
|
139
|
+
prof_method_t *result = ALLOC(prof_method_t);
|
140
|
+
result->object = Qnil;
|
141
|
+
result->call_infos = prof_call_infos_create();
|
142
|
+
result->call_infos2 = Qnil;
|
143
|
+
|
144
|
+
result->key = ALLOC(prof_method_key_t);
|
145
|
+
method_key(result->key, klass, mid);
|
146
|
+
|
147
|
+
//result->call_info_table = call_info_table_create();
|
148
|
+
|
149
|
+
if (source_file != NULL)
|
150
|
+
{
|
151
|
+
size_t len = strlen(source_file) + 1;
|
152
|
+
char *buffer = ALLOC_N(char, len);
|
153
|
+
|
154
|
+
MEMCPY(buffer, source_file, char, len);
|
155
|
+
result->source_file = buffer;
|
156
|
+
}
|
157
|
+
else
|
158
|
+
{
|
159
|
+
result->source_file = source_file;
|
160
|
+
}
|
161
|
+
result->line = line;
|
162
|
+
|
163
|
+
return result;
|
164
|
+
}
|
165
|
+
|
166
|
+
/* The underlying c structures are freed when the parent profile is freed.
|
167
|
+
However, on shutdown the Ruby GC frees objects in any will-nilly order.
|
168
|
+
That means the ruby thread object wrapping the c thread struct may
|
169
|
+
be freed before the parent profile. Thus we add in a free function
|
170
|
+
for the garbage collector so that if it does get called will nil
|
171
|
+
out our Ruby object reference.*/
|
172
|
+
static void
|
173
|
+
prof_method_ruby_gc_free(prof_method_t* method)
|
174
|
+
{
|
175
|
+
/* Has this thread object been accessed by Ruby? If
|
176
|
+
yes clean it up so to avoid a segmentation fault. */
|
177
|
+
if (method->object != Qnil)
|
178
|
+
{
|
179
|
+
RDATA(method->object)->data = NULL;
|
180
|
+
RDATA(method->object)->dfree = NULL;
|
181
|
+
RDATA(method->object)->dmark = NULL;
|
182
|
+
}
|
183
|
+
method->object = Qnil;
|
184
|
+
}
|
185
|
+
|
186
|
+
static void
|
187
|
+
prof_method_free(prof_method_t* method)
|
188
|
+
{
|
189
|
+
prof_method_ruby_gc_free(method);
|
190
|
+
prof_call_infos_free(method->call_infos);
|
191
|
+
|
192
|
+
xfree(method->key);
|
193
|
+
method->key = NULL;
|
194
|
+
|
195
|
+
xfree(method);
|
196
|
+
}
|
197
|
+
|
198
|
+
/*static int
|
199
|
+
mark_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
|
+
prof_call_info_mark(call_info);
|
203
|
+
return ST_CONTINUE;
|
204
|
+
}
|
205
|
+
*/
|
206
|
+
|
207
|
+
void
|
208
|
+
prof_method_mark(prof_method_t *method)
|
209
|
+
{
|
210
|
+
if (method->object)
|
211
|
+
rb_gc_mark(method->object);
|
212
|
+
|
213
|
+
if (method->call_infos2)
|
214
|
+
rb_gc_mark(method->call_infos2);
|
215
|
+
|
216
|
+
if (method->call_infos->object)
|
217
|
+
rb_gc_mark(method->call_infos->object);
|
218
|
+
|
219
|
+
//st_foreach(method->call_info_table, mark_call_infos, NULL);
|
220
|
+
}
|
221
|
+
|
222
|
+
VALUE
|
223
|
+
prof_method_wrap(prof_method_t *result)
|
224
|
+
{
|
225
|
+
if (result->object == Qnil)
|
226
|
+
{
|
227
|
+
result->object = Data_Wrap_Struct(cMethodInfo, prof_method_mark, prof_method_ruby_gc_free, result);
|
228
|
+
}
|
229
|
+
return result->object;
|
230
|
+
}
|
231
|
+
|
232
|
+
static prof_method_t *
|
233
|
+
get_prof_method(VALUE self)
|
234
|
+
{
|
235
|
+
/* Can't use Data_Get_Struct because that triggers the event hook
|
236
|
+
ending up in endless recursion. */
|
237
|
+
prof_method_t* result = DATA_PTR(self);
|
238
|
+
|
239
|
+
if (!result)
|
240
|
+
rb_raise(rb_eRuntimeError, "This RubyProf::MethodInfo instance has already been freed, likely because its profile has been freed.");
|
241
|
+
|
242
|
+
return result;
|
243
|
+
}
|
121
244
|
|
122
245
|
/* ================ Method Table =================*/
|
123
246
|
int
|
@@ -143,6 +266,21 @@ method_table_create()
|
|
143
266
|
return st_init_table(&type_method_hash);
|
144
267
|
}
|
145
268
|
|
269
|
+
static int
|
270
|
+
method_table_free_iterator(st_data_t key, st_data_t value, st_data_t dummy)
|
271
|
+
{
|
272
|
+
prof_method_free((prof_method_t*)value);
|
273
|
+
return ST_CONTINUE;
|
274
|
+
}
|
275
|
+
|
276
|
+
void
|
277
|
+
method_table_free(st_table *table)
|
278
|
+
{
|
279
|
+
st_foreach(table, method_table_free_iterator, 0);
|
280
|
+
st_free_table(table);
|
281
|
+
}
|
282
|
+
|
283
|
+
|
146
284
|
size_t
|
147
285
|
method_table_insert(st_table *table, const prof_method_key_t *key, prof_method_t *val)
|
148
286
|
{
|
@@ -163,15 +301,6 @@ method_table_lookup(st_table *table, const prof_method_key_t* key)
|
|
163
301
|
}
|
164
302
|
}
|
165
303
|
|
166
|
-
void
|
167
|
-
method_table_free(st_table *table)
|
168
|
-
{
|
169
|
-
/* Don't free the contents since they are wrapped by
|
170
|
-
Ruby objects! */
|
171
|
-
st_free_table(table);
|
172
|
-
}
|
173
|
-
|
174
|
-
|
175
304
|
/* ================ Method Info =================*/
|
176
305
|
/* Document-class: RubyProf::MethodInfo
|
177
306
|
The RubyProf::MethodInfo class stores profiling data for a method.
|
@@ -182,69 +311,6 @@ created. RubyProf::MethodInfo objects can be accessed via
|
|
182
311
|
the RubyProf::Result object.
|
183
312
|
*/
|
184
313
|
|
185
|
-
prof_method_t*
|
186
|
-
prof_method_create(prof_method_key_t *key, const char* source_file, int line)
|
187
|
-
{
|
188
|
-
prof_method_t *result = ALLOC(prof_method_t);
|
189
|
-
result->object = Qnil;
|
190
|
-
result->key = ALLOC(prof_method_key_t);
|
191
|
-
method_key(result->key, key->klass, key->mid);
|
192
|
-
|
193
|
-
result->call_infos = prof_call_infos_create();
|
194
|
-
|
195
|
-
if (source_file != NULL)
|
196
|
-
{
|
197
|
-
size_t len = strlen(source_file) + 1;
|
198
|
-
char *buffer = ALLOC_N(char, len);
|
199
|
-
|
200
|
-
MEMCPY(buffer, source_file, char, len);
|
201
|
-
result->source_file = buffer;
|
202
|
-
}
|
203
|
-
else
|
204
|
-
{
|
205
|
-
result->source_file = source_file;
|
206
|
-
}
|
207
|
-
result->line = line;
|
208
|
-
|
209
|
-
return result;
|
210
|
-
}
|
211
|
-
|
212
|
-
void
|
213
|
-
prof_method_mark(prof_method_t *method)
|
214
|
-
{
|
215
|
-
rb_gc_mark(method->call_infos->object);
|
216
|
-
rb_gc_mark(method->key->klass);
|
217
|
-
}
|
218
|
-
|
219
|
-
static void
|
220
|
-
prof_method_free(prof_method_t *method)
|
221
|
-
{
|
222
|
-
if (method->source_file)
|
223
|
-
{
|
224
|
-
xfree((char*)method->source_file);
|
225
|
-
}
|
226
|
-
|
227
|
-
prof_call_infos_free(method->call_infos);
|
228
|
-
xfree(method->key);
|
229
|
-
xfree(method);
|
230
|
-
}
|
231
|
-
|
232
|
-
VALUE
|
233
|
-
prof_method_wrap(prof_method_t *result)
|
234
|
-
{
|
235
|
-
if (result->object == Qnil)
|
236
|
-
{
|
237
|
-
result->object = Data_Wrap_Struct(cMethodInfo, prof_method_mark, prof_method_free, result);
|
238
|
-
}
|
239
|
-
return result->object;
|
240
|
-
}
|
241
|
-
|
242
|
-
static prof_method_t *
|
243
|
-
get_prof_method(VALUE obj)
|
244
|
-
{
|
245
|
-
return (prof_method_t *) DATA_PTR(obj);
|
246
|
-
}
|
247
|
-
|
248
314
|
/* call-seq:
|
249
315
|
line_no -> int
|
250
316
|
|
@@ -343,7 +409,11 @@ static VALUE
|
|
343
409
|
prof_method_call_infos(VALUE self)
|
344
410
|
{
|
345
411
|
prof_method_t *method = get_prof_method(self);
|
346
|
-
|
412
|
+
if (method->call_infos2 == Qnil)
|
413
|
+
{
|
414
|
+
method->call_infos2 = prof_call_infos_wrap(method->call_infos);
|
415
|
+
}
|
416
|
+
return method->call_infos2;
|
347
417
|
}
|
348
418
|
|
349
419
|
void rp_init_method_info()
|
data/ext/ruby_prof/rp_method.h
CHANGED
@@ -6,7 +6,7 @@
|
|
6
6
|
|
7
7
|
#include <ruby.h>
|
8
8
|
|
9
|
-
#ifndef RUBY_VM
|
9
|
+
#ifndef RUBY_VM
|
10
10
|
#include <st.h>
|
11
11
|
typedef st_data_t st_index_t;
|
12
12
|
#endif
|
@@ -18,10 +18,10 @@ typedef struct
|
|
18
18
|
{
|
19
19
|
VALUE klass; /* The method's class. */
|
20
20
|
ID mid; /* The method id. */
|
21
|
-
int depth; /* The recursion depth. */
|
22
21
|
st_index_t key; /* Cache calculated key */
|
23
22
|
} prof_method_key_t;
|
24
23
|
|
24
|
+
|
25
25
|
/* Forward declaration, see rp_call_info.h */
|
26
26
|
struct prof_call_infos_t;
|
27
27
|
|
@@ -31,18 +31,21 @@ typedef struct
|
|
31
31
|
prof_method_key_t *key; /* Method key */
|
32
32
|
const char *source_file; /* The method's source file */
|
33
33
|
int line; /* The method's line number. */
|
34
|
-
struct prof_call_infos_t *call_infos;
|
34
|
+
struct prof_call_infos_t *call_infos; /* Call info objects for this method */
|
35
35
|
VALUE object; /* Cached ruby object */
|
36
|
+
VALUE call_infos2; /* Cached array of RubyProf::CallInfo */
|
36
37
|
} prof_method_t;
|
37
38
|
|
38
39
|
void rp_init_method_info(void);
|
39
40
|
|
41
|
+
void method_key(prof_method_key_t* key, VALUE klass, ID mid);
|
42
|
+
|
40
43
|
st_table * method_table_create();
|
41
44
|
prof_method_t * method_table_lookup(st_table *table, const prof_method_key_t* key);
|
42
45
|
size_t method_table_insert(st_table *table, const prof_method_key_t *key, prof_method_t *val);
|
43
46
|
void method_table_free(st_table *table);
|
44
47
|
|
45
|
-
prof_method_t* prof_method_create(
|
48
|
+
prof_method_t* prof_method_create(VALUE klass, ID mid, const char* source_file, int line);
|
46
49
|
VALUE prof_method_wrap(prof_method_t *result);
|
47
50
|
void prof_method_mark(prof_method_t *method);
|
48
51
|
|