ruby-prof 1.4.3 → 1.6.3

Sign up to get free protection for your applications and to get access to all the features.
Files changed (87) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGES +59 -9
  3. data/{README.rdoc → README.md} +2 -2
  4. data/Rakefile +4 -4
  5. data/bin/ruby-prof +100 -87
  6. data/ext/ruby_prof/rp_allocation.c +140 -85
  7. data/ext/ruby_prof/rp_allocation.h +8 -6
  8. data/ext/ruby_prof/rp_call_tree.c +502 -369
  9. data/ext/ruby_prof/rp_call_tree.h +47 -43
  10. data/ext/ruby_prof/rp_call_trees.c +16 -8
  11. data/ext/ruby_prof/rp_measure_allocations.c +10 -13
  12. data/ext/ruby_prof/rp_measure_memory.c +8 -4
  13. data/ext/ruby_prof/rp_measure_process_time.c +7 -6
  14. data/ext/ruby_prof/rp_measurement.c +147 -20
  15. data/ext/ruby_prof/rp_measurement.h +4 -1
  16. data/ext/ruby_prof/rp_method.c +142 -83
  17. data/ext/ruby_prof/rp_method.h +63 -62
  18. data/ext/ruby_prof/rp_profile.c +933 -900
  19. data/ext/ruby_prof/rp_profile.h +1 -0
  20. data/ext/ruby_prof/rp_thread.c +433 -362
  21. data/ext/ruby_prof/rp_thread.h +39 -39
  22. data/ext/ruby_prof/ruby_prof.c +0 -2
  23. data/ext/ruby_prof/ruby_prof.h +8 -0
  24. data/ext/ruby_prof/vc/ruby_prof.vcxproj +11 -8
  25. data/lib/ruby-prof/assets/call_stack_printer.html.erb +2 -1
  26. data/lib/ruby-prof/compatibility.rb +14 -0
  27. data/lib/ruby-prof/method_info.rb +8 -1
  28. data/lib/ruby-prof/printers/abstract_printer.rb +2 -1
  29. data/lib/ruby-prof/printers/call_tree_printer.rb +4 -10
  30. data/lib/ruby-prof/printers/graph_html_printer.rb +1 -1
  31. data/lib/ruby-prof/printers/multi_printer.rb +17 -17
  32. data/lib/ruby-prof/profile.rb +70 -37
  33. data/lib/ruby-prof/rack.rb +31 -21
  34. data/lib/ruby-prof/version.rb +1 -1
  35. data/lib/ruby-prof.rb +1 -1
  36. data/ruby-prof.gemspec +2 -3
  37. data/test/abstract_printer_test.rb +1 -0
  38. data/test/alias_test.rb +97 -106
  39. data/test/call_tree_builder.rb +126 -0
  40. data/test/call_tree_test.rb +94 -0
  41. data/test/call_tree_visitor_test.rb +1 -6
  42. data/test/call_trees_test.rb +6 -6
  43. data/test/{basic_test.rb → compatibility_test.rb} +8 -2
  44. data/test/duplicate_names_test.rb +5 -5
  45. data/test/dynamic_method_test.rb +24 -15
  46. data/test/enumerable_test.rb +1 -1
  47. data/test/exceptions_test.rb +2 -2
  48. data/test/exclude_methods_test.rb +3 -8
  49. data/test/exclude_threads_test.rb +4 -9
  50. data/test/fiber_test.rb +74 -8
  51. data/test/gc_test.rb +11 -9
  52. data/test/inverse_call_tree_test.rb +33 -34
  53. data/test/line_number_test.rb +37 -61
  54. data/test/marshal_test.rb +16 -3
  55. data/test/measure_allocations.rb +1 -5
  56. data/test/measure_allocations_test.rb +642 -357
  57. data/test/{measure_memory_trace_test.rb → measure_memory_test.rb} +180 -616
  58. data/test/measure_process_time_test.rb +1566 -741
  59. data/test/measure_wall_time_test.rb +179 -193
  60. data/test/measurement_test.rb +82 -0
  61. data/test/merge_test.rb +146 -0
  62. data/test/method_info_test.rb +95 -0
  63. data/test/multi_printer_test.rb +0 -5
  64. data/test/no_method_class_test.rb +1 -1
  65. data/test/pause_resume_test.rb +12 -16
  66. data/test/printer_call_stack_test.rb +2 -2
  67. data/test/printer_call_tree_test.rb +4 -4
  68. data/test/printer_flat_test.rb +1 -1
  69. data/test/printer_graph_html_test.rb +2 -2
  70. data/test/printer_graph_test.rb +2 -2
  71. data/test/printers_test.rb +14 -20
  72. data/test/printing_recursive_graph_test.rb +2 -2
  73. data/test/profile_test.rb +85 -0
  74. data/test/recursive_test.rb +374 -155
  75. data/test/scheduler.rb +363 -0
  76. data/test/singleton_test.rb +1 -1
  77. data/test/stack_printer_test.rb +5 -8
  78. data/test/start_stop_test.rb +11 -14
  79. data/test/test_helper.rb +11 -8
  80. data/test/thread_test.rb +106 -15
  81. data/test/unique_call_path_test.rb +28 -12
  82. data/test/yarv_test.rb +11 -7
  83. metadata +17 -29
  84. data/ext/ruby_prof/rp_aggregate_call_tree.c +0 -59
  85. data/ext/ruby_prof/rp_aggregate_call_tree.h +0 -13
  86. data/test/measure_allocations_trace_test.rb +0 -375
  87. data/test/temp.rb +0 -20
