ruby-prof 0.11.0.rc3 → 0.11.2
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 +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
|