ruby-prof 0.11.0.rc3 → 0.11.2
Sign up to get free protection for your applications and to get access to all the features.
- data/CHANGES +28 -0
- data/Rakefile +1 -0
- data/bin/ruby-prof +57 -0
- data/ext/ruby_prof/rp_measure_allocations.c +9 -30
- data/ext/ruby_prof/rp_measure_gc_runs.c +11 -33
- data/ext/ruby_prof/rp_measure_gc_time.c +7 -19
- data/ext/ruby_prof/rp_measure_memory.c +20 -27
- data/ext/ruby_prof/rp_stack.c +17 -1
- data/ext/ruby_prof/rp_stack.h +8 -0
- data/ext/ruby_prof/ruby_prof.c +79 -16
- data/ext/ruby_prof/ruby_prof.h +2 -0
- data/ext/ruby_prof/vc/ruby_prof_18.vcxproj +3 -0
- data/ext/ruby_prof/version.h +2 -2
- data/lib/ruby-prof/compatibility.rb +43 -23
- data/lib/ruby-prof/printers/flat_printer.rb +1 -1
- data/lib/ruby-prof/printers/graph_html_printer.rb +1 -1
- data/lib/ruby-prof/printers/graph_printer.rb +1 -1
- data/ruby-prof.gemspec +1 -2
- data/test/basic_test.rb +55 -1
- data/test/line_number_test.rb +4 -6
- data/test/measure_cpu_time_test.rb +0 -3
- data/test/multi_printer_test.rb +0 -1
- data/test/pause_resume_test.rb +61 -0
- data/test/pause_test.rb +57 -0
- data/test/prime.rb +1 -1
- data/test/prime_test.rb +1 -1
- data/test/recursive_test.rb +9 -11
- data/test/test_suite.rb +2 -2
- data/test/thread_test.rb +5 -5
- data/test/unique_call_path_test.rb +0 -1
- metadata +8 -7
- data/test/summarize_test.rb +0 -48
data/CHANGES
CHANGED
@@ -1,3 +1,31 @@
|
|
1
|
+
0.11.2 (2012-05-06)
|
2
|
+
======================
|
3
|
+
* Fix compile issue with BOOL. Should be _Bool for C99.
|
4
|
+
|
5
|
+
|
6
|
+
0.11.1 (2012-05-06)
|
7
|
+
======================
|
8
|
+
* Added option --exclude-common-callbacks, plus exclude #map and #inject in common cycles (Vasily Fedoseyev)
|
9
|
+
* Add option --exclude-common-cycles to exclude common iterators (Vasily Fedoseyev)
|
10
|
+
* Allow method elimination from command line via '-x' and '-X' keys (Vasily Fedoseyev)
|
11
|
+
|
12
|
+
|
13
|
+
0.11.0 (2012-05-05)
|
14
|
+
======================
|
15
|
+
* Fix pause/resume so it actually works and add tests (David Barri)
|
16
|
+
* Resume now returns the result of the block when given (David Barri)
|
17
|
+
* Make recursive method explanation more clear (Charlie Savage)
|
18
|
+
* Fix ruby warnings (Charlie Savage)
|
19
|
+
* Toggle GC.enable_stats when profiling for memory to get the data (Vasily Fedoseyev)
|
20
|
+
* Fix patched ruby support and remove some warnings (Vasily Fedoseyev)
|
21
|
+
* Fix tests on 1.8.7 (rogerdpack)
|
22
|
+
|
23
|
+
|
24
|
+
0.11.0.rc3 (2012-03-26)
|
25
|
+
======================
|
26
|
+
* Include missing files in gemspec (Charlie Savage).
|
27
|
+
|
28
|
+
|
1
29
|
0.11.0.rc2 (2012-03-25)
|
2
30
|
======================
|
3
31
|
* Lots of improvements to Rack handler - this can be used to profile requests
|
data/Rakefile
CHANGED
data/bin/ruby-prof
CHANGED
@@ -172,6 +172,59 @@ opts = OptionParser.new do |opts|
|
|
172
172
|
options.exec ||= []
|
173
173
|
options.exec << code
|
174
174
|
end
|
175
|
+
|
176
|
+
opts.on('-x regexp', '--exclude regexp', 'exclude methods by regexp (see method elimination)') do|meth|
|
177
|
+
options.eliminate_methods ||= []
|
178
|
+
options.eliminate_methods << Regexp.new(meth)
|
179
|
+
end
|
180
|
+
|
181
|
+
opts.on('-X file', '--exclude-file file', 'exclude methods by regexp listed in file (see method elimination)') do|file|
|
182
|
+
options.eliminate_methods_files ||= []
|
183
|
+
options.eliminate_methods_files << file
|
184
|
+
end
|
185
|
+
|
186
|
+
opts.on('--exclude-common-cycles', 'make common iterators like Integer#times appear inlined') do|meth|
|
187
|
+
options.eliminate_methods ||= []
|
188
|
+
options.eliminate_methods += %w{
|
189
|
+
Integer#times
|
190
|
+
Integer#upto
|
191
|
+
Integer#downto
|
192
|
+
Enumerator#each
|
193
|
+
Enumerator#each_with_index
|
194
|
+
Enumerator#each_with_object
|
195
|
+
|
196
|
+
Array#each
|
197
|
+
Array#each_index
|
198
|
+
Array#reverse_each
|
199
|
+
Array#map
|
200
|
+
|
201
|
+
Hash#each
|
202
|
+
Hash#each_pair
|
203
|
+
Hash#each_key
|
204
|
+
Hash#each_value
|
205
|
+
|
206
|
+
Range#each
|
207
|
+
Enumerable#each_cons
|
208
|
+
Enumerable#each_entry
|
209
|
+
Enumerable#each_slice
|
210
|
+
Enumerable#each_with_index
|
211
|
+
Enumerable#each_with_object
|
212
|
+
Enumerable#reverse_each
|
213
|
+
Enumerable#inject
|
214
|
+
Enumerable#collect
|
215
|
+
Enumerable#reduce
|
216
|
+
}
|
217
|
+
#TODO: may be the whole Enumerable module should be excluded via 'Enumerable#.*', we need feedback on use cases.
|
218
|
+
end
|
219
|
+
|
220
|
+
opts.on('--exclude-common-callbacks', 'make common callbacks invocations like Integer#times appear inlined so you can see call origins in graph') do|meth|
|
221
|
+
options.eliminate_methods ||= []
|
222
|
+
options.eliminate_methods += %w{
|
223
|
+
Method#call
|
224
|
+
Proc#call
|
225
|
+
ActiveSupport::Callbacks::ClassMethods#__run_callback
|
226
|
+
}
|
227
|
+
end
|
175
228
|
end
|
176
229
|
|
177
230
|
begin
|
@@ -201,6 +254,10 @@ at_exit {
|
|
201
254
|
# Stop profiling
|
202
255
|
result = RubyProf.stop
|
203
256
|
|
257
|
+
# Eliminate unwanted methods from call graph
|
258
|
+
result.eliminate_methods! options.eliminate_methods if options.eliminate_methods
|
259
|
+
options.eliminate_methods_files.each{|f| result.eliminate_methods!(f)} if options.eliminate_methods_files
|
260
|
+
|
204
261
|
# Create a printer
|
205
262
|
printer = options.printer.new(result)
|
206
263
|
printer_options = {:min_percent => options.min_percent, :sort_method => options.sort_method}
|
@@ -8,50 +8,29 @@
|
|
8
8
|
static VALUE cMeasureAllocations;
|
9
9
|
|
10
10
|
#if defined(HAVE_RB_OS_ALLOCATED_OBJECTS)
|
11
|
-
|
11
|
+
unsigned LONG_LONG rb_os_allocated_objects();
|
12
|
+
#endif
|
13
|
+
|
14
|
+
#if defined(HAVE_RB_GC_MALLOC_ALLOCATIONS)
|
15
|
+
unsigned LONG_LONG rb_gc_malloc_allocations();
|
16
|
+
#endif
|
12
17
|
|
13
18
|
static double
|
14
19
|
measure_allocations()
|
15
20
|
{
|
21
|
+
#if defined(HAVE_RB_OS_ALLOCATED_OBJECTS)
|
22
|
+
#define MEASURE_ALLOCATIONS_ENABLED Qtrue
|
16
23
|
return rb_os_allocated_objects();
|
17
|
-
}
|
18
|
-
|
19
|
-
/* Document-method: prof_measure_allocations
|
20
|
-
call-seq:
|
21
|
-
measure_allocations -> int
|
22
|
-
|
23
|
-
Returns the total number of object allocations since Ruby started.*/
|
24
|
-
static VALUE
|
25
|
-
prof_measure_allocations(VALUE self)
|
26
|
-
{
|
27
|
-
#if defined(HAVE_LONG_LONG)
|
28
|
-
return ULL2NUM(rb_os_allocated_objects());
|
29
|
-
#else
|
30
|
-
return ULONG2NUM(rb_os_allocated_objects());
|
31
|
-
#endif
|
32
|
-
}
|
33
24
|
|
34
25
|
#elif defined(HAVE_RB_GC_MALLOC_ALLOCATIONS)
|
35
|
-
|
36
26
|
#define MEASURE_ALLOCATIONS_ENABLED Qtrue
|
37
|
-
|
38
|
-
static double
|
39
|
-
measure_allocations()
|
40
|
-
{
|
41
27
|
return rb_gc_malloc_allocations();
|
42
|
-
}
|
43
28
|
|
44
29
|
#else
|
45
|
-
|
46
30
|
#define MEASURE_ALLOCATIONS_ENABLED Qfalse
|
47
|
-
|
48
|
-
static double
|
49
|
-
measure_allocations()
|
50
|
-
{
|
51
31
|
return 0;
|
52
|
-
}
|
53
|
-
|
54
32
|
#endif
|
33
|
+
}
|
55
34
|
|
56
35
|
|
57
36
|
prof_measurer_t* prof_measurer_allocations()
|
@@ -8,53 +8,31 @@
|
|
8
8
|
static VALUE cMeasureGcRuns;
|
9
9
|
|
10
10
|
#if defined(HAVE_RB_GC_COLLECTIONS)
|
11
|
+
VALUE rb_gc_collections(void);
|
12
|
+
#endif
|
13
|
+
|
14
|
+
#if defined(HAVE_RB_GC_HEAP_INFO)
|
15
|
+
VALUE rb_gc_heap_info(void);
|
16
|
+
#endif
|
11
17
|
|
12
|
-
#define MEASURE_GC_RUNS_ENABLED Qtrue
|
13
18
|
|
14
19
|
static double
|
15
20
|
measure_gc_runs()
|
16
21
|
{
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
/* call-seq:
|
21
|
-
gc_runs -> Integer
|
22
|
-
|
23
|
-
Returns the total number of garbage collections.*/
|
24
|
-
static VALUE
|
25
|
-
prof_measure_gc_runs(VALUE self)
|
26
|
-
{
|
27
|
-
return rb_gc_collections();
|
28
|
-
}
|
22
|
+
#if defined(HAVE_RB_GC_COLLECTIONS)
|
23
|
+
#define MEASURE_GC_RUNS_ENABLED Qtrue
|
24
|
+
return NUM2INT(rb_gc_collections());
|
29
25
|
|
30
26
|
#elif defined(HAVE_RB_GC_HEAP_INFO)
|
31
|
-
|
32
27
|
#define MEASURE_GC_RUNS_ENABLED Qtrue
|
33
|
-
|
34
|
-
static double
|
35
|
-
measure_gc_runs()
|
36
|
-
{
|
37
28
|
VALUE h = rb_gc_heap_info();
|
38
29
|
return NUM2UINT(rb_hash_aref(h, rb_str_new2("num_gc_passes")));
|
39
|
-
}
|
40
|
-
|
41
|
-
static VALUE
|
42
|
-
prof_measure_gc_runs(VALUE self)
|
43
|
-
{
|
44
|
-
VALUE h = rb_gc_heap_info();
|
45
|
-
return rb_hash_aref(h, rb_str_new2("num_gc_passes"));
|
46
|
-
}
|
47
|
-
|
48
|
-
#else
|
49
30
|
|
31
|
+
#else
|
50
32
|
#define MEASURE_GC_RUNS_ENABLED Qfalse
|
51
|
-
|
52
|
-
static double
|
53
|
-
measure_gc_runs()
|
54
|
-
{
|
55
33
|
return 0;
|
56
|
-
}
|
57
34
|
#endif
|
35
|
+
}
|
58
36
|
|
59
37
|
prof_measurer_t* prof_measurer_gc_runs()
|
60
38
|
{
|
@@ -8,40 +8,27 @@
|
|
8
8
|
static VALUE cMeasureGcTimes;
|
9
9
|
|
10
10
|
#if defined(HAVE_RB_GC_TIME)
|
11
|
+
VALUE rb_gc_time();
|
12
|
+
#endif
|
11
13
|
|
12
|
-
#define MEASURE_GC_TIME_ENABLED Qtrue
|
13
14
|
|
14
15
|
static double
|
15
16
|
measure_gc_time()
|
16
17
|
{
|
17
|
-
|
18
|
+
#if defined(HAVE_RB_GC_TIME)
|
19
|
+
#define MEASURE_GC_TIME_ENABLED Qtrue
|
20
|
+
const int conversion = 1000000;
|
18
21
|
#if HAVE_LONG_LONG
|
19
22
|
return NUM2LL(rb_gc_time() / conversion);
|
20
23
|
#else
|
21
24
|
return NUM2LONG(rb_gc_time() / conversion));
|
22
25
|
#endif
|
23
|
-
}
|
24
|
-
|
25
|
-
/* call-seq:
|
26
|
-
gc_time -> Integer
|
27
|
-
|
28
|
-
Returns the time spent doing garbage collections in microseconds.*/
|
29
|
-
static VALUE
|
30
|
-
prof_measure_gc_time(VALUE self)
|
31
|
-
{
|
32
|
-
return rb_gc_time();
|
33
|
-
}
|
34
26
|
|
35
27
|
#else
|
36
|
-
|
37
28
|
#define MEASURE_GC_TIME_ENABLED Qfalse
|
38
|
-
|
39
|
-
static double
|
40
|
-
measure_gc_time()
|
41
|
-
{
|
42
29
|
return 0;
|
43
|
-
}
|
44
30
|
#endif
|
31
|
+
}
|
45
32
|
|
46
33
|
prof_measurer_t* prof_measurer_gc_time()
|
47
34
|
{
|
@@ -63,6 +50,7 @@ prof_measure_gc_time(VALUE self)
|
|
63
50
|
return ULONG2NUM(measure_gc_time());
|
64
51
|
#endif
|
65
52
|
}
|
53
|
+
|
66
54
|
void rp_init_measure_gc_time()
|
67
55
|
{
|
68
56
|
rb_define_const(mProf, "GC_TIME", INT2NUM(MEASURE_GC_TIME));
|
@@ -7,52 +7,45 @@
|
|
7
7
|
|
8
8
|
static VALUE cMeasureMemory;
|
9
9
|
|
10
|
+
|
10
11
|
#if defined(HAVE_RB_GC_ALLOCATED_SIZE)
|
11
|
-
|
12
|
-
#
|
12
|
+
VALUE rb_gc_allocated_size();
|
13
|
+
#endif
|
14
|
+
|
15
|
+
#if defined(HAVE_RB_GC_MALLOC_ALLOCATED_SIZE)
|
16
|
+
size_t rb_gc_malloc_allocated_size();
|
17
|
+
#endif
|
18
|
+
|
19
|
+
#if defined(HAVE_RB_HEAP_TOTAL_MEM)
|
20
|
+
//FIXME: did not find the patch to check prototype, assuming it to return size_t
|
21
|
+
size_t rb_heap_total_mem();
|
22
|
+
#endif
|
13
23
|
|
14
24
|
static double
|
15
25
|
measure_memory()
|
16
26
|
{
|
27
|
+
#if defined(HAVE_RB_GC_ALLOCATED_SIZE)
|
28
|
+
#define TOGGLE_GC_STATS 1
|
29
|
+
#define MEASURE_MEMORY_ENABLED Qtrue
|
17
30
|
#if defined(HAVE_LONG_LONG)
|
18
|
-
return NUM2LL(rb_gc_allocated_size() / 1024
|
31
|
+
return NUM2LL(rb_gc_allocated_size()) / 1024.0;
|
19
32
|
#else
|
20
|
-
return NUM2ULONG(rb_gc_allocated_size() / 1024
|
33
|
+
return NUM2ULONG(rb_gc_allocated_size()) / 1024.0;
|
21
34
|
#endif
|
22
|
-
}
|
23
35
|
|
24
36
|
#elif defined(HAVE_RB_GC_MALLOC_ALLOCATED_SIZE)
|
25
|
-
|
26
37
|
#define MEASURE_MEMORY_ENABLED Qtrue
|
27
|
-
|
28
|
-
static double
|
29
|
-
measure_memory()
|
30
|
-
{
|
31
|
-
return rb_gc_malloc_allocated_size() / 1024;
|
32
|
-
}
|
33
|
-
|
38
|
+
return rb_gc_malloc_allocated_size() / 1024.0;
|
34
39
|
|
35
40
|
#elif defined(HAVE_RB_HEAP_TOTAL_MEM)
|
36
|
-
|
37
41
|
#define MEASURE_MEMORY_ENABLED Qtrue
|
38
|
-
|
39
|
-
static double
|
40
|
-
measure_memory()
|
41
|
-
{
|
42
|
-
return rb_heap_total_mem() / 1024;
|
43
|
-
}
|
42
|
+
return rb_heap_total_mem() / 1024.0;
|
44
43
|
|
45
44
|
#else
|
46
|
-
|
47
45
|
#define MEASURE_MEMORY_ENABLED Qfalse
|
48
|
-
|
49
|
-
static double
|
50
|
-
measure_memory()
|
51
|
-
{
|
52
46
|
return 0;
|
53
|
-
}
|
54
|
-
|
55
47
|
#endif
|
48
|
+
}
|
56
49
|
|
57
50
|
prof_measurer_t* prof_measurer_memory()
|
58
51
|
{
|
data/ext/ruby_prof/rp_stack.c
CHANGED
@@ -5,6 +5,22 @@
|
|
5
5
|
|
6
6
|
#define INITIAL_STACK_SIZE 8
|
7
7
|
|
8
|
+
void
|
9
|
+
frame_pause(prof_frame_t *frame, double current_measurement)
|
10
|
+
{
|
11
|
+
if (frame && frame_is_unpaused(frame))
|
12
|
+
frame->pause_time = current_measurement;
|
13
|
+
}
|
14
|
+
|
15
|
+
void
|
16
|
+
frame_unpause(prof_frame_t *frame, double current_measurement)
|
17
|
+
{
|
18
|
+
if (frame && frame_is_paused(frame)) {
|
19
|
+
frame->dead_time += (current_measurement - frame->pause_time);
|
20
|
+
frame->pause_time = -1;
|
21
|
+
}
|
22
|
+
}
|
23
|
+
|
8
24
|
|
9
25
|
/* Creates a stack of prof_frame_t to keep track
|
10
26
|
of timings for active methods. */
|
@@ -48,7 +64,7 @@ stack_push(prof_stack_t *stack)
|
|
48
64
|
result->child_time = 0;
|
49
65
|
result->switch_time = 0;
|
50
66
|
result->wait_time = 0;
|
51
|
-
result->depth = (stack->ptr - stack->start);
|
67
|
+
result->depth = (int)(stack->ptr - stack->start); // shortening of 64 bit into 32
|
52
68
|
|
53
69
|
// Increment the stack ptr for next time
|
54
70
|
stack->ptr++;
|
data/ext/ruby_prof/rp_stack.h
CHANGED
@@ -22,10 +22,18 @@ typedef struct
|
|
22
22
|
double switch_time; /* Time at switch to different thread */
|
23
23
|
double wait_time;
|
24
24
|
double child_time;
|
25
|
+
double pause_time; // Time pause() was initiated
|
26
|
+
double dead_time; // Time to ignore (i.e. total amount of time between pause/resume blocks)
|
25
27
|
int depth;
|
26
28
|
unsigned int line;
|
27
29
|
} prof_frame_t;
|
28
30
|
|
31
|
+
#define frame_is_paused(f) (f->pause_time >= 0)
|
32
|
+
#define frame_is_unpaused(f) (f->pause_time < 0)
|
33
|
+
void frame_pause(prof_frame_t*, double current_measurement);
|
34
|
+
void frame_unpause(prof_frame_t*, double current_measurement);
|
35
|
+
|
36
|
+
|
29
37
|
/* Current stack of active methods.*/
|
30
38
|
typedef struct
|
31
39
|
{
|
data/ext/ruby_prof/ruby_prof.c
CHANGED
@@ -133,6 +133,11 @@ pop_frame(prof_profile_t* profile, thread_data_t *thread_data)
|
|
133
133
|
double measurement = profile->measurer->measure();
|
134
134
|
double total_time;
|
135
135
|
double self_time;
|
136
|
+
#ifdef _MSC_VER
|
137
|
+
BOOL frame_paused;
|
138
|
+
#else
|
139
|
+
_Bool frame_paused;
|
140
|
+
#endif
|
136
141
|
|
137
142
|
frame = stack_pop(thread_data->stack); // only time it's called
|
138
143
|
|
@@ -140,11 +145,13 @@ pop_frame(prof_profile_t* profile, thread_data_t *thread_data)
|
|
140
145
|
a method that exits. And it can happen if an exception is raised
|
141
146
|
in code that is being profiled and the stack unwinds (RubyProf is
|
142
147
|
not notified of that by the ruby runtime. */
|
143
|
-
if (frame == NULL)
|
148
|
+
if (frame == NULL)
|
144
149
|
return NULL;
|
145
150
|
|
146
151
|
/* Calculate the total time this method took */
|
147
|
-
|
152
|
+
frame_paused = frame_is_paused(frame);
|
153
|
+
frame_unpause(frame, measurement);
|
154
|
+
total_time = measurement - frame->start_time - frame->dead_time;
|
148
155
|
self_time = total_time - frame->child_time - frame->wait_time;
|
149
156
|
|
150
157
|
/* Update information about the current method */
|
@@ -158,6 +165,12 @@ pop_frame(prof_profile_t* profile, thread_data_t *thread_data)
|
|
158
165
|
if (parent_frame)
|
159
166
|
{
|
160
167
|
parent_frame->child_time += total_time;
|
168
|
+
parent_frame->dead_time += frame->dead_time;
|
169
|
+
|
170
|
+
// Repause parent if currently paused
|
171
|
+
if (frame_paused)
|
172
|
+
frame_pause(parent_frame, measurement);
|
173
|
+
|
161
174
|
call_info->line = parent_frame->line;
|
162
175
|
}
|
163
176
|
|
@@ -333,6 +346,11 @@ prof_event_hook(rb_event_flag_t event, NODE *node, VALUE self, ID mid, VALUE kla
|
|
333
346
|
call_info_table_insert(frame->call_info->call_infos, method->key, call_info);
|
334
347
|
prof_add_call_info(method->call_infos, call_info);
|
335
348
|
}
|
349
|
+
|
350
|
+
// Unpause the parent frame. If currently paused then:
|
351
|
+
// 1) The child frame will begin paused.
|
352
|
+
// 2) The parent will inherit the child's dead time.
|
353
|
+
frame_unpause(frame, measurement);
|
336
354
|
}
|
337
355
|
|
338
356
|
/* Push a new frame onto the stack for a new c-call or ruby call (into a method) */
|
@@ -340,6 +358,8 @@ prof_event_hook(rb_event_flag_t event, NODE *node, VALUE self, ID mid, VALUE kla
|
|
340
358
|
frame->call_info = call_info;
|
341
359
|
frame->call_info->depth = frame->depth;
|
342
360
|
frame->start_time = measurement;
|
361
|
+
frame->pause_time = profile->paused == Qtrue ? measurement : -1;
|
362
|
+
frame->dead_time = 0;
|
343
363
|
frame->line = rb_sourceline();
|
344
364
|
break;
|
345
365
|
}
|
@@ -459,7 +479,7 @@ prof_initialize(int argc, VALUE *argv, VALUE self)
|
|
459
479
|
{
|
460
480
|
prof_profile_t* profile = prof_get_profile(self);
|
461
481
|
VALUE mode;
|
462
|
-
prof_measure_mode_t measurer;
|
482
|
+
prof_measure_mode_t measurer = MEASURE_WALL_TIME;
|
463
483
|
VALUE exclude_threads;
|
464
484
|
int i;
|
465
485
|
|
@@ -497,6 +517,39 @@ prof_initialize(int argc, VALUE *argv, VALUE self)
|
|
497
517
|
return self;
|
498
518
|
}
|
499
519
|
|
520
|
+
static int pause_thread(st_data_t key, st_data_t value, st_data_t data)
|
521
|
+
{
|
522
|
+
thread_data_t* thread_data = (thread_data_t *) value;
|
523
|
+
prof_profile_t* profile = (prof_profile_t*) data;
|
524
|
+
|
525
|
+
prof_frame_t* frame = stack_peek(thread_data->stack);
|
526
|
+
frame_pause(frame, profile->measurement_at_pause_resume);
|
527
|
+
|
528
|
+
return ST_CONTINUE;
|
529
|
+
}
|
530
|
+
|
531
|
+
static int unpause_thread(st_data_t key, st_data_t value, st_data_t data)
|
532
|
+
{
|
533
|
+
thread_data_t* thread_data = (thread_data_t *) value;
|
534
|
+
prof_profile_t* profile = (prof_profile_t*) data;
|
535
|
+
|
536
|
+
prof_frame_t* frame = stack_peek(thread_data->stack);
|
537
|
+
frame_unpause(frame, profile->measurement_at_pause_resume);
|
538
|
+
|
539
|
+
return ST_CONTINUE;
|
540
|
+
}
|
541
|
+
|
542
|
+
/* call-seq:
|
543
|
+
paused? -> boolean
|
544
|
+
|
545
|
+
Returns whether a profile is currently paused.*/
|
546
|
+
static VALUE
|
547
|
+
prof_paused(VALUE self)
|
548
|
+
{
|
549
|
+
prof_profile_t* profile = prof_get_profile(self);
|
550
|
+
return profile->paused;
|
551
|
+
}
|
552
|
+
|
500
553
|
/* call-seq:
|
501
554
|
running? -> boolean
|
502
555
|
|
@@ -516,6 +569,7 @@ static VALUE
|
|
516
569
|
prof_start(VALUE self)
|
517
570
|
{
|
518
571
|
char* trace_file_name;
|
572
|
+
|
519
573
|
prof_profile_t* profile = prof_get_profile(self);
|
520
574
|
|
521
575
|
if (profile->running == Qtrue)
|
@@ -523,7 +577,15 @@ prof_start(VALUE self)
|
|
523
577
|
rb_raise(rb_eRuntimeError, "RubyProf.start was already called");
|
524
578
|
}
|
525
579
|
|
580
|
+
#ifndef RUBY_VM
|
581
|
+
if (pCurrentProfile != NULL)
|
582
|
+
{
|
583
|
+
rb_raise(rb_eRuntimeError, "Only one profile can run at a time on Ruby 1.8.*");
|
584
|
+
}
|
585
|
+
#endif
|
586
|
+
|
526
587
|
profile->running = Qtrue;
|
588
|
+
profile->paused = Qfalse;
|
527
589
|
profile->last_thread_data = NULL;
|
528
590
|
|
529
591
|
|
@@ -562,9 +624,13 @@ prof_pause(VALUE self)
|
|
562
624
|
rb_raise(rb_eRuntimeError, "RubyProf is not running.");
|
563
625
|
}
|
564
626
|
|
565
|
-
profile->
|
627
|
+
if (profile->paused == Qfalse)
|
628
|
+
{
|
629
|
+
profile->paused = Qtrue;
|
630
|
+
profile->measurement_at_pause_resume = profile->measurer->measure();
|
631
|
+
st_foreach(profile->threads_tbl, pause_thread, (st_data_t) profile);
|
632
|
+
}
|
566
633
|
|
567
|
-
prof_remove_hook();
|
568
634
|
return self;
|
569
635
|
}
|
570
636
|
|
@@ -578,20 +644,17 @@ prof_resume(VALUE self)
|
|
578
644
|
prof_profile_t* profile = prof_get_profile(self);
|
579
645
|
if (profile->running == Qfalse)
|
580
646
|
{
|
581
|
-
|
582
|
-
}
|
583
|
-
else
|
584
|
-
{
|
585
|
-
profile->running = Qtrue;
|
586
|
-
prof_install_hook(self);
|
647
|
+
rb_raise(rb_eRuntimeError, "RubyProf is not running.");
|
587
648
|
}
|
588
649
|
|
589
|
-
if (
|
650
|
+
if (profile->paused == Qtrue)
|
590
651
|
{
|
591
|
-
|
652
|
+
profile->paused = Qfalse;
|
653
|
+
profile->measurement_at_pause_resume = profile->measurer->measure();
|
654
|
+
st_foreach(profile->threads_tbl, unpause_thread, (st_data_t) profile);
|
592
655
|
}
|
593
656
|
|
594
|
-
return self;
|
657
|
+
return rb_block_given_p() ? rb_ensure(rb_yield, self, prof_pause, self) : self;
|
595
658
|
}
|
596
659
|
|
597
660
|
/* call-seq:
|
@@ -628,7 +691,7 @@ prof_stop(VALUE self)
|
|
628
691
|
|
629
692
|
/* Unset the last_thread_data (very important!)
|
630
693
|
and the threads table */
|
631
|
-
profile->running = Qfalse;
|
694
|
+
profile->running = profile->paused = Qfalse;
|
632
695
|
profile->last_thread_data = NULL;
|
633
696
|
|
634
697
|
/* Post process result */
|
@@ -686,10 +749,10 @@ void Init_ruby_prof()
|
|
686
749
|
rb_define_alloc_func (cProfile, prof_allocate);
|
687
750
|
rb_define_method(cProfile, "initialize", prof_initialize, -1);
|
688
751
|
rb_define_method(cProfile, "start", prof_start, 0);
|
689
|
-
rb_define_method(cProfile, "start", prof_start, 0);
|
690
752
|
rb_define_method(cProfile, "stop", prof_stop, 0);
|
691
753
|
rb_define_method(cProfile, "resume", prof_resume, 0);
|
692
754
|
rb_define_method(cProfile, "pause", prof_pause, 0);
|
693
755
|
rb_define_method(cProfile, "running?", prof_running, 0);
|
756
|
+
rb_define_method(cProfile, "paused?", prof_paused, 0);
|
694
757
|
rb_define_method(cProfile, "threads", prof_threads, 0);
|
695
758
|
}
|
data/ext/ruby_prof/ruby_prof.h
CHANGED
@@ -42,11 +42,13 @@ void method_key(prof_method_key_t* key, VALUE klass, ID mid);
|
|
42
42
|
typedef struct
|
43
43
|
{
|
44
44
|
VALUE running;
|
45
|
+
VALUE paused;
|
45
46
|
prof_measurer_t* measurer;
|
46
47
|
VALUE threads;
|
47
48
|
st_table* threads_tbl;
|
48
49
|
st_table* exclude_threads_tbl;
|
49
50
|
thread_data_t* last_thread_data;
|
51
|
+
double measurement_at_pause_resume;
|
50
52
|
} prof_profile_t;
|
51
53
|
|
52
54
|
|
@@ -64,6 +64,8 @@
|
|
64
64
|
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
|
65
65
|
<LinkIncremental>true</LinkIncremental>
|
66
66
|
<OutDir>C:\MinGW\local\src\ruby-prof\lib\1.8</OutDir>
|
67
|
+
<TargetExt>.so</TargetExt>
|
68
|
+
<TargetName>ruby_prof</TargetName>
|
67
69
|
</PropertyGroup>
|
68
70
|
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
|
69
71
|
<LinkIncremental>false</LinkIncremental>
|
@@ -81,6 +83,7 @@
|
|
81
83
|
<GenerateDebugInformation>true</GenerateDebugInformation>
|
82
84
|
<AdditionalLibraryDirectories>C:\MinGW\local\ruby187vc\lib</AdditionalLibraryDirectories>
|
83
85
|
<AdditionalDependencies>msvcr100-ruby18.lib;%(AdditionalDependencies)</AdditionalDependencies>
|
86
|
+
<ModuleDefinitionFile>ruby_prof.def</ModuleDefinitionFile>
|
84
87
|
</Link>
|
85
88
|
</ItemDefinitionGroup>
|
86
89
|
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
|
data/ext/ruby_prof/version.h
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
/* Copyright (C) 2005-2011 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
|
-
#define RUBY_PROF_VERSION "0.11.
|
4
|
+
#define RUBY_PROF_VERSION "0.11.2" // for easy parsing from rake files
|
5
5
|
#define RUBY_PROF_VERSION_MAJ 0
|
6
6
|
#define RUBY_PROF_VERSION_MIN 11
|
7
|
-
#define RUBY_PROF_VERSION_MIC
|
7
|
+
#define RUBY_PROF_VERSION_MIC 2
|
@@ -18,7 +18,7 @@ module RubyProf
|
|
18
18
|
def self.measure_cpu_time
|
19
19
|
Measure::CpuTime.measure
|
20
20
|
end
|
21
|
-
|
21
|
+
|
22
22
|
def self.measure_gc_runs
|
23
23
|
Measure::GcRuns.measure
|
24
24
|
end
|
@@ -38,7 +38,7 @@ module RubyProf
|
|
38
38
|
def self.measure_wall_time
|
39
39
|
Measure::WallTime.measure
|
40
40
|
end
|
41
|
-
|
41
|
+
|
42
42
|
# call-seq:
|
43
43
|
# measure_mode -> measure_mode
|
44
44
|
#
|
@@ -51,11 +51,11 @@ module RubyProf
|
|
51
51
|
# *RubyProf::MEMORY - Measure memory size. This requires a patched Ruby interpreter.
|
52
52
|
# *RubyProf::GC_RUNS - Measure number of garbage collections. This requires a patched Ruby interpreter.
|
53
53
|
# *RubyProf::GC_TIME - Measure time spent doing garbage collection. This requires a patched Ruby interpreter.*/
|
54
|
-
|
54
|
+
|
55
55
|
def self.measure_mode
|
56
56
|
@measure_mode ||= RubyProf::WALL_TIME
|
57
57
|
end
|
58
|
-
|
58
|
+
|
59
59
|
# call-seq:
|
60
60
|
# measure_mode=value -> void
|
61
61
|
#
|
@@ -71,33 +71,31 @@ module RubyProf
|
|
71
71
|
def self.measure_mode=(value)
|
72
72
|
@measure_mode = value
|
73
73
|
end
|
74
|
-
|
74
|
+
|
75
75
|
# call-seq:
|
76
76
|
# exclude_threads= -> void
|
77
77
|
#
|
78
78
|
# Specifies what threads ruby-prof should exclude from profiling
|
79
|
-
|
79
|
+
|
80
80
|
def self.exclude_threads
|
81
81
|
@exclude_threads ||= Array.new
|
82
82
|
end
|
83
|
-
|
83
|
+
|
84
84
|
def self.exclude_threads=(value)
|
85
85
|
@exclude_threads = value
|
86
86
|
end
|
87
|
-
|
87
|
+
|
88
88
|
# Profiling
|
89
89
|
def self.start
|
90
|
-
|
91
|
-
raise(RuntimeError, "RubyProf is already running");
|
92
|
-
end
|
90
|
+
ensure_not_running!
|
93
91
|
@profile = Profile.new(self.measure_mode, self.exclude_threads)
|
92
|
+
enable_gc_stats_if_needed
|
94
93
|
@profile.start
|
95
94
|
end
|
96
95
|
|
97
96
|
def self.pause
|
98
|
-
|
99
|
-
|
100
|
-
end
|
97
|
+
ensure_running!
|
98
|
+
disable_gc_stats_if_needed
|
101
99
|
@profile.pause
|
102
100
|
end
|
103
101
|
|
@@ -110,25 +108,47 @@ module RubyProf
|
|
110
108
|
end
|
111
109
|
|
112
110
|
def self.resume
|
113
|
-
|
114
|
-
|
115
|
-
end
|
111
|
+
ensure_running!
|
112
|
+
enable_gc_stats_if_needed
|
116
113
|
@profile.resume
|
117
114
|
end
|
118
115
|
|
119
116
|
def self.stop
|
120
|
-
|
121
|
-
|
122
|
-
end
|
117
|
+
ensure_running!
|
118
|
+
disable_gc_stats_if_needed
|
123
119
|
result = @profile.stop
|
124
120
|
@profile = nil
|
125
121
|
result
|
126
122
|
end
|
127
123
|
|
124
|
+
# Profile a block
|
128
125
|
def self.profile(&block)
|
129
|
-
|
130
|
-
|
126
|
+
ensure_not_running!
|
127
|
+
gc_stat_was_enabled = enable_gc_stats_if_needed
|
128
|
+
res = Profile.profile(self.measure_mode, self.exclude_threads, &block)
|
129
|
+
disable_gc_stats_if_needed(gc_stat_was_enabled)
|
130
|
+
res
|
131
|
+
end
|
132
|
+
|
133
|
+
|
134
|
+
private
|
135
|
+
def self.ensure_running!
|
136
|
+
raise(RuntimeError, "RubyProf.start was not yet called") unless running?
|
137
|
+
end
|
138
|
+
|
139
|
+
def self.ensure_not_running!
|
140
|
+
raise(RuntimeError, "RubyProf is already running") if running?
|
141
|
+
end
|
142
|
+
|
143
|
+
# for GC.allocated_size to work GC statistics should be enabled
|
144
|
+
def self.enable_gc_stats_if_needed
|
145
|
+
if self.measure_mode == RubyProf::MEMORY && GC.respond_to?(:enable_stats)
|
146
|
+
@gc_stat_was_enabled = GC.enable_stats
|
131
147
|
end
|
132
|
-
|
148
|
+
end
|
149
|
+
|
150
|
+
def self.disable_gc_stats_if_needed(was_enabled=nil)
|
151
|
+
was_enabled ||= defined?(@gc_stat_was_enabled) && @gc_stat_was_enabled
|
152
|
+
GC.disable_stats if self.measure_mode == RubyProf::MEMORY && GC.respond_to?(:disable_stats) && !was_enabled
|
133
153
|
end
|
134
154
|
end
|
data/ruby-prof.gemspec
CHANGED
@@ -6,8 +6,7 @@ version_header = File.read(File.expand_path('../ext/ruby_prof/version.h', __FILE
|
|
6
6
|
match = version_header.match(/RUBY_PROF_VERSION\s*"([^"]+)"/)
|
7
7
|
raise(RuntimeError, "Could not determine RUBY_PROF_VERSION") if not match
|
8
8
|
|
9
|
-
|
10
|
-
RUBY_PROF_VERSION = "#{match[1]}.rc3"
|
9
|
+
RUBY_PROF_VERSION = "#{match[1]}"
|
11
10
|
|
12
11
|
Gem::Specification.new do |spec|
|
13
12
|
spec.name = "ruby-prof"
|
data/test/basic_test.rb
CHANGED
@@ -39,4 +39,58 @@ class BasicTest < Test::Unit::TestCase
|
|
39
39
|
|
40
40
|
RubyProf.stop
|
41
41
|
end
|
42
|
-
|
42
|
+
|
43
|
+
def test_pause_seq
|
44
|
+
p= RubyProf::Profile.new(RubyProf::WALL_TIME,[])
|
45
|
+
p.start ; assert !p.paused?
|
46
|
+
p.pause ; assert p.paused?
|
47
|
+
p.resume; assert !p.paused?
|
48
|
+
p.pause ; assert p.paused?
|
49
|
+
p.pause ; assert p.paused?
|
50
|
+
p.resume; assert !p.paused?
|
51
|
+
p.resume; assert !p.paused?
|
52
|
+
p.stop ; assert !p.paused?
|
53
|
+
end
|
54
|
+
|
55
|
+
def test_pause_block
|
56
|
+
p= RubyProf::Profile.new(RubyProf::WALL_TIME,[])
|
57
|
+
p.start
|
58
|
+
p.pause
|
59
|
+
assert p.paused?
|
60
|
+
|
61
|
+
times_block_invoked = 0
|
62
|
+
retval= p.resume{
|
63
|
+
times_block_invoked += 1
|
64
|
+
120 + times_block_invoked
|
65
|
+
}
|
66
|
+
assert_equal 1, times_block_invoked
|
67
|
+
assert p.paused?
|
68
|
+
|
69
|
+
assert_equal 121, retval, "resume() should return the result of the given block."
|
70
|
+
|
71
|
+
p.stop
|
72
|
+
end
|
73
|
+
|
74
|
+
def test_pause_block_with_error
|
75
|
+
p= RubyProf::Profile.new(RubyProf::WALL_TIME,[])
|
76
|
+
p.start
|
77
|
+
p.pause
|
78
|
+
assert p.paused?
|
79
|
+
|
80
|
+
begin
|
81
|
+
p.resume{ raise }
|
82
|
+
flunk 'Exception expected.'
|
83
|
+
rescue
|
84
|
+
assert p.paused?
|
85
|
+
end
|
86
|
+
|
87
|
+
p.stop
|
88
|
+
end
|
89
|
+
|
90
|
+
def test_resume_when_not_paused
|
91
|
+
p= RubyProf::Profile.new(RubyProf::WALL_TIME,[])
|
92
|
+
p.start ; assert !p.paused?
|
93
|
+
p.resume; assert !p.paused?
|
94
|
+
p.stop ; assert !p.paused?
|
95
|
+
end
|
96
|
+
end
|
data/test/line_number_test.rb
CHANGED
@@ -5,11 +5,9 @@ require File.expand_path('../test_helper', __FILE__)
|
|
5
5
|
|
6
6
|
class LineNumbers
|
7
7
|
def method1
|
8
|
-
3
|
9
8
|
end
|
10
9
|
|
11
10
|
def method2
|
12
|
-
3
|
13
11
|
method1
|
14
12
|
end
|
15
13
|
|
@@ -32,11 +30,11 @@ class LineNumbersTest < Test::Unit::TestCase
|
|
32
30
|
|
33
31
|
method = methods[0]
|
34
32
|
assert_equal('LineNumbersTest#test_function_line_no', method.full_name)
|
35
|
-
assert_equal(
|
33
|
+
assert_equal(25, method.line)
|
36
34
|
|
37
35
|
method = methods[1]
|
38
36
|
assert_equal('LineNumbers#method2', method.full_name)
|
39
|
-
assert_equal(
|
37
|
+
assert_equal(10, method.line)
|
40
38
|
|
41
39
|
method = methods[2]
|
42
40
|
assert_equal('LineNumbers#method1', method.full_name)
|
@@ -64,10 +62,10 @@ class LineNumbersTest < Test::Unit::TestCase
|
|
64
62
|
|
65
63
|
method = methods[1]
|
66
64
|
assert_equal('LineNumbers#method3', method.full_name)
|
67
|
-
assert_equal(
|
65
|
+
assert_equal(14, method.line)
|
68
66
|
|
69
67
|
method = methods[2]
|
70
68
|
assert_equal('LineNumbersTest#test_c_function', method.full_name)
|
71
|
-
assert_equal(
|
69
|
+
assert_equal(48, method.line)
|
72
70
|
end
|
73
71
|
end
|
data/test/multi_printer_test.rb
CHANGED
@@ -0,0 +1,61 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
# encoding: UTF-8
|
3
|
+
|
4
|
+
require File.expand_path('../test_helper', __FILE__)
|
5
|
+
|
6
|
+
class PauseResumeTest < Test::Unit::TestCase
|
7
|
+
|
8
|
+
# pause/resume in the same frame
|
9
|
+
def test_pause_resume_1
|
10
|
+
p= RubyProf::Profile.new(RubyProf::WALL_TIME,[])
|
11
|
+
|
12
|
+
p.start
|
13
|
+
method_1a
|
14
|
+
|
15
|
+
p.pause
|
16
|
+
method_1b
|
17
|
+
|
18
|
+
p.resume
|
19
|
+
method_1c
|
20
|
+
|
21
|
+
r= p.stop
|
22
|
+
assert_in_delta(0.6, r.threads[0].methods.select{|m| m.full_name =~ /test_pause_resume_1$/}[0].total_time, 0.05)
|
23
|
+
end
|
24
|
+
def method_1a; sleep 0.2 end
|
25
|
+
def method_1b; sleep 1 end
|
26
|
+
def method_1c; sleep 0.4 end
|
27
|
+
|
28
|
+
# pause in parent frame, resume in child
|
29
|
+
def test_pause_resume_2
|
30
|
+
p= RubyProf::Profile.new(RubyProf::WALL_TIME,[])
|
31
|
+
|
32
|
+
p.start
|
33
|
+
method_2a
|
34
|
+
|
35
|
+
p.pause
|
36
|
+
sleep 0.5
|
37
|
+
method_2b(p)
|
38
|
+
|
39
|
+
r= p.stop
|
40
|
+
assert_in_delta(0.6, r.threads[0].methods.select{|m| m.full_name =~ /test_pause_resume_2$/}[0].total_time, 0.05)
|
41
|
+
end
|
42
|
+
def method_2a; sleep 0.2 end
|
43
|
+
def method_2b(p); sleep 0.5; p.resume; sleep 0.4 end
|
44
|
+
|
45
|
+
# pause in child frame, resume in parent
|
46
|
+
def test_pause_resume_3
|
47
|
+
p= RubyProf::Profile.new(RubyProf::WALL_TIME,[])
|
48
|
+
|
49
|
+
p.start
|
50
|
+
method_3a(p)
|
51
|
+
|
52
|
+
sleep 0.5
|
53
|
+
p.resume
|
54
|
+
method_3b
|
55
|
+
|
56
|
+
r= p.stop
|
57
|
+
assert_in_delta(0.6, r.threads[0].methods.select{|m| m.full_name =~ /test_pause_resume_3$/}[0].total_time, 0.05)
|
58
|
+
end
|
59
|
+
def method_3a(p); sleep 0.2; p.pause; sleep 0.5 end
|
60
|
+
def method_3b; sleep 0.4 end
|
61
|
+
end
|
data/test/pause_test.rb
ADDED
@@ -0,0 +1,57 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
# encoding: UTF-8
|
3
|
+
|
4
|
+
require File.expand_path('../test_helper', __FILE__)
|
5
|
+
|
6
|
+
class PauseTest < Test::Unit::TestCase
|
7
|
+
def setup
|
8
|
+
# Need to use wall time for this test due to the sleep calls
|
9
|
+
RubyProf::measure_mode = RubyProf::WALL_TIME
|
10
|
+
end
|
11
|
+
|
12
|
+
def test_pause_resume
|
13
|
+
RubyProf.start
|
14
|
+
# Measured
|
15
|
+
RubyProf::C1.hello
|
16
|
+
RubyProf.pause
|
17
|
+
|
18
|
+
# Not measured
|
19
|
+
RubyProf::C1.hello
|
20
|
+
|
21
|
+
RubyProf.resume
|
22
|
+
# Measured
|
23
|
+
RubyProf::C1.hello
|
24
|
+
result = RubyProf.stop
|
25
|
+
|
26
|
+
printer = RubyProf::FlatPrinter.new(result)
|
27
|
+
printer.print
|
28
|
+
|
29
|
+
# Length should be 3:
|
30
|
+
# PauseTest#test_pause_resume
|
31
|
+
# <Class::RubyProf::C1>#hello
|
32
|
+
# Kernel#sleep
|
33
|
+
|
34
|
+
methods = result.threads.first.methods.sort.reverse
|
35
|
+
assert_equal(3, methods.length)
|
36
|
+
|
37
|
+
# Check the names
|
38
|
+
assert_equal('PauseTest#test_pause_resume', methods[0].full_name)
|
39
|
+
assert_equal('<Class::RubyProf::C1>#hello', methods[1].full_name)
|
40
|
+
assert_equal('Kernel#sleep', methods[2].full_name)
|
41
|
+
|
42
|
+
# Check times
|
43
|
+
assert_in_delta(0.1, methods[0].total_time, 0.01)
|
44
|
+
assert_in_delta(0, methods[0].wait_time, 0.01)
|
45
|
+
assert_in_delta(0, methods[0].self_time, 0.01)
|
46
|
+
|
47
|
+
assert_in_delta(0.1, methods[1].total_time, 0.01)
|
48
|
+
assert_in_delta(0, methods[1].wait_time, 0.01)
|
49
|
+
assert_in_delta(0, methods[1].self_time, 0.01)
|
50
|
+
|
51
|
+
assert_in_delta(0.1, methods[2].total_time, 0.01)
|
52
|
+
assert_in_delta(0, methods[2].wait_time, 0.01)
|
53
|
+
assert_in_delta(0.1, methods[2].self_time, 0.01)
|
54
|
+
|
55
|
+
end
|
56
|
+
|
57
|
+
end
|
data/test/prime.rb
CHANGED
data/test/prime_test.rb
CHANGED
data/test/recursive_test.rb
CHANGED
@@ -50,9 +50,10 @@ class RecursiveTest < Test::Unit::TestCase
|
|
50
50
|
method.full_name.match(/Fixnum/)
|
51
51
|
end
|
52
52
|
|
53
|
-
assert_equal(3, methods.length)
|
53
|
+
assert_equal(3, methods.length)
|
54
54
|
|
55
55
|
# Method 0: RecursiveTest#test_simple
|
56
|
+
methods.sort!.reverse!
|
56
57
|
method = methods[0]
|
57
58
|
assert_equal('RecursiveTest#test_simple', method.full_name)
|
58
59
|
assert_equal(1, method.called)
|
@@ -79,16 +80,12 @@ class RecursiveTest < Test::Unit::TestCase
|
|
79
80
|
assert_equal(2, method.call_infos.length)
|
80
81
|
|
81
82
|
call_info = method.call_infos.first
|
82
|
-
|
83
|
-
assert_equal(4, call_info.children.length)
|
84
|
-
else
|
85
|
-
assert_equal(2, call_info.children.length)
|
86
|
-
end
|
83
|
+
assert_equal(2 + (RUBY_VERSION < '1.9.0' ? 2 : 0), call_info.children.length)
|
87
84
|
assert_equal('RecursiveTest#test_simple->Object#simple', call_info.call_sequence)
|
88
85
|
assert(!call_info.recursive)
|
89
86
|
|
90
87
|
call_info = method.call_infos.last
|
91
|
-
assert_equal(1, call_info.children.length)
|
88
|
+
assert_equal(1 + (RUBY_VERSION < '1.9.0' ? 2 : 0), call_info.children.length)
|
92
89
|
assert_equal('RecursiveTest#test_simple->Object#simple->Object#simple', call_info.call_sequence)
|
93
90
|
assert(call_info.recursive)
|
94
91
|
|
@@ -112,6 +109,7 @@ class RecursiveTest < Test::Unit::TestCase
|
|
112
109
|
assert(!call_info.recursive)
|
113
110
|
|
114
111
|
if RUBY_VERSION < '1.9'
|
112
|
+
methods = result.threads.first.methods.dup.sort!.reverse!
|
115
113
|
method = methods[3]
|
116
114
|
assert_equal('Fixnum#-', method.full_name)
|
117
115
|
assert_equal(2, method.called)
|
@@ -207,7 +205,7 @@ class RecursiveTest < Test::Unit::TestCase
|
|
207
205
|
|
208
206
|
call_info = method.call_infos[1]
|
209
207
|
assert_equal('RecursiveTest#test_cycle->Object#render->Integer#times->Object#render_partial->Integer#times', call_info.call_sequence)
|
210
|
-
assert_equal(1, call_info.children.length)
|
208
|
+
assert_equal(1 + (RUBY_VERSION < '1.9.0' ? 1 : 0), call_info.children.length)
|
211
209
|
assert(call_info.recursive)
|
212
210
|
|
213
211
|
method = methods[3]
|
@@ -221,17 +219,17 @@ class RecursiveTest < Test::Unit::TestCase
|
|
221
219
|
assert_equal(3, method.call_infos.length)
|
222
220
|
call_info = method.call_infos[0]
|
223
221
|
assert_equal('RecursiveTest#test_cycle->Object#render->Integer#times->Object#render_partial', call_info.call_sequence)
|
224
|
-
assert_equal(3, call_info.children.length)
|
222
|
+
assert_equal(3 + (RUBY_VERSION < '1.9.0' ? 1 : 0), call_info.children.length)
|
225
223
|
assert(!call_info.recursive)
|
226
224
|
|
227
225
|
call_info = method.call_infos[1]
|
228
226
|
assert_equal('RecursiveTest#test_cycle->Object#render->Integer#times->Object#render_partial->Object#render_partial', call_info.call_sequence)
|
229
|
-
assert_equal(1, call_info.children.length)
|
227
|
+
assert_equal(1 + (RUBY_VERSION < '1.9.0' ? 1 : 0), call_info.children.length)
|
230
228
|
assert(call_info.recursive)
|
231
229
|
|
232
230
|
call_info = method.call_infos[2]
|
233
231
|
assert_equal('RecursiveTest#test_cycle->Object#render->Integer#times->Object#render_partial->Integer#times->Object#render_partial', call_info.call_sequence)
|
234
|
-
assert_equal(1, call_info.children.length)
|
232
|
+
assert_equal(1 + (RUBY_VERSION < '1.9.0' ? 1 : 0), call_info.children.length)
|
235
233
|
assert(call_info.recursive)
|
236
234
|
|
237
235
|
method = methods[4]
|
data/test/test_suite.rb
CHANGED
@@ -24,6 +24,7 @@ require File.expand_path("../test_helper", __FILE__)
|
|
24
24
|
module_test
|
25
25
|
multi_printer_test
|
26
26
|
no_method_class_test
|
27
|
+
pause_test
|
27
28
|
prime_test
|
28
29
|
printers_test
|
29
30
|
recursive_test
|
@@ -34,5 +35,4 @@ require File.expand_path("../test_helper", __FILE__)
|
|
34
35
|
thread_test
|
35
36
|
unique_call_path_test).each do |test|
|
36
37
|
require File.expand_path("../#{test}", __FILE__)
|
37
|
-
end
|
38
|
-
|
38
|
+
end
|
data/test/thread_test.rb
CHANGED
@@ -25,14 +25,14 @@ class ThreadTest < Test::Unit::TestCase
|
|
25
25
|
|
26
26
|
def test_thread_identity
|
27
27
|
RubyProf.start
|
28
|
-
|
28
|
+
sleep_thread = Thread.new do
|
29
29
|
sleep(1)
|
30
30
|
end
|
31
|
-
|
31
|
+
sleep_thread.join
|
32
32
|
result = RubyProf.stop
|
33
33
|
|
34
34
|
thread_ids = result.threads.map {|thread| thread.id}.sort
|
35
|
-
threads = [Thread.current,
|
35
|
+
threads = [Thread.current, sleep_thread]
|
36
36
|
assert_equal(2, result.threads.length)
|
37
37
|
|
38
38
|
assert(thread_ids.include?(threads[0].object_id))
|
@@ -164,9 +164,9 @@ class ThreadTest < Test::Unit::TestCase
|
|
164
164
|
end
|
165
165
|
|
166
166
|
def test_thread
|
167
|
-
|
167
|
+
RubyProf.profile do
|
168
168
|
begin
|
169
|
-
|
169
|
+
Timeout::timeout(2) do
|
170
170
|
while true
|
171
171
|
next
|
172
172
|
end
|
metadata
CHANGED
@@ -1,15 +1,15 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: ruby-prof
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.11.
|
5
|
-
prerelease:
|
4
|
+
version: 0.11.2
|
5
|
+
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
8
8
|
- Shugo Maeda, Charlie Savage, Roger Pack, Stefan Kaes
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2012-
|
12
|
+
date: 2012-05-06 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: rake-compiler
|
@@ -137,6 +137,8 @@ files:
|
|
137
137
|
- test/module_test.rb
|
138
138
|
- test/multi_printer_test.rb
|
139
139
|
- test/no_method_class_test.rb
|
140
|
+
- test/pause_resume_test.rb
|
141
|
+
- test/pause_test.rb
|
140
142
|
- test/prime.rb
|
141
143
|
- test/prime_test.rb
|
142
144
|
- test/printers_test.rb
|
@@ -145,7 +147,6 @@ files:
|
|
145
147
|
- test/stack_printer_test.rb
|
146
148
|
- test/stack_test.rb
|
147
149
|
- test/start_stop_test.rb
|
148
|
-
- test/summarize_test.rb
|
149
150
|
- test/test_helper.rb
|
150
151
|
- test/test_suite.rb
|
151
152
|
- test/thread_test.rb
|
@@ -165,12 +166,12 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
165
166
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
166
167
|
none: false
|
167
168
|
requirements:
|
168
|
-
- - ! '
|
169
|
+
- - ! '>='
|
169
170
|
- !ruby/object:Gem::Version
|
170
|
-
version:
|
171
|
+
version: '0'
|
171
172
|
requirements: []
|
172
173
|
rubyforge_project:
|
173
|
-
rubygems_version: 1.8.
|
174
|
+
rubygems_version: 1.8.24
|
174
175
|
signing_key:
|
175
176
|
specification_version: 3
|
176
177
|
summary: Fast Ruby profiler
|
data/test/summarize_test.rb
DELETED
@@ -1,48 +0,0 @@
|
|
1
|
-
#!/usr/bin/env ruby
|
2
|
-
# encoding: UTF-8
|
3
|
-
|
4
|
-
require File.expand_path('../test_helper', __FILE__)
|
5
|
-
|
6
|
-
def slow
|
7
|
-
sleep(3)
|
8
|
-
end
|
9
|
-
|
10
|
-
def fast
|
11
|
-
sleep(3)
|
12
|
-
end
|
13
|
-
|
14
|
-
def slow_caller
|
15
|
-
1.times do
|
16
|
-
slow
|
17
|
-
end
|
18
|
-
end
|
19
|
-
|
20
|
-
def fast_caller
|
21
|
-
1.times do
|
22
|
-
fast
|
23
|
-
end
|
24
|
-
end
|
25
|
-
|
26
|
-
def parent
|
27
|
-
[1..10].each do
|
28
|
-
#slow_caller
|
29
|
-
fast_caller
|
30
|
-
end
|
31
|
-
end
|
32
|
-
|
33
|
-
class SummarizeTest < Test::Unit::TestCase
|
34
|
-
def setup
|
35
|
-
# Need to use wall time for this test due to the sleep calls
|
36
|
-
RubyProf::measure_mode = RubyProf::WALL_TIME
|
37
|
-
end
|
38
|
-
|
39
|
-
def test
|
40
|
-
result = RubyProf::Profile.profile do
|
41
|
-
parent
|
42
|
-
end
|
43
|
-
|
44
|
-
printer = RubyProf::GraphPrinter.new(result)
|
45
|
-
printer.print(STDOUT)
|
46
|
-
|
47
|
-
end
|
48
|
-
end
|