data/test/scheduler.rb ADDED
@@ -0,0 +1,363 @@
1
+ # frozen_string_literal: true
2
+
3
+ # This is an example and simplified scheduler for test purposes.
4
+ # It is not efficient for a large number of file descriptors as it uses IO.select().
5
+ # Production Fiber schedulers should use epoll/kqueue/etc.
6
+
7
+ require 'fiber'
8
+ require 'socket'
9
+
10
+ begin
11
+ require 'io/nonblock'
12
+ rescue LoadError
13
+ # Ignore.
14
+ end
15
+
16
+ class Scheduler
17
+ experimental = Warning[:experimental]
18
+ begin
19
+ Warning[:experimental] = false
20
+ IO::Buffer.new(0)
21
+ ensure
22
+ Warning[:experimental] = experimental
23
+ end
24
+
25
+ def initialize
26
+ @readable = {}
27
+ @writable = {}
28
+ @waiting = {}
29
+
30
+ @closed = false
31
+
32
+ @lock = Thread::Mutex.new
33
+ @blocking = Hash.new.compare_by_identity
34
+ @ready = []
35
+
36
+ @urgent = IO.pipe
37
+ end
38
+
39
+ attr :readable
40
+ attr :writable
41
+ attr :waiting
42
+
43
+ def next_timeout
44
+ _fiber, timeout = @waiting.min_by{|key, value| value}
45
+
46
+ if timeout
47
+ offset = timeout - current_time
48
+
49
+ if offset < 0
50
+ return 0
51
+ else
52
+ return offset
53
+ end
54
+ end
55
+ end
56
+
57
+ def run
58
+ # $stderr.puts [__method__, Fiber.current].inspect
59
+
60
+ while @readable.any? or @writable.any? or @waiting.any? or @blocking.any?
61
+ # Can only handle file descriptors up to 1024...
62
+ readable, writable = IO.select(@readable.keys + [@urgent.first], @writable.keys, [], next_timeout)
63
+
64
+ # puts "readable: #{readable}" if readable&.any?
65
+ # puts "writable: #{writable}" if writable&.any?
66
+
67
+ selected = {}
68
+
69
+ readable&.each do |io|
70
+ if fiber = @readable.delete(io)
71
+ @writable.delete(io) if @writable[io] == fiber
72
+ selected[fiber] = IO::READABLE
73
+ elsif io == @urgent.first
74
+ @urgent.first.read_nonblock(1024)
75
+ end
76
+ end
77
+
78
+ writable&.each do |io|
79
+ if fiber = @writable.delete(io)
80
+ @readable.delete(io) if @readable[io] == fiber
81
+ selected[fiber] = selected.fetch(fiber, 0) | IO::WRITABLE
82
+ end
83
+ end
84
+
85
+ selected.each do |fiber, events|
86
+ fiber.resume(events)
87
+ end
88
+
89
+ if @waiting.any?
90
+ time = current_time
91
+ waiting, @waiting = @waiting, {}
92
+
93
+ waiting.each do |fiber, timeout|
94
+ if fiber.alive?
95
+ if timeout <= time
96
+ fiber.resume
97
+ else
98
+ @waiting[fiber] = timeout
99
+ end
100
+ end
101
+ end
102
+ end
103
+
104
+ if @ready.any?
105
+ ready = nil
106
+
107
+ @lock.synchronize do
108
+ ready, @ready = @ready, []
109
+ end
110
+
111
+ ready.each do |fiber|
112
+ fiber.resume
113
+ end
114
+ end
115
+ end
116
+ end
117
+
118
+ def scheduler_close
119
+ close(true)
120
+ end
121
+
122
+ def close(internal = false)
123
+ # $stderr.puts [__method__, Fiber.current].inspect
124
+
125
+ unless internal
126
+ if Fiber.scheduler == self
127
+ return Fiber.set_scheduler(nil)
128
+ end
129
+ end
130
+
131
+ if @closed
132
+ raise "Scheduler already closed!"
133
+ end
134
+
135
+ self.run
136
+ ensure
137
+ if @urgent
138
+ @urgent.each(&:close)
139
+ @urgent = nil
140
+ end
141
+
142
+ @closed ||= true
143
+
144
+ # We freeze to detect any unintended modifications after the scheduler is closed:
145
+ self.freeze
146
+ end
147
+
148
+ def closed?
149
+ @closed
150
+ end
151
+
152
+ def current_time
153
+ Process.clock_gettime(Process::CLOCK_MONOTONIC)
154
+ end
155
+
156
+ def timeout_after(duration, klass, message, &block)
157
+ fiber = Fiber.current
158
+
159
+ self.fiber do
160
+ sleep(duration)
161
+
162
+ if fiber&.alive?
163
+ fiber.raise(klass, message)
164
+ end
165
+ end
166
+
167
+ begin
168
+ yield(duration)
169
+ ensure
170
+ fiber = nil
171
+ end
172
+ end
173
+
174
+ def process_wait(pid, flags)
175
+ # $stderr.puts [__method__, pid, flags, Fiber.current].inspect
176
+
177
+ # This is a very simple way to implement a non-blocking wait:
178
+ Thread.new do
179
+ Process::Status.wait(pid, flags)
180
+ end.value
181
+ end
182
+
183
+ def io_wait(io, events, duration)
184
+ # $stderr.puts [__method__, io, events, duration, Fiber.current].inspect
185
+
186
+ unless (events & IO::READABLE).zero?
187
+ @readable[io] = Fiber.current
188
+ end
189
+
190
+ unless (events & IO::WRITABLE).zero?
191
+ @writable[io] = Fiber.current
192
+ end
193
+
194
+ Fiber.yield
195
+ ensure
196
+ @readable.delete(io)
197
+ @writable.delete(io)
198
+ end
199
+
200
+ def io_select(...)
201
+ # Emulate the operation using a non-blocking thread:
202
+ Thread.new do
203
+ IO.select(...)
204
+ end.value
205
+ end
206
+
207
+ # Used for Kernel#sleep and Thread::Mutex#sleep
208
+ def kernel_sleep(duration = nil)
209
+ # $stderr.puts [__method__, duration, Fiber.current].inspect
210
+
211
+ self.block(:sleep, duration)
212
+
213
+ return true
214
+ end
215
+
216
+ # Used when blocking on synchronization (Thread::Mutex#lock,
217
+ # Thread::Queue#pop, Thread::SizedQueue#push, ...)
218
+ def block(blocker, timeout = nil)
219
+ # $stderr.puts [__method__, blocker, timeout].inspect
220
+
221
+ fiber = Fiber.current
222
+
223
+ if timeout
224
+ @waiting[fiber] = current_time + timeout
225
+ begin
226
+ Fiber.yield
227
+ ensure
228
+ # Remove from @waiting in the case #unblock was called before the timeout expired:
229
+ @waiting.delete(fiber)
230
+ end
231
+ else
232
+ @blocking[fiber] = true
233
+ begin
234
+ Fiber.yield
235
+ ensure
236
+ @blocking.delete(fiber)
237
+ end
238
+ end
239
+ end
240
+
241
+ # Used when synchronization wakes up a previously-blocked fiber
242
+ # (Thread::Mutex#unlock, Thread::Queue#push, ...).
243
+ # This might be called from another thread.
244
+ def unblock(blocker, fiber)
245
+ # $stderr.puts [__method__, blocker, fiber].inspect
246
+ # $stderr.puts blocker.backtrace.inspect
247
+ # $stderr.puts fiber.backtrace.inspect
248
+
249
+ @lock.synchronize do
250
+ @ready << fiber
251
+ end
252
+
253
+ io = @urgent.last
254
+ io.write_nonblock('.')
255
+ end
256
+
257
+ def fiber(&block)
258
+ fiber = Fiber.new(blocking: false, &block)
259
+
260
+ fiber.resume
261
+
262
+ return fiber
263
+ end
264
+
265
+ def address_resolve(hostname)
266
+ Thread.new do
267
+ Addrinfo.getaddrinfo(hostname, nil).map(&:ip_address).uniq
268
+ end.value
269
+ end
270
+ end
271
+
272
+ class IOBufferScheduler < Scheduler
273
+ EAGAIN = -Errno::EAGAIN::Errno
274
+
275
+ def io_read(io, buffer, length, offset)
276
+ total = 0
277
+ io.nonblock = true
278
+
279
+ while true
280
+ maximum_size = buffer.size - offset
281
+ result = blocking{buffer.read(io, maximum_size, offset)}
282
+
283
+ if result > 0
284
+ total += result
285
+ offset += result
286
+ break if total >= length
287
+ elsif result == 0
288
+ break
289
+ elsif result == EAGAIN
290
+ if length > 0
291
+ self.io_wait(io, IO::READABLE, nil)
292
+ else
293
+ return result
294
+ end
295
+ elsif result < 0
296
+ return result
297
+ end
298
+ end
299
+
300
+ return total
301
+ end
302
+
303
+ def io_write(io, buffer, length, offset)
304
+ total = 0
305
+ io.nonblock = true
306
+
307
+ while true
308
+ maximum_size = buffer.size - offset
309
+ result = blocking{buffer.write(io, maximum_size, offset)}
310
+
311
+ if result > 0
312
+ total += result
313
+ offset += result
314
+ break if total >= length
315
+ elsif result == 0
316
+ break
317
+ elsif result == EAGAIN
318
+ if length > 0
319
+ self.io_wait(io, IO::WRITABLE, nil)
320
+ else
321
+ return result
322
+ end
323
+ elsif result < 0
324
+ return result
325
+ end
326
+ end
327
+
328
+ return total
329
+ end
330
+
331
+ def blocking(&block)
332
+ Fiber.blocking(&block)
333
+ end
334
+ end
335
+
336
+ class BrokenUnblockScheduler < Scheduler
337
+ def unblock(blocker, fiber)
338
+ super
339
+
340
+ raise "Broken unblock!"
341
+ end
342
+ end
343
+
344
+ class SleepingUnblockScheduler < Scheduler
345
+ # This method is invoked when the thread is exiting.
346
+ def unblock(blocker, fiber)
347
+ super
348
+
349
+ # This changes the current thread state to `THREAD_RUNNING` which causes `thread_join_sleep` to hang.
350
+ sleep(0.1)
351
+ end
352
+ end
353
+
354
+ class SleepingBlockingScheduler < Scheduler
355
+ def kernel_sleep(duration = nil)
356
+ # Deliberaly sleep in a blocking state which can trigger a deadlock if the implementation is not correct.
357
+ Fiber.blocking{sleep 0.0001}
358
+
359
+ self.block(:sleep, duration)
360
+
361
+ return true
362
+ end
363
+ end
@@ -26,7 +26,7 @@ end
26
26
 
