ruby-prof 0.11.0.rc1-x86-mingw32 → 0.11.0.rc2-x86-mingw32
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/CHANGES +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/1.8/ruby_prof.so +0 -0
- data/lib/1.9/ruby_prof.so +0 -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 +65 -85
- 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/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
|
|