ruby-prof 0.15.9 → 0.16.0
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.
- checksums.yaml +4 -4
- data/CHANGES +27 -1
- data/README.rdoc +83 -31
- data/bin/ruby-prof +4 -4
- data/doc/LICENSE.html +1 -1
- data/doc/README_rdoc.html +92 -33
- data/doc/Rack.html +1 -1
- data/doc/Rack/RubyProf.html +17 -14
- data/doc/RubyProf.html +30 -29
- data/doc/RubyProf/AbstractPrinter.html +1 -1
- data/doc/RubyProf/AggregateCallInfo.html +1 -1
- data/doc/RubyProf/CallInfo.html +1 -1
- data/doc/RubyProf/CallInfoPrinter.html +1 -1
- data/doc/RubyProf/CallInfoVisitor.html +1 -1
- data/doc/RubyProf/CallStackPrinter.html +1 -1
- data/doc/RubyProf/CallTreePrinter.html +349 -67
- data/doc/RubyProf/Cmd.html +5 -5
- data/doc/RubyProf/DotPrinter.html +2 -2
- data/doc/RubyProf/FlatPrinter.html +1 -1
- data/doc/RubyProf/FlatPrinterWithLineNumbers.html +1 -1
- data/doc/RubyProf/GraphHtmlPrinter.html +1 -1
- data/doc/RubyProf/GraphPrinter.html +1 -1
- data/doc/RubyProf/MethodInfo.html +2 -2
- data/doc/RubyProf/MultiPrinter.html +11 -9
- data/doc/RubyProf/Profile.html +94 -44
- data/doc/RubyProf/ProfileTask.html +1 -1
- data/doc/RubyProf/Thread.html +43 -1
- data/doc/created.rid +16 -16
- data/doc/examples/flat_txt.html +1 -1
- data/doc/examples/graph_html.html +1 -1
- data/doc/examples/graph_txt.html +3 -3
- data/doc/index.html +85 -30
- data/doc/js/navigation.js.gz +0 -0
- data/doc/js/search_index.js +1 -1
- data/doc/js/search_index.js.gz +0 -0
- data/doc/js/searcher.js +2 -2
- data/doc/js/searcher.js.gz +0 -0
- data/doc/table_of_contents.html +117 -68
- data/examples/cachegrind.out.1 +114 -0
- data/examples/cachegrind.out.1.32313213 +114 -0
- data/examples/graph.txt +1 -1
- data/ext/ruby_prof/extconf.rb +6 -2
- data/ext/ruby_prof/rp_measure_cpu_time.c +29 -31
- data/ext/ruby_prof/rp_method.c +1 -1
- data/ext/ruby_prof/rp_thread.c +57 -52
- data/ext/ruby_prof/ruby_prof.c +122 -66
- data/ext/ruby_prof/ruby_prof.h +2 -0
- data/lib/ruby-prof.rb +14 -13
- data/lib/ruby-prof/assets/call_stack_printer.js.html +1 -1
- data/lib/ruby-prof/compatibility.rb +9 -8
- data/lib/ruby-prof/method_info.rb +1 -1
- data/lib/ruby-prof/printers/call_tree_printer.rb +88 -50
- data/lib/ruby-prof/printers/dot_printer.rb +1 -1
- data/lib/ruby-prof/printers/multi_printer.rb +6 -4
- data/lib/ruby-prof/profile.rb +0 -1
- data/lib/ruby-prof/rack.rb +53 -16
- data/lib/ruby-prof/thread.rb +11 -0
- data/lib/ruby-prof/version.rb +1 -1
- data/test/exclude_threads_test.rb +2 -3
- data/test/fiber_test.rb +21 -7
- data/test/measure_cpu_time_test.rb +84 -24
- data/test/multi_printer_test.rb +5 -4
- data/test/pause_resume_test.rb +7 -7
- data/test/printers_test.rb +6 -4
- data/test/rack_test.rb +26 -1
- data/test/test_helper.rb +28 -3
- data/test/thread_test.rb +1 -0
- metadata +5 -3
@@ -18,15 +18,17 @@ module RubyProf
|
|
18
18
|
def print(options)
|
19
19
|
@profile = options.delete(:profile) || "profile"
|
20
20
|
@directory = options.delete(:path) || File.expand_path(".")
|
21
|
+
|
21
22
|
File.open(stack_profile, "w") do |f|
|
22
23
|
@stack_printer.print(f, options.merge(:graph => "#{@profile}.graph.html"))
|
23
24
|
end
|
25
|
+
|
24
26
|
File.open(graph_profile, "w") do |f|
|
25
27
|
@graph_printer.print(f, options)
|
26
28
|
end
|
27
|
-
|
28
|
-
|
29
|
-
|
29
|
+
|
30
|
+
@tree_printer.print(options.merge(:path => @directory, :profile => @profile))
|
31
|
+
|
30
32
|
File.open(flat_profile, "w") do |f|
|
31
33
|
@flat_printer.print(f, options)
|
32
34
|
end
|
@@ -44,7 +46,7 @@ module RubyProf
|
|
44
46
|
|
45
47
|
# the name of the callgrind profile file
|
46
48
|
def tree_profile
|
47
|
-
"#{@directory}/#{@profile}.
|
49
|
+
"#{@directory}/#{@profile}.callgrind.out.#{$$}"
|
48
50
|
end
|
49
51
|
|
50
52
|
# the name of the flat profile file
|
data/lib/ruby-prof/profile.rb
CHANGED
data/lib/ruby-prof/rack.rb
CHANGED
@@ -16,30 +16,61 @@ module Rack
|
|
16
16
|
::RubyProf::GraphHtmlPrinter => 'graph.html',
|
17
17
|
::RubyProf::CallStackPrinter => 'call_stack.html'}
|
18
18
|
|
19
|
-
@skip_paths = options[:skip_paths] || [%r{^/assets}, %r{\.css
|
19
|
+
@skip_paths = options[:skip_paths] || [%r{^/assets}, %r{\.(css|js|png|jpeg|jpg|gif)$}]
|
20
|
+
@only_paths = options[:only_paths]
|
20
21
|
end
|
21
22
|
|
22
23
|
def call(env)
|
23
24
|
request = Rack::Request.new(env)
|
24
25
|
|
25
|
-
if
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
end
|
26
|
+
if should_profile?(request.path)
|
27
|
+
begin
|
28
|
+
result = nil
|
29
|
+
data = ::RubyProf::Profile.profile(profiling_options) do
|
30
|
+
result = @app.call(env)
|
31
|
+
end
|
32
32
|
|
33
|
-
|
34
|
-
|
33
|
+
path = request.path.gsub('/', '-')
|
34
|
+
path.slice!(0)
|
35
35
|
|
36
|
-
|
37
|
-
|
36
|
+
print(data, path)
|
37
|
+
result
|
38
|
+
end
|
39
|
+
else
|
40
|
+
@app.call(env)
|
38
41
|
end
|
39
42
|
end
|
40
43
|
|
41
44
|
private
|
42
45
|
|
46
|
+
def should_profile?(path)
|
47
|
+
return false if paths_match?(path, @skip_paths)
|
48
|
+
|
49
|
+
@only_paths ? paths_match?(path, @only_paths) : true
|
50
|
+
end
|
51
|
+
|
52
|
+
def paths_match?(path, paths)
|
53
|
+
paths.any? { |skip_path| skip_path =~ path }
|
54
|
+
end
|
55
|
+
|
56
|
+
def profiling_options
|
57
|
+
options = {}
|
58
|
+
options[:measure_mode] = ::RubyProf.measure_mode
|
59
|
+
options[:exclude_threads] =
|
60
|
+
if @options[:ignore_existing_threads]
|
61
|
+
Thread.list.select{|t| t != Thread.current}
|
62
|
+
else
|
63
|
+
::RubyProf.exclude_threads
|
64
|
+
end
|
65
|
+
if @options[:request_thread_only]
|
66
|
+
options[:include_threads] = [Thread.current]
|
67
|
+
end
|
68
|
+
if @options[:merge_fibers]
|
69
|
+
options[:merge_fibers] = true
|
70
|
+
end
|
71
|
+
options
|
72
|
+
end
|
73
|
+
|
43
74
|
def print(data, path)
|
44
75
|
@printer_klasses.each do |printer_klass, base_name|
|
45
76
|
printer = printer_klass.new(data)
|
@@ -48,11 +79,17 @@ module Rack
|
|
48
79
|
base_name = base_name.call
|
49
80
|
end
|
50
81
|
|
51
|
-
|
52
|
-
|
53
|
-
|
82
|
+
if printer_klass == ::RubyProf::MultiPrinter
|
83
|
+
printer.print(@options.merge(:profile => "#{path}-#{base_name}"))
|
84
|
+
elsif printer_klass == ::RubyProf::CallTreePrinter
|
85
|
+
printer.print(@options.merge(:profile => "#{path}-#{base_name}"))
|
86
|
+
else
|
87
|
+
file_name = ::File.join(@tmpdir, "#{path}-#{base_name}")
|
88
|
+
::File.open(file_name, 'wb') do |file|
|
89
|
+
printer.print(file, @options)
|
90
|
+
end
|
54
91
|
end
|
55
92
|
end
|
56
93
|
end
|
57
94
|
end
|
58
|
-
end
|
95
|
+
end
|
data/lib/ruby-prof/thread.rb
CHANGED
@@ -26,5 +26,16 @@ module RubyProf
|
|
26
26
|
sum
|
27
27
|
end
|
28
28
|
end
|
29
|
+
|
30
|
+
def wait_time
|
31
|
+
# wait_time, like self:time, is always method local
|
32
|
+
# thus we need to sum over all methods and call infos
|
33
|
+
self.methods.inject(0) do |sum, method_info|
|
34
|
+
method_info.call_infos.each do |call_info|
|
35
|
+
sum += call_info.wait_time
|
36
|
+
end
|
37
|
+
sum
|
38
|
+
end
|
39
|
+
end
|
29
40
|
end
|
30
41
|
end
|
data/lib/ruby-prof/version.rb
CHANGED
@@ -26,7 +26,8 @@ class ExcludeThreadsTest < TestCase
|
|
26
26
|
thread2_proc
|
27
27
|
end
|
28
28
|
|
29
|
-
|
29
|
+
# exclude_threads already includes the minitest thread pool
|
30
|
+
RubyProf.exclude_threads += [ thread2 ]
|
30
31
|
|
31
32
|
RubyProf.start
|
32
33
|
|
@@ -35,8 +36,6 @@ class ExcludeThreadsTest < TestCase
|
|
35
36
|
|
36
37
|
result = RubyProf.stop
|
37
38
|
|
38
|
-
RubyProf::exclude_threads = nil
|
39
|
-
|
40
39
|
assert_equal(2, result.threads.length)
|
41
40
|
|
42
41
|
output = Array.new
|
data/test/fiber_test.rb
CHANGED
@@ -37,18 +37,18 @@ class FiberTest < TestCase
|
|
37
37
|
@fiber_ids = Set.new
|
38
38
|
@root_fiber = Fiber.current.object_id
|
39
39
|
@thread_id = Thread.current.object_id
|
40
|
-
@result = RubyProf.profile { fiber_test }
|
41
40
|
end
|
42
41
|
|
43
42
|
def test_fibers
|
44
|
-
|
45
|
-
|
46
|
-
assert_equal(
|
43
|
+
result = RubyProf.profile { fiber_test }
|
44
|
+
profiled_fiber_ids = result.threads.map(&:fiber_id)
|
45
|
+
assert_equal(2, result.threads.length)
|
46
|
+
assert_equal([@thread_id], result.threads.map(&:id).uniq)
|
47
47
|
assert_equal(@fiber_ids, Set.new(profiled_fiber_ids))
|
48
48
|
|
49
49
|
assert profiled_fiber_ids.include?(@root_fiber)
|
50
|
-
assert(root_fiber_profile =
|
51
|
-
assert(enum_fiber_profile =
|
50
|
+
assert(root_fiber_profile = result.threads.detect{|t| t.fiber_id == @root_fiber})
|
51
|
+
assert(enum_fiber_profile = result.threads.detect{|t| t.fiber_id != @root_fiber})
|
52
52
|
|
53
53
|
assert_in_delta(0.3, root_fiber_profile.total_time, 0.05)
|
54
54
|
assert_in_delta(0.2, enum_fiber_profile.total_time, 0.05)
|
@@ -58,8 +58,22 @@ class FiberTest < TestCase
|
|
58
58
|
|
59
59
|
assert_in_delta(0.2, method_next.total_time, 0.05)
|
60
60
|
assert_in_delta(0.2, method_each.total_time, 0.05)
|
61
|
+
end
|
62
|
+
|
63
|
+
def test_merged_fibers
|
64
|
+
result = RubyProf.profile(merge_fibers: true) { fiber_test }
|
65
|
+
assert_equal(1, result.threads.length)
|
66
|
+
|
67
|
+
profile = result.threads.first
|
68
|
+
assert_equal 0, profile.fiber_id
|
69
|
+
|
70
|
+
assert_in_delta(0.3, profile.total_time, 0.05)
|
61
71
|
|
62
|
-
|
72
|
+
assert(method_next = profile.methods.detect{|m| m.full_name == "Enumerator#next"})
|
73
|
+
assert(method_each = profile.methods.detect{|m| m.full_name == "Enumerator#each"})
|
74
|
+
|
75
|
+
assert_in_delta(0.2, method_next.total_time, 0.05)
|
76
|
+
assert_in_delta(0.2, method_each.total_time, 0.05)
|
63
77
|
end
|
64
78
|
|
65
79
|
end
|
@@ -8,8 +8,11 @@ class MeasureCpuTimeTest < TestCase
|
|
8
8
|
RubyProf::measure_mode = RubyProf::CPU_TIME
|
9
9
|
end
|
10
10
|
|
11
|
+
def teardown
|
12
|
+
RubyProf::measure_mode = RubyProf::WALL_TIME
|
13
|
+
end
|
14
|
+
|
11
15
|
def test_mode
|
12
|
-
RubyProf::measure_mode = RubyProf::CPU_TIME
|
13
16
|
assert_equal(RubyProf::CPU_TIME, RubyProf::measure_mode)
|
14
17
|
end
|
15
18
|
|
@@ -19,12 +22,12 @@ class MeasureCpuTimeTest < TestCase
|
|
19
22
|
|
20
23
|
def test_class_methods
|
21
24
|
result = RubyProf.profile do
|
22
|
-
RubyProf::C7.
|
25
|
+
RubyProf::C7.busy_wait
|
23
26
|
end
|
24
27
|
|
25
28
|
# Length should be greater 2:
|
26
29
|
# MeasureCpuTimeTest#test_class_methods
|
27
|
-
# <Class::RubyProf::C1>#
|
30
|
+
# <Class::RubyProf::C1>#busy_wait
|
28
31
|
# ....
|
29
32
|
|
30
33
|
methods = result.threads.first.methods.sort.reverse[0..1]
|
@@ -32,21 +35,21 @@ class MeasureCpuTimeTest < TestCase
|
|
32
35
|
|
33
36
|
# Check the names
|
34
37
|
assert_equal('MeasureCpuTimeTest#test_class_methods', methods[0].full_name)
|
35
|
-
assert_equal('<Class::RubyProf::C7>#
|
38
|
+
assert_equal('<Class::RubyProf::C7>#busy_wait', methods[1].full_name)
|
36
39
|
|
37
40
|
# Check times
|
38
|
-
assert_in_delta(0.1, methods[0].total_time, 0.
|
39
|
-
assert_in_delta(0, methods[0].wait_time, 0.
|
40
|
-
assert_in_delta(0, methods[0].self_time, 0.
|
41
|
+
assert_in_delta(0.1, methods[0].total_time, 0.05)
|
42
|
+
assert_in_delta(0, methods[0].wait_time, 0.05)
|
43
|
+
assert_in_delta(0, methods[0].self_time, 0.05)
|
41
44
|
|
42
|
-
assert_in_delta(0.1, methods[1].total_time, 0.
|
43
|
-
assert_in_delta(0, methods[1].wait_time, 0.
|
44
|
-
assert_in_delta(0, methods[1].self_time, 0.
|
45
|
+
assert_in_delta(0.1, methods[1].total_time, 0.05)
|
46
|
+
assert_in_delta(0, methods[1].wait_time, 0.05)
|
47
|
+
assert_in_delta(0, methods[1].self_time, 0.05)
|
45
48
|
end
|
46
49
|
|
47
50
|
def test_instance_methods
|
48
51
|
result = RubyProf.profile do
|
49
|
-
RubyProf::C7.new.
|
52
|
+
RubyProf::C7.new.busy_wait
|
50
53
|
end
|
51
54
|
|
52
55
|
methods = result.threads.first.methods.sort.reverse[0..1]
|
@@ -54,12 +57,12 @@ class MeasureCpuTimeTest < TestCase
|
|
54
57
|
|
55
58
|
# Methods at this point:
|
56
59
|
# MeasureCpuTimeTest#test_instance_methods
|
57
|
-
# C7#
|
60
|
+
# C7#busy_wait
|
58
61
|
# ...
|
59
62
|
|
60
63
|
names = methods.map(&:full_name)
|
61
64
|
assert_equal('MeasureCpuTimeTest#test_instance_methods', names[0])
|
62
|
-
assert_equal('RubyProf::C7#
|
65
|
+
assert_equal('RubyProf::C7#busy_wait', names[1])
|
63
66
|
|
64
67
|
|
65
68
|
# Check times
|
@@ -69,24 +72,24 @@ class MeasureCpuTimeTest < TestCase
|
|
69
72
|
|
70
73
|
assert_in_delta(0.2, methods[1].total_time, 0.03)
|
71
74
|
assert_in_delta(0, methods[1].wait_time, 0.03)
|
72
|
-
assert_in_delta(0, methods[1].self_time, 0.
|
75
|
+
assert_in_delta(0, methods[1].self_time, 0.2)
|
73
76
|
end
|
74
77
|
|
75
78
|
def test_module_methods
|
76
79
|
result = RubyProf.profile do
|
77
|
-
RubyProf::C8.
|
80
|
+
RubyProf::C8.busy_wait
|
78
81
|
end
|
79
82
|
|
80
83
|
# Methods:
|
81
84
|
# MeasureCpuTimeTest#test_module_methods
|
82
|
-
# M1#
|
85
|
+
# M1#busy_wait
|
83
86
|
# ...
|
84
87
|
|
85
88
|
methods = result.threads.first.methods.sort.reverse[0..1]
|
86
89
|
assert_equal(2, methods.length)
|
87
90
|
|
88
91
|
assert_equal('MeasureCpuTimeTest#test_module_methods', methods[0].full_name)
|
89
|
-
assert_equal('RubyProf::M7#
|
92
|
+
assert_equal('RubyProf::M7#busy_wait', methods[1].full_name)
|
90
93
|
|
91
94
|
# Check times
|
92
95
|
assert_in_delta(0.3, methods[0].total_time, 0.1)
|
@@ -100,26 +103,26 @@ class MeasureCpuTimeTest < TestCase
|
|
100
103
|
|
101
104
|
def test_module_instance_methods
|
102
105
|
result = RubyProf.profile do
|
103
|
-
RubyProf::C8.new.
|
106
|
+
RubyProf::C8.new.busy_wait
|
104
107
|
end
|
105
108
|
|
106
109
|
# Methods:
|
107
110
|
# MeasureCpuTimeTest#test_module_instance_methods
|
108
|
-
# M7#
|
111
|
+
# M7#busy_wait
|
109
112
|
# ...
|
110
113
|
|
111
114
|
methods = result.threads.first.methods.sort.reverse[0..1]
|
112
115
|
assert_equal(2, methods.length)
|
113
116
|
names = methods.map(&:full_name)
|
114
117
|
assert_equal('MeasureCpuTimeTest#test_module_instance_methods', names[0])
|
115
|
-
assert_equal('RubyProf::M7#
|
118
|
+
assert_equal('RubyProf::M7#busy_wait', names[1])
|
116
119
|
|
117
120
|
# Check times
|
118
121
|
assert_in_delta(0.3, methods[0].total_time, 0.1)
|
119
122
|
assert_in_delta(0, methods[0].wait_time, 0.1)
|
120
123
|
assert_in_delta(0, methods[0].self_time, 0.1)
|
121
124
|
|
122
|
-
assert_in_delta(0.3, methods[1].total_time, 0.
|
125
|
+
assert_in_delta(0.3, methods[1].total_time, 0.1)
|
123
126
|
assert_in_delta(0, methods[1].wait_time, 0.01)
|
124
127
|
assert_in_delta(0, methods[1].self_time, 0.1)
|
125
128
|
end
|
@@ -128,19 +131,19 @@ class MeasureCpuTimeTest < TestCase
|
|
128
131
|
c3 = RubyProf::C3.new
|
129
132
|
|
130
133
|
class << c3
|
131
|
-
def
|
134
|
+
def busy_wait
|
132
135
|
end
|
133
136
|
end
|
134
137
|
|
135
138
|
result = RubyProf.profile do
|
136
|
-
c3.
|
139
|
+
c3.busy_wait
|
137
140
|
end
|
138
141
|
|
139
142
|
methods = result.threads.first.methods.sort.reverse
|
140
143
|
assert_equal(2, methods.length)
|
141
144
|
|
142
145
|
assert_equal('MeasureCpuTimeTest#test_singleton', methods[0].full_name)
|
143
|
-
assert_equal('<Object::RubyProf::C3>#
|
146
|
+
assert_equal('<Object::RubyProf::C3>#busy_wait', methods[1].full_name)
|
144
147
|
|
145
148
|
assert_in_delta(0, methods[0].total_time, 0.01)
|
146
149
|
assert_in_delta(0, methods[0].wait_time, 0.01)
|
@@ -150,4 +153,61 @@ class MeasureCpuTimeTest < TestCase
|
|
150
153
|
assert_in_delta(0, methods[1].wait_time, 0.01)
|
151
154
|
assert_in_delta(0, methods[1].self_time, 0.01)
|
152
155
|
end
|
156
|
+
|
157
|
+
|
158
|
+
def test_sleeping_does_accumulate_wall_time
|
159
|
+
RubyProf::measure_mode = RubyProf::WALL_TIME
|
160
|
+
result = RubyProf.profile do
|
161
|
+
sleep 0.1
|
162
|
+
end
|
163
|
+
methods = result.threads.first.methods.sort.reverse
|
164
|
+
assert_equal(["MeasureCpuTimeTest#test_sleeping_does_accumulate_wall_time", "Kernel#sleep"], methods.map(&:full_name))
|
165
|
+
assert_in_delta(0.1, methods[1].total_time, 0.01)
|
166
|
+
assert_equal(0, methods[1].wait_time)
|
167
|
+
assert_in_delta(0.1, methods[1].self_time, 0.01)
|
168
|
+
end
|
169
|
+
|
170
|
+
def test_sleeping_does_not_accumulate_significant_cpu_time
|
171
|
+
result = RubyProf.profile do
|
172
|
+
sleep 0.1
|
173
|
+
end
|
174
|
+
methods = result.threads.first.methods.sort.reverse
|
175
|
+
assert_equal(["MeasureCpuTimeTest#test_sleeping_does_not_accumulate_significant_cpu_time", "Kernel#sleep"], methods.map(&:full_name))
|
176
|
+
assert_in_delta(0, methods[1].total_time, 0.01)
|
177
|
+
assert_equal(0, methods[1].wait_time)
|
178
|
+
assert_in_delta(0, methods[1].self_time, 0.01)
|
179
|
+
end
|
180
|
+
|
181
|
+
def test_waiting_for_threads_does_not_accumulate_cpu_time
|
182
|
+
background_thread = nil
|
183
|
+
result = RubyProf.profile do
|
184
|
+
background_thread = Thread.new{ sleep 0.1 }
|
185
|
+
background_thread.join
|
186
|
+
end
|
187
|
+
# check number of threads
|
188
|
+
assert_equal(2, result.threads.length)
|
189
|
+
fg, bg = result.threads
|
190
|
+
assert(fg.methods.map(&:full_name).include?("Thread#join"))
|
191
|
+
assert(bg.methods.map(&:full_name).include?("Kernel#sleep"))
|
192
|
+
assert_in_delta(0, fg.total_time, 0.01)
|
193
|
+
assert_in_delta(0, bg.total_time, 0.01)
|
194
|
+
end
|
195
|
+
|
196
|
+
def test_waiting_for_threads_does_accumulate_wall_time
|
197
|
+
RubyProf::measure_mode = RubyProf::WALL_TIME
|
198
|
+
background_thread = nil
|
199
|
+
result = RubyProf.profile do
|
200
|
+
background_thread = Thread.new{ sleep 0.1 }
|
201
|
+
background_thread.join
|
202
|
+
end
|
203
|
+
# check number of threads
|
204
|
+
assert_equal(2, result.threads.length)
|
205
|
+
fg, bg = result.threads
|
206
|
+
assert(fg.methods.map(&:full_name).include?("Thread#join"))
|
207
|
+
assert(bg.methods.map(&:full_name).include?("Kernel#sleep"))
|
208
|
+
assert_in_delta(0.1, fg.total_time, 0.01)
|
209
|
+
assert_in_delta(0.1, fg.wait_time, 0.01)
|
210
|
+
assert_in_delta(0.1, bg.total_time, 0.01)
|
211
|
+
end
|
212
|
+
|
153
213
|
end
|