ruby-prof 0.18.0-x64-mingw32
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/CHANGES +500 -0
- data/LICENSE +25 -0
- data/README.rdoc +487 -0
- data/Rakefile +113 -0
- data/bin/ruby-prof +345 -0
- data/bin/ruby-prof-check-trace +45 -0
- data/examples/flat.txt +50 -0
- data/examples/graph.dot +84 -0
- data/examples/graph.html +823 -0
- data/examples/graph.txt +139 -0
- data/examples/multi.flat.txt +23 -0
- data/examples/multi.graph.html +760 -0
- data/examples/multi.grind.dat +114 -0
- data/examples/multi.stack.html +547 -0
- data/examples/stack.html +547 -0
- data/ext/ruby_prof/extconf.rb +68 -0
- data/ext/ruby_prof/rp_call_info.c +425 -0
- data/ext/ruby_prof/rp_call_info.h +53 -0
- data/ext/ruby_prof/rp_measure.c +40 -0
- data/ext/ruby_prof/rp_measure.h +45 -0
- data/ext/ruby_prof/rp_measure_allocations.c +76 -0
- data/ext/ruby_prof/rp_measure_cpu_time.c +136 -0
- data/ext/ruby_prof/rp_measure_gc_runs.c +73 -0
- data/ext/ruby_prof/rp_measure_gc_time.c +60 -0
- data/ext/ruby_prof/rp_measure_memory.c +77 -0
- data/ext/ruby_prof/rp_measure_process_time.c +71 -0
- data/ext/ruby_prof/rp_measure_wall_time.c +45 -0
- data/ext/ruby_prof/rp_method.c +630 -0
- data/ext/ruby_prof/rp_method.h +75 -0
- data/ext/ruby_prof/rp_stack.c +173 -0
- data/ext/ruby_prof/rp_stack.h +63 -0
- data/ext/ruby_prof/rp_thread.c +277 -0
- data/ext/ruby_prof/rp_thread.h +27 -0
- data/ext/ruby_prof/ruby_prof.c +794 -0
- data/ext/ruby_prof/ruby_prof.h +60 -0
- data/ext/ruby_prof/vc/ruby_prof.sln +31 -0
- data/ext/ruby_prof/vc/ruby_prof.vcxproj +141 -0
- data/lib/2.6.3/ruby_prof.so +0 -0
- data/lib/ruby-prof.rb +68 -0
- data/lib/ruby-prof/aggregate_call_info.rb +76 -0
- data/lib/ruby-prof/assets/call_stack_printer.css.html +117 -0
- data/lib/ruby-prof/assets/call_stack_printer.js.html +385 -0
- data/lib/ruby-prof/assets/call_stack_printer.png +0 -0
- data/lib/ruby-prof/call_info.rb +115 -0
- data/lib/ruby-prof/call_info_visitor.rb +40 -0
- data/lib/ruby-prof/compatibility.rb +179 -0
- data/lib/ruby-prof/method_info.rb +121 -0
- data/lib/ruby-prof/printers/abstract_printer.rb +104 -0
- data/lib/ruby-prof/printers/call_info_printer.rb +41 -0
- data/lib/ruby-prof/printers/call_stack_printer.rb +265 -0
- data/lib/ruby-prof/printers/call_tree_printer.rb +143 -0
- data/lib/ruby-prof/printers/dot_printer.rb +132 -0
- data/lib/ruby-prof/printers/flat_printer.rb +70 -0
- data/lib/ruby-prof/printers/flat_printer_with_line_numbers.rb +83 -0
- data/lib/ruby-prof/printers/graph_html_printer.rb +249 -0
- data/lib/ruby-prof/printers/graph_printer.rb +116 -0
- data/lib/ruby-prof/printers/multi_printer.rb +84 -0
- data/lib/ruby-prof/profile.rb +26 -0
- data/lib/ruby-prof/profile/exclude_common_methods.rb +207 -0
- data/lib/ruby-prof/profile/legacy_method_elimination.rb +50 -0
- data/lib/ruby-prof/rack.rb +174 -0
- data/lib/ruby-prof/task.rb +147 -0
- data/lib/ruby-prof/thread.rb +35 -0
- data/lib/ruby-prof/version.rb +3 -0
- data/lib/unprof.rb +10 -0
- data/ruby-prof.gemspec +58 -0
- data/test/abstract_printer_test.rb +53 -0
- data/test/aggregate_test.rb +136 -0
- data/test/basic_test.rb +128 -0
- data/test/block_test.rb +74 -0
- data/test/call_info_test.rb +78 -0
- data/test/call_info_visitor_test.rb +31 -0
- data/test/duplicate_names_test.rb +32 -0
- data/test/dynamic_method_test.rb +55 -0
- data/test/enumerable_test.rb +21 -0
- data/test/exceptions_test.rb +24 -0
- data/test/exclude_methods_test.rb +146 -0
- data/test/exclude_threads_test.rb +53 -0
- data/test/fiber_test.rb +79 -0
- data/test/issue137_test.rb +63 -0
- data/test/line_number_test.rb +80 -0
- data/test/measure_allocations_test.rb +26 -0
- data/test/measure_cpu_time_test.rb +212 -0
- data/test/measure_gc_runs_test.rb +32 -0
- data/test/measure_gc_time_test.rb +36 -0
- data/test/measure_memory_test.rb +33 -0
- data/test/measure_process_time_test.rb +61 -0
- data/test/measure_wall_time_test.rb +255 -0
- data/test/method_elimination_test.rb +84 -0
- data/test/module_test.rb +45 -0
- data/test/multi_printer_test.rb +104 -0
- data/test/no_method_class_test.rb +15 -0
- data/test/pause_resume_test.rb +166 -0
- data/test/prime.rb +54 -0
- data/test/printers_test.rb +275 -0
- data/test/printing_recursive_graph_test.rb +127 -0
- data/test/rack_test.rb +157 -0
- data/test/recursive_test.rb +215 -0
- data/test/singleton_test.rb +38 -0
- data/test/stack_printer_test.rb +77 -0
- data/test/stack_test.rb +138 -0
- data/test/start_stop_test.rb +112 -0
- data/test/test_helper.rb +267 -0
- data/test/thread_test.rb +187 -0
- data/test/unique_call_path_test.rb +202 -0
- data/test/yarv_test.rb +55 -0
- metadata +199 -0
@@ -0,0 +1,112 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
# encoding: UTF-8
|
3
|
+
|
4
|
+
require File.expand_path('../test_helper', __FILE__)
|
5
|
+
|
6
|
+
class StartStopTest < 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 method1
|
13
|
+
RubyProf.start
|
14
|
+
method2
|
15
|
+
end
|
16
|
+
|
17
|
+
def method2
|
18
|
+
method3
|
19
|
+
end
|
20
|
+
|
21
|
+
def method3
|
22
|
+
sleep(2)
|
23
|
+
@result = RubyProf.stop
|
24
|
+
end
|
25
|
+
|
26
|
+
def test_extra_stop_should_raise
|
27
|
+
RubyProf.start
|
28
|
+
assert_raises(RuntimeError) do
|
29
|
+
RubyProf.start
|
30
|
+
end
|
31
|
+
|
32
|
+
assert_raises(RuntimeError) do
|
33
|
+
RubyProf.profile {}
|
34
|
+
end
|
35
|
+
|
36
|
+
RubyProf.stop # ok
|
37
|
+
assert_raises(RuntimeError) do
|
38
|
+
RubyProf.stop
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
|
43
|
+
def test_different_methods
|
44
|
+
method1
|
45
|
+
|
46
|
+
# Ruby prof should be stopped
|
47
|
+
assert_equal(false, RubyProf.running?)
|
48
|
+
|
49
|
+
|
50
|
+
# Length should be 4:
|
51
|
+
# StartStopTest#method1
|
52
|
+
# StartStopTest#method2
|
53
|
+
# StartStopTest#method3
|
54
|
+
# Kernel#sleep
|
55
|
+
|
56
|
+
methods = @result.threads.first.methods.sort.reverse
|
57
|
+
assert_equal(4, methods.length)
|
58
|
+
|
59
|
+
# Check StackTest#test_call_sequence
|
60
|
+
method = methods[0]
|
61
|
+
assert_equal('StartStopTest#method1', method.full_name)
|
62
|
+
assert_equal(1, method.called)
|
63
|
+
assert_in_delta(2, method.total_time, 0.05)
|
64
|
+
assert_in_delta(0, method.wait_time, 0.02)
|
65
|
+
assert_in_delta(0, method.self_time, 0.02)
|
66
|
+
assert_in_delta(2, method.children_time, 0.05)
|
67
|
+
assert_equal(1, method.call_infos.length)
|
68
|
+
|
69
|
+
call_info = method.call_infos[0]
|
70
|
+
assert_equal('StartStopTest#method1', call_info.call_sequence)
|
71
|
+
assert_equal(1, call_info.children.length)
|
72
|
+
|
73
|
+
method = methods[1]
|
74
|
+
assert_equal('StartStopTest#method2', method.full_name)
|
75
|
+
assert_equal(1, method.called)
|
76
|
+
assert_in_delta(2, method.total_time, 0.05)
|
77
|
+
assert_in_delta(0, method.wait_time, 0.02)
|
78
|
+
assert_in_delta(0, method.self_time, 0.02)
|
79
|
+
assert_in_delta(2, method.children_time, 0.05)
|
80
|
+
assert_equal(1, method.call_infos.length)
|
81
|
+
|
82
|
+
call_info = method.call_infos[0]
|
83
|
+
assert_equal('StartStopTest#method1->StartStopTest#method2', call_info.call_sequence)
|
84
|
+
assert_equal(1, call_info.children.length)
|
85
|
+
|
86
|
+
method = methods[2]
|
87
|
+
assert_equal('StartStopTest#method3', method.full_name)
|
88
|
+
assert_equal(1, method.called)
|
89
|
+
assert_in_delta(2, method.total_time, 0.02)
|
90
|
+
assert_in_delta(0, method.wait_time, 0.02)
|
91
|
+
assert_in_delta(0, method.self_time, 0.02)
|
92
|
+
assert_in_delta(2, method.children_time, 0.02)
|
93
|
+
assert_equal(1, method.call_infos.length)
|
94
|
+
|
95
|
+
call_info = method.call_infos[0]
|
96
|
+
assert_equal('StartStopTest#method1->StartStopTest#method2->StartStopTest#method3', call_info.call_sequence)
|
97
|
+
assert_equal(1, call_info.children.length)
|
98
|
+
|
99
|
+
method = methods[3]
|
100
|
+
assert_equal('Kernel#sleep', method.full_name)
|
101
|
+
assert_equal(1, method.called)
|
102
|
+
assert_in_delta(2, method.total_time, 0.02)
|
103
|
+
assert_in_delta(0, method.wait_time, 0.02)
|
104
|
+
assert_in_delta(2, method.self_time, 0.02)
|
105
|
+
assert_in_delta(0, method.children_time, 0.02)
|
106
|
+
assert_equal(1, method.call_infos.length)
|
107
|
+
|
108
|
+
call_info = method.call_infos[0]
|
109
|
+
assert_equal('StartStopTest#method1->StartStopTest#method2->StartStopTest#method3->Kernel#sleep', call_info.call_sequence)
|
110
|
+
assert_equal(0, call_info.children.length)
|
111
|
+
end
|
112
|
+
end
|
data/test/test_helper.rb
ADDED
@@ -0,0 +1,267 @@
|
|
1
|
+
# encoding: UTF-8
|
2
|
+
|
3
|
+
require "rubygems"
|
4
|
+
gem "minitest"
|
5
|
+
|
6
|
+
# To make testing/debugging easier, test within this source tree versus an installed gem
|
7
|
+
dir = File.dirname(__FILE__)
|
8
|
+
root = File.expand_path(File.join(dir, '..'))
|
9
|
+
lib = File.expand_path(File.join(root, 'lib'))
|
10
|
+
ext = File.expand_path(File.join(root, 'ext', 'ruby_prof'))
|
11
|
+
|
12
|
+
$LOAD_PATH << lib
|
13
|
+
$LOAD_PATH << ext
|
14
|
+
|
15
|
+
require 'ruby-prof'
|
16
|
+
|
17
|
+
# stub deprecation warnings
|
18
|
+
module RubyProf
|
19
|
+
module SuppressDeprecationWarnings
|
20
|
+
def deprecation_warning(*args)
|
21
|
+
super if ENV['SHOW_RUBY_PROF_DEPRECATION_WARNINGS'] == '1'
|
22
|
+
end
|
23
|
+
end
|
24
|
+
extend SuppressDeprecationWarnings
|
25
|
+
end
|
26
|
+
|
27
|
+
require 'minitest/autorun'
|
28
|
+
|
29
|
+
class TestCase < Minitest::Test
|
30
|
+
# I know this sucks, but ...
|
31
|
+
def assert_nothing_raised(*)
|
32
|
+
yield
|
33
|
+
end
|
34
|
+
|
35
|
+
def before_setup
|
36
|
+
# make sure to exclude all threads except the one running the test
|
37
|
+
# minitest allocates a thread pool and they would otherwise show
|
38
|
+
# up in the profile data, breaking tests randomly
|
39
|
+
RubyProf.exclude_threads = Thread.list.select{|t| t != Thread.current}
|
40
|
+
end
|
41
|
+
|
42
|
+
def after_teardown
|
43
|
+
# reset exclude threads after testing
|
44
|
+
RubyProf.exclude_threads = nil
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
require File.expand_path('../prime', __FILE__)
|
49
|
+
|
50
|
+
# Some classes used in measurement tests
|
51
|
+
module RubyProf
|
52
|
+
class C1
|
53
|
+
def C1.hello
|
54
|
+
sleep(0.1)
|
55
|
+
end
|
56
|
+
|
57
|
+
def hello
|
58
|
+
sleep(0.2)
|
59
|
+
end
|
60
|
+
end
|
61
|
+
|
62
|
+
module M1
|
63
|
+
def hello
|
64
|
+
sleep(0.3)
|
65
|
+
end
|
66
|
+
end
|
67
|
+
|
68
|
+
class C2
|
69
|
+
include M1
|
70
|
+
extend M1
|
71
|
+
end
|
72
|
+
|
73
|
+
class C3
|
74
|
+
def hello
|
75
|
+
sleep(0.4)
|
76
|
+
end
|
77
|
+
end
|
78
|
+
|
79
|
+
module M4
|
80
|
+
def hello
|
81
|
+
sleep(0.5)
|
82
|
+
end
|
83
|
+
end
|
84
|
+
|
85
|
+
module M5
|
86
|
+
include M4
|
87
|
+
def goodbye
|
88
|
+
hello
|
89
|
+
end
|
90
|
+
end
|
91
|
+
|
92
|
+
class C6
|
93
|
+
include M5
|
94
|
+
def test
|
95
|
+
goodbye
|
96
|
+
end
|
97
|
+
end
|
98
|
+
|
99
|
+
class C7
|
100
|
+
def self.busy_wait
|
101
|
+
t = Time.now.to_f
|
102
|
+
while Time.now.to_f - t < 0.1; end
|
103
|
+
end
|
104
|
+
|
105
|
+
def self.sleep_wait
|
106
|
+
sleep 0.1
|
107
|
+
end
|
108
|
+
|
109
|
+
def busy_wait
|
110
|
+
t = Time.now.to_f
|
111
|
+
while Time.now.to_f - t < 0.2; end
|
112
|
+
end
|
113
|
+
|
114
|
+
def sleep_wait
|
115
|
+
sleep 0.2
|
116
|
+
end
|
117
|
+
end
|
118
|
+
|
119
|
+
module M7
|
120
|
+
def busy_wait
|
121
|
+
t = Time.now.to_f
|
122
|
+
while Time.now.to_f - t < 0.3; end
|
123
|
+
end
|
124
|
+
|
125
|
+
def sleep_wait
|
126
|
+
sleep 0.3
|
127
|
+
end
|
128
|
+
end
|
129
|
+
|
130
|
+
class C8
|
131
|
+
include M7
|
132
|
+
extend M7
|
133
|
+
end
|
134
|
+
|
135
|
+
def self.ruby_major_version
|
136
|
+
match = RUBY_VERSION.match(/(\d)\.(\d)/)
|
137
|
+
return Integer(match[1])
|
138
|
+
end
|
139
|
+
|
140
|
+
def self.ruby_minor_version
|
141
|
+
match = RUBY_VERSION.match(/(\d)\.(\d)/)
|
142
|
+
return Integer(match[2])
|
143
|
+
end
|
144
|
+
|
145
|
+
def self.parent_object
|
146
|
+
if ruby_major_version == 1 && ruby_minor_version == 8
|
147
|
+
Object
|
148
|
+
else
|
149
|
+
BasicObject
|
150
|
+
end
|
151
|
+
end
|
152
|
+
|
153
|
+
def self.ruby_2?
|
154
|
+
ruby_major_version == 2
|
155
|
+
end
|
156
|
+
|
157
|
+
# store printer output in this directory
|
158
|
+
def self.tmpdir
|
159
|
+
path = File.expand_path('../../tmp', __FILE__)
|
160
|
+
unless Dir.exist?(path)
|
161
|
+
Dir.mkdir(path)
|
162
|
+
end
|
163
|
+
path
|
164
|
+
end
|
165
|
+
end
|
166
|
+
|
167
|
+
module MemoryTestHelper
|
168
|
+
def memory_test_helper
|
169
|
+
result = RubyProf.profile {Array.new}
|
170
|
+
total = result.threads.first.methods.inject(0) { |sum, m| sum + m.total_time }
|
171
|
+
assert(total < 1_000_000, 'Total should not have subtract overflow error')
|
172
|
+
total
|
173
|
+
end
|
174
|
+
end
|
175
|
+
|
176
|
+
module PrinterTestHelper
|
177
|
+
Metrics = Struct.new(:name, :total, :self_t, :wait, :child, :calls)
|
178
|
+
class Metrics
|
179
|
+
def pp
|
180
|
+
"%s[total: %.2f, self: %.2f, wait: %.2f, child: %.2f, calls: %s]" %
|
181
|
+
[name, total, self_t, wait, child, calls]
|
182
|
+
end
|
183
|
+
end
|
184
|
+
|
185
|
+
Entry = Struct.new(:total_p, :self_p, :metrics, :parents, :children)
|
186
|
+
class Entry
|
187
|
+
def child(name)
|
188
|
+
children.detect{|m| m.name == name}
|
189
|
+
end
|
190
|
+
|
191
|
+
def parent(name)
|
192
|
+
parents.detect{|m| m.name == name}
|
193
|
+
end
|
194
|
+
|
195
|
+
def pp
|
196
|
+
res = ""
|
197
|
+
res << "NODE (total%%: %.2f, self%%: %.2f) %s\n" % [total_p, self_p, metrics.pp]
|
198
|
+
res << " PARENTS:\n"
|
199
|
+
parents.each {|m| res << " " + m.pp << "\n"}
|
200
|
+
res << " CHILDREN:\n"
|
201
|
+
children.each {|m| res << " " + m.pp << "\n"}
|
202
|
+
res
|
203
|
+
end
|
204
|
+
end
|
205
|
+
|
206
|
+
class MetricsArray < Array
|
207
|
+
def metrics_for(name)
|
208
|
+
detect {|e| e.metrics.name == name}
|
209
|
+
end
|
210
|
+
|
211
|
+
def pp(io = STDOUT)
|
212
|
+
entries = map do |e|
|
213
|
+
begin
|
214
|
+
e.pp
|
215
|
+
rescue
|
216
|
+
puts $!.message + e.inspect
|
217
|
+
""
|
218
|
+
end
|
219
|
+
end
|
220
|
+
io.puts entries.join("--------------------------------------------------\n")
|
221
|
+
end
|
222
|
+
|
223
|
+
def self.parse(str)
|
224
|
+
res = new
|
225
|
+
entry = nil
|
226
|
+
relatives = []
|
227
|
+
state = :preamble
|
228
|
+
|
229
|
+
str.each_line do |l|
|
230
|
+
line = l.chomp.strip
|
231
|
+
if line =~ /-----/
|
232
|
+
if state == :preamble
|
233
|
+
state = :parsing_parents
|
234
|
+
entry = Entry.new
|
235
|
+
elsif state == :parsing_parents
|
236
|
+
entry = Entry.new
|
237
|
+
elsif state == :parsing_children
|
238
|
+
entry.children = relatives
|
239
|
+
res << entry
|
240
|
+
entry = Entry.new
|
241
|
+
relatives = []
|
242
|
+
state = :parsing_parents
|
243
|
+
end
|
244
|
+
elsif line =~ /^\s*$/ || line =~ /indicates recursively called methods/
|
245
|
+
next
|
246
|
+
elsif state != :preamble
|
247
|
+
elements = line.split(/\s+/)
|
248
|
+
method = elements.pop
|
249
|
+
numbers = elements[0..-2].map(&:to_f)
|
250
|
+
metrics = Metrics.new(method, *numbers[-4..-1], elements[-1])
|
251
|
+
if numbers.size == 6
|
252
|
+
entry.metrics = metrics
|
253
|
+
entry.total_p = numbers[0]
|
254
|
+
entry.self_p = numbers[1]
|
255
|
+
entry.parents = relatives
|
256
|
+
entry.children = relatives = []
|
257
|
+
state = :parsing_children
|
258
|
+
res << entry
|
259
|
+
else
|
260
|
+
relatives << metrics
|
261
|
+
end
|
262
|
+
end
|
263
|
+
end
|
264
|
+
res
|
265
|
+
end
|
266
|
+
end
|
267
|
+
end
|
data/test/thread_test.rb
ADDED
@@ -0,0 +1,187 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
# encoding: UTF-8
|
3
|
+
|
4
|
+
require File.expand_path('../test_helper', __FILE__)
|
5
|
+
require 'timeout'
|
6
|
+
require 'benchmark'
|
7
|
+
|
8
|
+
# -- Tests ----
|
9
|
+
class ThreadTest < TestCase
|
10
|
+
def setup
|
11
|
+
# Need to use wall time for this test due to the sleep calls
|
12
|
+
RubyProf::measure_mode = RubyProf::WALL_TIME
|
13
|
+
end
|
14
|
+
|
15
|
+
def test_thread_count
|
16
|
+
RubyProf.start
|
17
|
+
|
18
|
+
thread = Thread.new do
|
19
|
+
sleep(1)
|
20
|
+
end
|
21
|
+
|
22
|
+
thread.join
|
23
|
+
result = RubyProf.stop
|
24
|
+
assert_equal(2, result.threads.length)
|
25
|
+
end
|
26
|
+
|
27
|
+
def test_thread_identity
|
28
|
+
RubyProf.start
|
29
|
+
sleep_thread = Thread.new do
|
30
|
+
sleep(1)
|
31
|
+
end
|
32
|
+
sleep_thread.join
|
33
|
+
result = RubyProf.stop
|
34
|
+
|
35
|
+
thread_ids = result.threads.map {|thread| thread.id}.sort
|
36
|
+
threads = [Thread.current, sleep_thread]
|
37
|
+
assert_equal(2, result.threads.length)
|
38
|
+
|
39
|
+
assert(thread_ids.include?(threads[0].object_id))
|
40
|
+
assert(thread_ids.include?(threads[1].object_id))
|
41
|
+
|
42
|
+
assert_instance_of(Thread, ObjectSpace._id2ref(thread_ids[0]))
|
43
|
+
assert(threads.include?(ObjectSpace._id2ref(thread_ids[0])))
|
44
|
+
|
45
|
+
assert_instance_of(Thread, ObjectSpace._id2ref(thread_ids[1]))
|
46
|
+
assert(threads.include?(ObjectSpace._id2ref(thread_ids[1])))
|
47
|
+
end
|
48
|
+
|
49
|
+
def test_thread_timings
|
50
|
+
RubyProf.start
|
51
|
+
thread = Thread.new do
|
52
|
+
sleep 0
|
53
|
+
# force it to hit thread.join, below, first
|
54
|
+
# thus forcing sleep(1), below, to be counted as (wall) self_time
|
55
|
+
# since we currently count time "in some other thread" as self.wait_time
|
56
|
+
# for whatever reason
|
57
|
+
sleep(1)
|
58
|
+
end
|
59
|
+
thread.join
|
60
|
+
result = RubyProf.stop
|
61
|
+
|
62
|
+
# Check background thread
|
63
|
+
assert_equal(2, result.threads.length)
|
64
|
+
|
65
|
+
rp_thread = result.threads.detect {|t| t.id == thread.object_id}
|
66
|
+
methods = rp_thread.methods.sort.reverse
|
67
|
+
# fails on travis. why?
|
68
|
+
# expected_methods = ["ThreadTest#test_thread_timings", "Kernel#sleep"]
|
69
|
+
# assert_equal(expected_methods, methods.map(&:full_name))
|
70
|
+
|
71
|
+
method = methods[0]
|
72
|
+
assert_equal('ThreadTest#test_thread_timings', method.full_name)
|
73
|
+
assert_equal(1, method.called)
|
74
|
+
assert_in_delta(1, method.total_time, 0.05)
|
75
|
+
assert_in_delta(0, method.self_time, 0.05)
|
76
|
+
assert_in_delta(0, method.wait_time, 0.05)
|
77
|
+
assert_in_delta(1, method.children_time, 0.05)
|
78
|
+
assert_equal(1, method.call_infos.length)
|
79
|
+
call_info = method.call_infos[0]
|
80
|
+
assert_equal('ThreadTest#test_thread_timings', call_info.call_sequence)
|
81
|
+
assert_equal(1, call_info.children.length)
|
82
|
+
|
83
|
+
method = methods[1]
|
84
|
+
assert_equal('Kernel#sleep', method.full_name)
|
85
|
+
assert_equal(2, method.called)
|
86
|
+
assert_in_delta(1, method.total_time, 0.05)
|
87
|
+
assert_in_delta(1.0, method.self_time, 0.05)
|
88
|
+
assert_in_delta(0, method.wait_time, 0.05)
|
89
|
+
assert_in_delta(0, method.children_time, 0.05)
|
90
|
+
|
91
|
+
assert_equal(1, method.call_infos.length)
|
92
|
+
call_info = method.call_infos[0]
|
93
|
+
assert_equal('ThreadTest#test_thread_timings->Kernel#sleep', call_info.call_sequence)
|
94
|
+
assert_equal(0, call_info.children.length)
|
95
|
+
|
96
|
+
# Check foreground thread
|
97
|
+
rp_thread = result.threads.detect {|athread| athread.id == Thread.current.object_id}
|
98
|
+
methods = rp_thread.methods.sort.reverse
|
99
|
+
assert_equal(4, methods.length)
|
100
|
+
methods = methods.sort.reverse
|
101
|
+
|
102
|
+
method = methods[0]
|
103
|
+
assert_equal('ThreadTest#test_thread_timings', method.full_name)
|
104
|
+
# the sub calls to Object#new, when popped,
|
105
|
+
# cause the parent frame to be created for method #test_thread_timings, which means a +1 when it's popped in the end
|
106
|
+
# xxxx a test that shows it the other way, too (never creates parent frame--if that's even possible)
|
107
|
+
assert_equal(1, method.called)
|
108
|
+
assert_in_delta(1, method.total_time, 0.05)
|
109
|
+
assert_in_delta(0, method.self_time, 0.05)
|
110
|
+
assert_in_delta(0, method.wait_time, 0.05)
|
111
|
+
assert_in_delta(1, method.children_time, 0.05)
|
112
|
+
|
113
|
+
assert_equal(1, method.call_infos.length)
|
114
|
+
call_info = method.call_infos[0]
|
115
|
+
assert_equal('ThreadTest#test_thread_timings', call_info.call_sequence)
|
116
|
+
assert_equal(2, call_info.children.length)
|
117
|
+
|
118
|
+
method = methods[1]
|
119
|
+
assert_equal('Thread#join', method.full_name)
|
120
|
+
assert_equal(1, method.called)
|
121
|
+
assert_in_delta(1, method.total_time, 0.05)
|
122
|
+
assert_in_delta(0, method.self_time, 0.05)
|
123
|
+
assert_in_delta(1.0, method.wait_time, 0.05)
|
124
|
+
assert_in_delta(0, method.children_time, 0.05)
|
125
|
+
|
126
|
+
assert_equal(1, method.call_infos.length)
|
127
|
+
call_info = method.call_infos[0]
|
128
|
+
assert_equal('ThreadTest#test_thread_timings->Thread#join', call_info.call_sequence)
|
129
|
+
assert_equal(0, call_info.children.length)
|
130
|
+
|
131
|
+
method = methods[2]
|
132
|
+
assert_equal('<Class::Thread>#new', method.full_name)
|
133
|
+
assert_equal(1, method.called)
|
134
|
+
assert_in_delta(0, method.total_time, 0.05)
|
135
|
+
assert_in_delta(0, method.self_time, 0.05)
|
136
|
+
assert_in_delta(0, method.wait_time, 0.05)
|
137
|
+
assert_in_delta(0, method.children_time, 0.05)
|
138
|
+
|
139
|
+
assert_equal(1, method.call_infos.length)
|
140
|
+
call_info = method.call_infos[0]
|
141
|
+
assert_equal('ThreadTest#test_thread_timings-><Class::Thread>#new', call_info.call_sequence)
|
142
|
+
assert_equal(1, call_info.children.length)
|
143
|
+
|
144
|
+
method = methods[3]
|
145
|
+
assert_equal('Thread#initialize', method.full_name)
|
146
|
+
assert_equal(1, method.called)
|
147
|
+
assert_in_delta(0, method.total_time, 0.05)
|
148
|
+
assert_in_delta(0, method.self_time, 0.05)
|
149
|
+
assert_in_delta(0, method.wait_time, 0.05)
|
150
|
+
assert_in_delta(0, method.children_time, 0.05)
|
151
|
+
|
152
|
+
assert_equal(1, method.call_infos.length)
|
153
|
+
call_info = method.call_infos[0]
|
154
|
+
assert_equal('ThreadTest#test_thread_timings-><Class::Thread>#new->Thread#initialize', call_info.call_sequence)
|
155
|
+
assert_equal(0, call_info.children.length)
|
156
|
+
end
|
157
|
+
|
158
|
+
# useless test: what does it test?
|
159
|
+
def test_thread_back_and_forth
|
160
|
+
result = nil
|
161
|
+
seconds = Benchmark.realtime do
|
162
|
+
result = RubyProf.profile do
|
163
|
+
a = Thread.new { 100_000.times { sleep 0 }}
|
164
|
+
b = Thread.new { 100_000.times { sleep 0 }}
|
165
|
+
a.join
|
166
|
+
b.join
|
167
|
+
end
|
168
|
+
end
|
169
|
+
methods = result.threads.map {|thread| thread.methods}
|
170
|
+
timings = methods.flatten.sort
|
171
|
+
assert(timings[-1].total_time < seconds)
|
172
|
+
end
|
173
|
+
|
174
|
+
# useless test: what does it test?
|
175
|
+
def test_thread
|
176
|
+
RubyProf.profile do
|
177
|
+
begin
|
178
|
+
Timeout::timeout(2) do
|
179
|
+
while true
|
180
|
+
next
|
181
|
+
end
|
182
|
+
end
|
183
|
+
rescue Timeout::Error
|
184
|
+
end
|
185
|
+
end
|
186
|
+
end
|
187
|
+
end
|