27
27
  class SingletonTest < TestCase
28
28
  def test_singleton
29
- result = RubyProf.profile do
29
+ result = RubyProf::Profile.profile do
30
30
  a = A.new
31
31
  a << :first_thing
32
32
  assert_equal(1, a.as.size)
@@ -27,16 +27,12 @@ class STPT
27
27
  end
28
28
 
29
29
  class StackPrinterTest < TestCase
30
- def setup
31
- # Need to use wall time for this test due to the sleep calls
32
- RubyProf::measure_mode = RubyProf::WALL_TIME
33
- end
34
-
35
30
  def test_stack_can_be_printed
36
31
  start_time = Time.now
37
- RubyProf.start
38
- 5.times{STPT.new.a}
39
- result = RubyProf.stop
32
+ result = RubyProf::Profile.profile(measure_mode: RubyProf::WALL_TIME) do
33
+ 5.times{STPT.new.a}
34
+ end
35
+
40
36
  end_time = Time.now
41
37
  expected_time = end_time - start_time
42
38
 
@@ -50,6 +46,7 @@ class StackPrinterTest < TestCase
50
46
  end
51
47
 
52
48
  private
49
+
53
50
  def print(result)
54
51
  test = caller.first =~ /in `(.*)'/ ? $1 : "test"
55
52
  testfile_name = "#{Dir.tmpdir}/ruby_prof_#{test}.html"
@@ -5,37 +5,34 @@ require File.expand_path('../test_helper', __FILE__)
5
5
 
6
6
  class StartStopTest < TestCase
7
7
  def setup
8
+ super
8
9
  # Need to use wall time for this test due to the sleep calls
9
- RubyProf::measure_mode = RubyProf::WALL_TIME
10
+ @profile = RubyProf::Profile.new(measure_mode: RubyProf::WALL_TIME)
10
11
  end
11
12
 
12
13
  def method1
13
- RubyProf.start
14
- method2
14
+ @profile.start
15
+ method2
15
16
  end
16
17
 
17
18
  def method2
18
- method3
19
+ method3
19
20
  end
20
21
 
21
22
  def method3
22
23
  sleep(2)
23
- @result = RubyProf.stop
24
+ @result = @profile.stop
24
25
  end
25
26
 
26
27
  def test_extra_stop_should_raise
27
- RubyProf.start
28
+ @profile.start
28
29
  assert_raises(RuntimeError) do
29
- RubyProf.start
30
+ @profile.start
30
31
  end
31
32
 
33
+ @profile.stop # ok
32
34
  assert_raises(RuntimeError) do
33
- RubyProf.profile {}
34
- end
35
-
36
- RubyProf.stop # ok
37
- assert_raises(RuntimeError) do
38
- RubyProf.stop
35
+ @profile.stop
39
36
  end
40
37
  end
41
38
 
@@ -43,7 +40,7 @@ class StartStopTest < TestCase
43
40
  method1
44
41
 
45
42
  # Ruby prof should be stopped
46
- assert_equal(false, RubyProf.running?)
43
+ assert_equal(false, @profile.running?)
47
44
 
48
45
  methods = @result.threads.first.methods.sort.reverse
49
46
  assert_equal(4, methods.length)
data/test/test_helper.rb CHANGED
@@ -1,17 +1,20 @@
1
1
  # encoding: UTF-8
2
2
 
3
+ # To make testing/debugging easier test within this source tree versus an installed gem
3
4
  require 'bundler/setup'
4
- require 'minitest/autorun'
5
5
 
6
- # Disable minitest parallel tests. The problem is the thread switching will change test results
7
- # (self vs wait time)
8
- if Gem::Version.new(Minitest::VERSION) > Gem::Version.new('5.11.3')
9
- ENV["MT_CPU"] = "0" # Newer versions minitest
10
- else
11
- ENV["N"] = "0" # Older versions of minitest
12
- end
6
+ # Add ext directory to load path to make it easier to test locally built extensions
7
+ ext_path = File.expand_path(File.join(__dir__, '..', 'ext', 'ruby_prof'))
8
+ $LOAD_PATH.unshift(File.expand_path(ext_path))
13
9
 
10
+ # Now load code
14
11
  require 'ruby-prof'
15
12
 
13
+ # Disable minitest parallel tests. The problem is the thread switching will change test results
14
+ # (self vs wait time)
15
+ ENV["MT_CPU"] = "0" # New versions of minitest
16
+ ENV["N"] = "0" # Older versions of minitest
17
+
18
+ require 'minitest/autorun'
16
19
  class TestCase < Minitest::Test
17
20
  end
data/test/thread_test.rb CHANGED
@@ -4,33 +4,122 @@
4
4
  require File.expand_path('../test_helper', __FILE__)
5
5
  require 'timeout'
6
6
  require 'benchmark'
7
+ require_relative './call_tree_builder'
7
8
 
8
9
  # -- Tests ----
9
10
  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
11
+ def test_initialize
12
+ method_info = RubyProf::MethodInfo.new(Array, :size)
13
+ call_tree = RubyProf::CallTree.new(method_info)
14
+ thread = RubyProf::Thread.new(call_tree, Thread.current, Fiber.current)
15
+
16
+ assert_equal(call_tree, thread.call_tree)
17
+ assert(thread)
18
+ assert(thread.id)
19
+ assert(thread.fiber_id)
20
+
21
+ assert_equal(1, thread.methods.size)
22
+ assert_same(method_info, thread.methods[0])
23
+ end
24
+
25
+ def test_merge
26
+ call_tree_1 = create_call_tree_1
27
+ thread_1 = RubyProf::Thread.new(call_tree_1, Thread.current, Fiber.current)
28
+ assert_equal(6, thread_1.methods.size)
29
+
30
+ call_tree_2 = create_call_tree_2
31
+ thread_2 = RubyProf::Thread.new(call_tree_2, Thread.current, Fiber.current)
32
+ assert_equal(6, thread_2.methods.size)
33
+
34
+ thread_1.merge!(thread_2)
35
+ assert_equal(7, thread_1.methods.size)
36
+
37
+ # Method times
38
+ assert_in_delta(11.6, thread_1.methods[0].total_time, 0.00001) # root
39
+ assert_in_delta(4.1, thread_1.methods[1].total_time, 0.00001) # a
40
+ assert_in_delta(1.5, thread_1.methods[2].total_time, 0.00001) # aa
41
+ assert_in_delta(2.6, thread_1.methods[3].total_time, 0.00001) # ab
42
+ assert_in_delta(7.5, thread_1.methods[4].total_time, 0.00001) # b
43
+ assert_in_delta(6.6, thread_1.methods[5].total_time, 0.00001) # bb
44
+ assert_in_delta(0.9, thread_1.methods[6].total_time, 0.00001) # ba
45
+
46
+ # Root
47
+ call_tree = call_tree_1
48
+ assert_equal(:root, call_tree.target.method_name)
49
+ assert_in_delta(11.6, call_tree.total_time, 0.00001)
50
+ assert_in_delta(0, call_tree.self_time, 0.00001)
51
+ assert_in_delta(0.0, call_tree.wait_time, 0.00001)
52
+ assert_in_delta(11.6, call_tree.children_time, 0.00001)
53
+
54
+ # a
55
+ call_tree = call_tree_1.children[0]
56
+ assert_equal(:a, call_tree.target.method_name)
57
+ assert_in_delta(4.1, call_tree.total_time, 0.00001)
58
+ assert_in_delta(0, call_tree.self_time, 0.00001)
59
+ assert_in_delta(0.0, call_tree.wait_time, 0.00001)
60
+ assert_in_delta(4.1, call_tree.children_time, 0.00001)
61
+
62
+ # aa
63
+ call_tree = call_tree_1.children[0].children[0]
64
+ assert_equal(:aa, call_tree.target.method_name)
65
+ assert_in_delta(1.5, call_tree.total_time, 0.00001)
66
+ assert_in_delta(1.5, call_tree.self_time, 0.00001)
67
+ assert_in_delta(0.0, call_tree.wait_time, 0.00001)
68
+ assert_in_delta(0.0, call_tree.children_time, 0.00001)
69
+
70
+ # ab
71
+ call_tree = call_tree_1.children[0].children[1]
72
+ assert_equal(:ab, call_tree.target.method_name)
73
+ assert_in_delta(2.6, call_tree.total_time, 0.00001)
74
+ assert_in_delta(2.6, call_tree.self_time, 0.00001)
75
+ assert_in_delta(0.0, call_tree.wait_time, 0.00001)
76
+ assert_in_delta(0.0, call_tree.children_time, 0.00001)
77
+
78
+ # # b
79
+ # call_tree = call_tree_1.children[1]
80
+ # assert_equal(:b, call_tree.target.method_name)
81
+ # assert_in_delta(7.5, call_tree.total_time, 0.00001)
82
+ # assert_in_delta(0, call_tree.self_time, 0.00001)
83
+ # assert_in_delta(0.0, call_tree.wait_time, 0.00001)
84
+ # assert_in_delta(7.5, call_tree.children_time, 0.00001)
85
+
86
+ # bb
87
+ # call_tree = call_tree_1.children[1].children[0]
88
+ # assert_equal(:bb, call_tree.target.method_name)
89
+ # assert_in_delta(6.6, call_tree.total_time, 0.00001)
90
+ # assert_in_delta(6.6, call_tree.self_time, 0.00001)
91
+ # assert_in_delta(0.0, call_tree.wait_time, 0.00001)
92
+ # assert_in_delta(0.0, call_tree.children_time, 0.00001)
93
+
94
+ # ba
95
+ call_tree = call_tree_1.children[1].children[1]
96
+ assert_equal(:ba, call_tree.target.method_name)
97
+ assert_in_delta(0.9, call_tree.total_time, 0.00001)
98
+ assert_in_delta(0.7, call_tree.self_time, 0.00001)
99
+ assert_in_delta(0.2, call_tree.wait_time, 0.00001)
100
+ assert_in_delta(0.0, call_tree.children_time, 0.00001)
13
101
  end
14
102
 
15
103
  def test_thread_count
16
- RubyProf.start
104
+ result = RubyProf::Profile.profile(measure_mode: RubyProf::WALL_TIME) do
105
+ thread = Thread.new do
106
+ sleep(1)
107
+ end
17
108
 
18
- thread = Thread.new do
19
- sleep(1)
109
+ thread.join
20
110
  end
21
-
22
- thread.join
23
- result = RubyProf.stop
24
111
  assert_equal(2, result.threads.length)
25
112
  end
26
113
 
27
114
  def test_thread_identity
28
- RubyProf.start
115
+ profile = RubyProf::Profile.new(measure_mode: RubyProf::WALL_TIME)
116
+ profile.start
117
+
29
118
  sleep_thread = Thread.new do
30
119
  sleep(1)
31
120
  end
32
121
  sleep_thread.join
33
- result = RubyProf.stop
122
+ result = profile.stop
34
123
 
35
124
  thread_ids = result.threads.map {|thread| thread.id}.sort
36
125
  threads = [Thread.current, sleep_thread]
@@ -47,7 +136,9 @@ class ThreadTest < TestCase
47
136
  end
48
137
 
49
138
  def test_thread_timings
50
- RubyProf.start
139
+ profile = RubyProf::Profile.new(measure_mode: RubyProf::WALL_TIME)
140
+ profile.start
141
+
51
142
  thread = Thread.new do
52
143
  sleep 0
53
144
  # force it to hit thread.join, below, first
@@ -57,7 +148,7 @@ class ThreadTest < TestCase
57
148
  sleep(1)
58
149
  end
59
150
  thread.join
60
- result = RubyProf.stop
151
+ result = profile.stop
61
152
 
62
153
  # Check background thread
63
154
  assert_equal(2, result.threads.length)
@@ -71,10 +162,10 @@ class ThreadTest < TestCase
71
162
  method = methods[0]
72
163
  assert_equal('ThreadTest#test_thread_timings', method.full_name)
73
164
  assert_equal(1, method.called)
74
- assert_in_delta(1, method.total_time, 0.05)
165
+ assert_in_delta(1, method.total_time, 0.1)
75
166
  assert_in_delta(0, method.self_time, 0.05)
76
167
  assert_in_delta(0, method.wait_time, 0.05)
77
- assert_in_delta(1, method.children_time, 0.05)
168
+ assert_in_delta(1, method.children_time, 0.1)
78
169
  assert_equal(0, method.call_trees.callers.length)
79
170
 
80
171
  method = methods[1]