skaes-ruby-prof 0.7.3
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 +202 -0
- data/LICENSE +23 -0
- data/README +436 -0
- data/Rakefile +129 -0
- data/bin/ruby-prof +207 -0
- data/examples/flat.txt +55 -0
- data/examples/graph.html +823 -0
- data/examples/graph.txt +170 -0
- data/ext/extconf.rb +34 -0
- data/ext/measure_allocations.h +58 -0
- data/ext/measure_cpu_time.h +152 -0
- data/ext/measure_gc_runs.h +76 -0
- data/ext/measure_gc_time.h +57 -0
- data/ext/measure_memory.h +101 -0
- data/ext/measure_process_time.h +52 -0
- data/ext/measure_wall_time.h +53 -0
- data/ext/mingw/Rakefile +23 -0
- data/ext/mingw/build.rake +38 -0
- data/ext/ruby_prof.c +1747 -0
- data/ext/ruby_prof.h +185 -0
- data/ext/vc/ruby_prof.sln +20 -0
- data/ext/vc/ruby_prof.vcproj +241 -0
- data/ext/version.h +4 -0
- data/lib/ruby-prof.rb +51 -0
- data/lib/ruby-prof/abstract_printer.rb +41 -0
- data/lib/ruby-prof/aggregate_call_info.rb +68 -0
- data/lib/ruby-prof/call_info.rb +112 -0
- data/lib/ruby-prof/call_stack_printer.rb +746 -0
- data/lib/ruby-prof/call_tree_printer.rb +84 -0
- data/lib/ruby-prof/empty.png +0 -0
- data/lib/ruby-prof/flat_printer.rb +79 -0
- data/lib/ruby-prof/graph_html_printer.rb +272 -0
- data/lib/ruby-prof/graph_printer.rb +164 -0
- data/lib/ruby-prof/method_info.rb +131 -0
- data/lib/ruby-prof/minus.png +0 -0
- data/lib/ruby-prof/multi_printer.rb +55 -0
- data/lib/ruby-prof/plus.png +0 -0
- data/lib/ruby-prof/result.rb +70 -0
- data/lib/ruby-prof/task.rb +146 -0
- data/lib/ruby-prof/test.rb +148 -0
- data/lib/unprof.rb +8 -0
- data/rails/environment/profile.rb +24 -0
- data/rails/example/example_test.rb +9 -0
- data/rails/profile_test_helper.rb +21 -0
- data/test/aggregate_test.rb +136 -0
- data/test/basic_test.rb +283 -0
- data/test/duplicate_names_test.rb +32 -0
- data/test/exceptions_test.rb +15 -0
- data/test/exclude_threads_test.rb +54 -0
- data/test/line_number_test.rb +73 -0
- data/test/measurement_test.rb +121 -0
- data/test/method_elimination_test.rb +74 -0
- data/test/module_test.rb +54 -0
- data/test/multi_printer_test.rb +81 -0
- data/test/no_method_class_test.rb +13 -0
- data/test/prime.rb +58 -0
- data/test/prime_test.rb +13 -0
- data/test/printers_test.rb +73 -0
- data/test/recursive_test.rb +215 -0
- data/test/singleton_test.rb +38 -0
- data/test/stack_printer_test.rb +74 -0
- data/test/stack_test.rb +138 -0
- data/test/start_stop_test.rb +95 -0
- data/test/test_suite.rb +26 -0
- data/test/thread_test.rb +159 -0
- data/test/unique_call_path_test.rb +206 -0
- metadata +128 -0
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
#!/usr/bin/env ruby
|
|
2
|
+
|
|
3
|
+
require 'test/unit'
|
|
4
|
+
require 'ruby-prof'
|
|
5
|
+
|
|
6
|
+
class DuplicateNames < Test::Unit::TestCase
|
|
7
|
+
def test_names
|
|
8
|
+
result = RubyProf::profile do
|
|
9
|
+
str = %{module Foo; class Bar; def foo; end end end}
|
|
10
|
+
|
|
11
|
+
eval str
|
|
12
|
+
Foo::Bar.new.foo
|
|
13
|
+
DuplicateNames.class_eval {remove_const :Foo}
|
|
14
|
+
|
|
15
|
+
eval str
|
|
16
|
+
Foo::Bar.new.foo
|
|
17
|
+
DuplicateNames.class_eval {remove_const :Foo}
|
|
18
|
+
|
|
19
|
+
eval str
|
|
20
|
+
Foo::Bar.new.foo
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
# There should be 3 foo methods
|
|
24
|
+
methods = result.threads.values.first.sort.reverse
|
|
25
|
+
|
|
26
|
+
methods = methods.select do |method|
|
|
27
|
+
method.full_name == 'DuplicateNames::Foo::Bar#foo'
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
assert_equal(3, methods.length)
|
|
31
|
+
end
|
|
32
|
+
end
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
#!/usr/bin/env ruby
|
|
2
|
+
require 'test/unit'
|
|
3
|
+
require 'ruby-prof'
|
|
4
|
+
|
|
5
|
+
class ExceptionsTest < Test::Unit::TestCase
|
|
6
|
+
def test_profile
|
|
7
|
+
result = begin
|
|
8
|
+
RubyProf.profile do
|
|
9
|
+
raise(RuntimeError, 'Test error')
|
|
10
|
+
end
|
|
11
|
+
rescue => e
|
|
12
|
+
end
|
|
13
|
+
assert_not_nil(result)
|
|
14
|
+
end
|
|
15
|
+
end
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
#!/usr/bin/env ruby
|
|
2
|
+
|
|
3
|
+
require 'test/unit'
|
|
4
|
+
require 'ruby-prof'
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
# -- Tests ----
|
|
8
|
+
class ExcludeThreadsTest < Test::Unit::TestCase
|
|
9
|
+
def test_exclude_threads
|
|
10
|
+
|
|
11
|
+
def thread1_proc
|
|
12
|
+
sleep(0.5)
|
|
13
|
+
sleep(2)
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
def thread2_proc
|
|
17
|
+
sleep(0.5)
|
|
18
|
+
sleep(2)
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
thread1 = Thread.new do
|
|
22
|
+
thread1_proc
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
thread2 = Thread.new do
|
|
26
|
+
thread2_proc
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
RubyProf::exclude_threads = [ thread2 ]
|
|
30
|
+
|
|
31
|
+
RubyProf.start
|
|
32
|
+
|
|
33
|
+
thread1.join
|
|
34
|
+
thread2.join
|
|
35
|
+
|
|
36
|
+
result = RubyProf.stop
|
|
37
|
+
|
|
38
|
+
RubyProf::exclude_threads = nil
|
|
39
|
+
|
|
40
|
+
assert_equal(2, result.threads.length)
|
|
41
|
+
|
|
42
|
+
output = Array.new
|
|
43
|
+
result.threads.each do | thread_id, methods |
|
|
44
|
+
methods.each do | m |
|
|
45
|
+
if m.full_name.index("ExcludeThreadsTest#thread") == 0
|
|
46
|
+
output.push(m.full_name)
|
|
47
|
+
end
|
|
48
|
+
end
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
assert_equal(1, output.length)
|
|
52
|
+
assert_equal("ExcludeThreadsTest#thread1_proc", output[0])
|
|
53
|
+
end
|
|
54
|
+
end
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
#!/usr/bin/env ruby
|
|
2
|
+
require 'test/unit'
|
|
3
|
+
require 'ruby-prof'
|
|
4
|
+
require 'prime'
|
|
5
|
+
|
|
6
|
+
class LineNumbers
|
|
7
|
+
def method1
|
|
8
|
+
a = 3
|
|
9
|
+
end
|
|
10
|
+
|
|
11
|
+
def method2
|
|
12
|
+
a = 3
|
|
13
|
+
method1
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
def method3
|
|
17
|
+
sleep(1)
|
|
18
|
+
end
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
# -- Tests ----
|
|
22
|
+
class LineNumbersTest < Test::Unit::TestCase
|
|
23
|
+
def test_function_line_no
|
|
24
|
+
numbers = LineNumbers.new
|
|
25
|
+
|
|
26
|
+
result = RubyProf.profile do
|
|
27
|
+
numbers.method2
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
methods = result.threads.values.first.sort.reverse
|
|
31
|
+
assert_equal(3, methods.length)
|
|
32
|
+
|
|
33
|
+
method = methods[0]
|
|
34
|
+
assert_equal('LineNumbersTest#test_function_line_no', method.full_name)
|
|
35
|
+
assert_equal(27, method.line)
|
|
36
|
+
|
|
37
|
+
method = methods[1]
|
|
38
|
+
assert_equal('LineNumbers#method2', method.full_name)
|
|
39
|
+
assert_equal(11, method.line)
|
|
40
|
+
|
|
41
|
+
method = methods[2]
|
|
42
|
+
assert_equal('LineNumbers#method1', method.full_name)
|
|
43
|
+
assert_equal(7, method.line)
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
def test_c_function
|
|
47
|
+
numbers = LineNumbers.new
|
|
48
|
+
|
|
49
|
+
result = RubyProf.profile do
|
|
50
|
+
numbers.method3
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
methods = result.threads.values.first.sort_by {|method| method.full_name}
|
|
54
|
+
assert_equal(3, methods.length)
|
|
55
|
+
|
|
56
|
+
# Methods:
|
|
57
|
+
# LineNumbers#method3
|
|
58
|
+
# LineNumbersTest#test_c_function
|
|
59
|
+
# Kernel#sleep
|
|
60
|
+
|
|
61
|
+
method = methods[0]
|
|
62
|
+
assert_equal('Kernel#sleep', method.full_name)
|
|
63
|
+
assert_equal(0, method.line)
|
|
64
|
+
|
|
65
|
+
method = methods[1]
|
|
66
|
+
assert_equal('LineNumbers#method3', method.full_name)
|
|
67
|
+
assert_equal(16, method.line)
|
|
68
|
+
|
|
69
|
+
method = methods[2]
|
|
70
|
+
assert_equal('LineNumbersTest#test_c_function', method.full_name)
|
|
71
|
+
assert_equal(50, method.line)
|
|
72
|
+
end
|
|
73
|
+
end
|
|
@@ -0,0 +1,121 @@
|
|
|
1
|
+
#!/usr/bin/env ruby
|
|
2
|
+
require 'test/unit'
|
|
3
|
+
require 'ruby-prof'
|
|
4
|
+
|
|
5
|
+
class MeasurementTest < Test::Unit::TestCase
|
|
6
|
+
def setup
|
|
7
|
+
GC.enable_stats if GC.respond_to?(:enable_stats)
|
|
8
|
+
end
|
|
9
|
+
|
|
10
|
+
def teardown
|
|
11
|
+
GC.disable_stats if GC.respond_to?(:disable_stats)
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
def test_process_time_mode
|
|
15
|
+
RubyProf::measure_mode = RubyProf::PROCESS_TIME
|
|
16
|
+
assert_equal(RubyProf::PROCESS_TIME, RubyProf::measure_mode)
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
def test_process_time
|
|
20
|
+
t = RubyProf.measure_process_time
|
|
21
|
+
assert_kind_of(Float, t)
|
|
22
|
+
|
|
23
|
+
u = RubyProf.measure_process_time
|
|
24
|
+
assert(u >= t, [t, u].inspect)
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
def test_wall_time_mode
|
|
28
|
+
RubyProf::measure_mode = RubyProf::WALL_TIME
|
|
29
|
+
assert_equal(RubyProf::WALL_TIME, RubyProf::measure_mode)
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
def test_wall_time
|
|
33
|
+
t = RubyProf.measure_wall_time
|
|
34
|
+
assert_kind_of Float, t
|
|
35
|
+
|
|
36
|
+
u = RubyProf.measure_wall_time
|
|
37
|
+
assert u >= t, [t, u].inspect
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
if RubyProf::CPU_TIME
|
|
41
|
+
def test_cpu_time_mode
|
|
42
|
+
RubyProf::measure_mode = RubyProf::CPU_TIME
|
|
43
|
+
assert_equal(RubyProf::CPU_TIME, RubyProf::measure_mode)
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
def test_cpu_time
|
|
47
|
+
RubyProf.cpu_frequency = 2.33e9
|
|
48
|
+
|
|
49
|
+
t = RubyProf.measure_cpu_time
|
|
50
|
+
assert_kind_of Float, t
|
|
51
|
+
|
|
52
|
+
u = RubyProf.measure_cpu_time
|
|
53
|
+
assert u > t, [t, u].inspect
|
|
54
|
+
end
|
|
55
|
+
end
|
|
56
|
+
|
|
57
|
+
if RubyProf::ALLOCATIONS
|
|
58
|
+
def test_allocations_mode
|
|
59
|
+
RubyProf::measure_mode = RubyProf::ALLOCATIONS
|
|
60
|
+
assert_equal(RubyProf::ALLOCATIONS, RubyProf::measure_mode)
|
|
61
|
+
end
|
|
62
|
+
|
|
63
|
+
def test_allocations
|
|
64
|
+
t = RubyProf.measure_allocations
|
|
65
|
+
assert_kind_of Integer, t
|
|
66
|
+
|
|
67
|
+
u = RubyProf.measure_allocations
|
|
68
|
+
assert u > t, [t, u].inspect
|
|
69
|
+
end
|
|
70
|
+
end
|
|
71
|
+
|
|
72
|
+
if RubyProf::MEMORY
|
|
73
|
+
def test_memory_mode
|
|
74
|
+
RubyProf::measure_mode = RubyProf::MEMORY
|
|
75
|
+
assert_equal(RubyProf::MEMORY, RubyProf::measure_mode)
|
|
76
|
+
end
|
|
77
|
+
|
|
78
|
+
def test_memory
|
|
79
|
+
t = RubyProf.measure_memory
|
|
80
|
+
assert_kind_of Integer, t
|
|
81
|
+
|
|
82
|
+
u = RubyProf.measure_memory
|
|
83
|
+
assert(u >= t, [t, u].inspect)
|
|
84
|
+
|
|
85
|
+
result = RubyProf.profile {Array.new}
|
|
86
|
+
total = result.threads.values.first.methods.inject(0) { |sum, m| sum + m.total_time }
|
|
87
|
+
|
|
88
|
+
assert(total > 0, 'Should measure more than zero kilobytes of memory usage')
|
|
89
|
+
assert_not_equal(0, total % 1, 'Should not truncate fractional kilobyte measurements')
|
|
90
|
+
end
|
|
91
|
+
end
|
|
92
|
+
|
|
93
|
+
if RubyProf::GC_RUNS
|
|
94
|
+
def test_gc_runs_mode
|
|
95
|
+
RubyProf::measure_mode = RubyProf::GC_RUNS
|
|
96
|
+
assert_equal(RubyProf::GC_RUNS, RubyProf::measure_mode)
|
|
97
|
+
end
|
|
98
|
+
|
|
99
|
+
def test_gc_runs
|
|
100
|
+
t = RubyProf.measure_gc_runs
|
|
101
|
+
assert_kind_of Integer, t
|
|
102
|
+
|
|
103
|
+
GC.start
|
|
104
|
+
|
|
105
|
+
u = RubyProf.measure_gc_runs
|
|
106
|
+
assert u > t, [t, u].inspect
|
|
107
|
+
end
|
|
108
|
+
end
|
|
109
|
+
|
|
110
|
+
if RubyProf::GC_TIME
|
|
111
|
+
def test_gc_time
|
|
112
|
+
t = RubyProf.measure_gc_time
|
|
113
|
+
assert_kind_of Integer, t
|
|
114
|
+
|
|
115
|
+
GC.start
|
|
116
|
+
|
|
117
|
+
u = RubyProf.measure_gc_time
|
|
118
|
+
assert u > t, [t, u].inspect
|
|
119
|
+
end
|
|
120
|
+
end
|
|
121
|
+
end
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
#!/usr/bin/env ruby
|
|
2
|
+
|
|
3
|
+
require 'test/unit'
|
|
4
|
+
require 'ruby-prof'
|
|
5
|
+
require 'tmpdir'
|
|
6
|
+
|
|
7
|
+
# Test data
|
|
8
|
+
# A
|
|
9
|
+
# / \
|
|
10
|
+
# B C
|
|
11
|
+
# \
|
|
12
|
+
# B
|
|
13
|
+
|
|
14
|
+
class ESTPT
|
|
15
|
+
def a
|
|
16
|
+
100.times{b}
|
|
17
|
+
300.times{c}
|
|
18
|
+
c;c;c
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
def b
|
|
22
|
+
sleep 0.0001
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
def c
|
|
26
|
+
5.times{b}
|
|
27
|
+
end
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
class MethodEliminationTest < Test::Unit::TestCase
|
|
31
|
+
def setup
|
|
32
|
+
# Need to use wall time for this test due to the sleep calls
|
|
33
|
+
RubyProf::measure_mode = RubyProf::WALL_TIME
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
def test_setting_parent
|
|
37
|
+
result = RubyProf.profile do
|
|
38
|
+
1000.times { 1+1 }
|
|
39
|
+
end
|
|
40
|
+
method_infos = result.threads.values.first
|
|
41
|
+
assert(m1 = method_infos[0])
|
|
42
|
+
assert(c1 = m1.call_infos.first)
|
|
43
|
+
assert_equal(c1, c1.parent = c1)
|
|
44
|
+
assert_equal c1, c1.parent
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
def test_methods_can_be_eliminated
|
|
48
|
+
RubyProf.start
|
|
49
|
+
5.times{ESTPT.new.a}
|
|
50
|
+
result = RubyProf.stop
|
|
51
|
+
# result.dump
|
|
52
|
+
eliminated = result.eliminate_methods!([/Integer#times/])
|
|
53
|
+
# puts eliminated.inspect
|
|
54
|
+
# result.dump
|
|
55
|
+
eliminated.each do |m|
|
|
56
|
+
assert_method_has_been_eliminated(result, m)
|
|
57
|
+
end
|
|
58
|
+
end
|
|
59
|
+
|
|
60
|
+
private
|
|
61
|
+
def assert_method_has_been_eliminated(result, eliminated_method)
|
|
62
|
+
result.threads.each do |thread_id, methods|
|
|
63
|
+
methods.each do |method|
|
|
64
|
+
method.call_infos.each do |ci|
|
|
65
|
+
assert(ci.target != eliminated_method, "broken self")
|
|
66
|
+
assert(ci.parent.target != eliminated_method, "broken parent") if ci.parent
|
|
67
|
+
ci.children.each do |callee|
|
|
68
|
+
assert(callee.target != eliminated_method, "broken kid")
|
|
69
|
+
end
|
|
70
|
+
end
|
|
71
|
+
end
|
|
72
|
+
end
|
|
73
|
+
end
|
|
74
|
+
end
|
data/test/module_test.rb
ADDED
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
#!/usr/bin/env ruby
|
|
2
|
+
require 'test/unit'
|
|
3
|
+
require 'ruby-prof'
|
|
4
|
+
|
|
5
|
+
# Need to use wall time for this test due to the sleep calls
|
|
6
|
+
RubyProf::measure_mode = RubyProf::WALL_TIME
|
|
7
|
+
|
|
8
|
+
module Foo
|
|
9
|
+
def Foo::hello
|
|
10
|
+
sleep(0.5)
|
|
11
|
+
end
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
module Bar
|
|
15
|
+
def Bar::hello
|
|
16
|
+
sleep(0.5)
|
|
17
|
+
Foo::hello
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
def hello
|
|
21
|
+
sleep(0.5)
|
|
22
|
+
Bar::hello
|
|
23
|
+
end
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
include Bar
|
|
27
|
+
|
|
28
|
+
class ModuleTest < Test::Unit::TestCase
|
|
29
|
+
def test_nested_modules
|
|
30
|
+
result = RubyProf.profile do
|
|
31
|
+
hello
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
methods = result.threads.values.first.sort.reverse
|
|
35
|
+
|
|
36
|
+
# Length should be 5
|
|
37
|
+
assert_equal(5, methods.length)
|
|
38
|
+
|
|
39
|
+
method = methods[0]
|
|
40
|
+
assert_equal('ModuleTest#test_nested_modules', method.full_name)
|
|
41
|
+
|
|
42
|
+
method = methods[1]
|
|
43
|
+
assert_equal('Bar#hello', method.full_name)
|
|
44
|
+
|
|
45
|
+
method = methods[2]
|
|
46
|
+
assert_equal('Kernel#sleep', method.full_name)
|
|
47
|
+
|
|
48
|
+
method = methods[3]
|
|
49
|
+
assert_equal('<Module::Bar>#hello', method.full_name)
|
|
50
|
+
|
|
51
|
+
method = methods[4]
|
|
52
|
+
assert_equal('<Module::Foo>#hello', method.full_name)
|
|
53
|
+
end
|
|
54
|
+
end
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
#!/usr/bin/env ruby
|
|
2
|
+
|
|
3
|
+
require 'test/unit'
|
|
4
|
+
require 'ruby-prof'
|
|
5
|
+
require 'tmpdir'
|
|
6
|
+
|
|
7
|
+
# Test data
|
|
8
|
+
# A
|
|
9
|
+
# / \
|
|
10
|
+
# B C
|
|
11
|
+
# \
|
|
12
|
+
# B
|
|
13
|
+
|
|
14
|
+
class MSTPT
|
|
15
|
+
def a
|
|
16
|
+
100.times{b}
|
|
17
|
+
300.times{c}
|
|
18
|
+
c;c;c
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
def b
|
|
22
|
+
sleep 0.0001
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
def c
|
|
26
|
+
5.times{b}
|
|
27
|
+
end
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
class MultiPrinterTest < Test::Unit::TestCase
|
|
31
|
+
def setup
|
|
32
|
+
# Need to use wall time for this test due to the sleep calls
|
|
33
|
+
RubyProf::measure_mode = RubyProf::WALL_TIME
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
def test_all_profiles_can_be_created
|
|
37
|
+
start_time = Time.now
|
|
38
|
+
RubyProf.start
|
|
39
|
+
5.times{MSTPT.new.a}
|
|
40
|
+
result = RubyProf.stop
|
|
41
|
+
end_time = Time.now
|
|
42
|
+
expected_time = end_time - start_time
|
|
43
|
+
stack = graph = nil
|
|
44
|
+
assert_nothing_raised { stack, graph = print(result) }
|
|
45
|
+
re = Regexp.new('
|
|
46
|
+
\s*<table>
|
|
47
|
+
\s*<tr>
|
|
48
|
+
\s*<th>Thread ID</th>
|
|
49
|
+
\s*<th>Total Time</th>
|
|
50
|
+
\s*</tr>
|
|
51
|
+
\s*
|
|
52
|
+
\s*<tr>
|
|
53
|
+
\s*<td><a href="#\d+">\d+</a></td>
|
|
54
|
+
\s*<td>([\.0-9]+)</td>
|
|
55
|
+
\s*</tr>
|
|
56
|
+
\s*
|
|
57
|
+
\s*</table>')
|
|
58
|
+
assert graph =~ re
|
|
59
|
+
display_time = $1.to_f
|
|
60
|
+
difference = (expected_time-display_time).abs
|
|
61
|
+
assert_in_delta expected_time, display_time, 0.001
|
|
62
|
+
end
|
|
63
|
+
|
|
64
|
+
private
|
|
65
|
+
def print(result)
|
|
66
|
+
test = caller.first =~ /in `(.*)'/ ? $1 : "test"
|
|
67
|
+
path = Dir::tmpdir
|
|
68
|
+
profile = "ruby_prof_#{test}"
|
|
69
|
+
printer = RubyProf::MultiPrinter.new(result)
|
|
70
|
+
printer.print(:path => path, :profile => profile,
|
|
71
|
+
:threshold => 0, :min_percent => 0, :title => "ruby_prof #{test}")
|
|
72
|
+
if RUBY_PLATFORM =~ /darwin/ && ENV['SHOW_FILES']=="1"
|
|
73
|
+
system("open #{printer.stack_profile}")
|
|
74
|
+
end
|
|
75
|
+
if GC.respond_to?(:dump_file_and_line_info)
|
|
76
|
+
GC.start
|
|
77
|
+
GC.dump_file_and_line_info("heap.dump")
|
|
78
|
+
end
|
|
79
|
+
[File.open(printer.stack_profile){|f|f.read}, File.open(printer.graph_profile){|f|f.read}]
|
|
80
|
+
end
|
|
81
|
+
end
|