ruby-prof 1.4.5 → 1.5.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,82 @@
1
+ # frozen_string_literal: true
2
+
3
+ require File.expand_path('../test_helper', __FILE__)
4
+
5
+ class MeasurementTest < Minitest::Test
6
+ def test_initialize
7
+ measurement = RubyProf::Measurement.new(3.3, 2.2, 1.1, 4)
8
+ assert_equal(3.3, measurement.total_time)
9
+ assert_equal(2.2, measurement.self_time)
10
+ assert_equal(1.1, measurement.wait_time)
11
+ assert_equal(4, measurement.called)
12
+ end
13
+
14
+ def test_clone
15
+ measurement_1 = RubyProf::Measurement.new(3.3, 2.2, 1.1, 4)
16
+ measurement_2 = measurement_1.clone
17
+
18
+ refute(measurement_1.equal?(measurement_2))
19
+ refute(measurement_1.eql?(measurement_2))
20
+ refute(measurement_1 == measurement_2)
21
+
22
+ assert_equal(measurement_1.total_time, measurement_2.total_time)
23
+ assert_equal(measurement_1.self_time, measurement_2.self_time)
24
+ assert_equal(measurement_1.wait_time, measurement_2.wait_time)
25
+ assert_equal(measurement_1.called, measurement_2.called)
26
+ end
27
+
28
+ def test_dup
29
+ measurement_1 = RubyProf::Measurement.new(3.3, 2.2, 1.1, 4)
30
+ measurement_2 = measurement_1.dup
31
+
32
+ refute(measurement_1.equal?(measurement_2))
33
+ refute(measurement_1.eql?(measurement_2))
34
+ refute(measurement_1 == measurement_2)
35
+
36
+ assert_equal(measurement_1.total_time, measurement_2.total_time)
37
+ assert_equal(measurement_1.self_time, measurement_2.self_time)
38
+ assert_equal(measurement_1.wait_time, measurement_2.wait_time)
39
+ assert_equal(measurement_1.called, measurement_2.called)
40
+ end
41
+
42
+ def test_merge!
43
+ measurement1 = RubyProf::Measurement.new(3.3, 2.2, 1.1, 4)
44
+ measurement2 = RubyProf::Measurement.new(3, 2, 1, 3)
45
+
46
+ measurement1.merge!(measurement2)
47
+
48
+ assert_equal(6.3, measurement1.total_time)
49
+ assert_equal(4.2, measurement1.self_time)
50
+ assert_equal(2.1, measurement1.wait_time)
51
+ assert_equal(7, measurement1.called)
52
+
53
+ assert_equal(3, measurement2.total_time)
54
+ assert_equal(2, measurement2.self_time)
55
+ assert_equal(1, measurement2.wait_time)
56
+ assert_equal(3, measurement2.called)
57
+ end
58
+
59
+ def test_set_total_time
60
+ measurement = RubyProf::Measurement.new(4, 3, 1, 1)
61
+ measurement.total_time = 5.1
62
+ assert_equal(5.1, measurement.total_time)
63
+ end
64
+
65
+ def test_set_self_time
66
+ measurement = RubyProf::Measurement.new(4, 3, 1, 1)
67
+ measurement.self_time = 3.1
68
+ assert_equal(3.1, measurement.self_time)
69
+ end
70
+
71
+ def test_set_wait_time
72
+ measurement = RubyProf::Measurement.new(4, 3, 1, 1)
73
+ measurement.wait_time = 1.1
74
+ assert_equal(1.1, measurement.wait_time)
75
+ end
76
+
77
+ def test_set_called
78
+ measurement = RubyProf::Measurement.new(4, 3, 1, 1)
79
+ measurement.called = 2
80
+ assert_equal(2, measurement.called)
81
+ end
82
+ end
@@ -0,0 +1,95 @@
1
+ # frozen_string_literal: true
2
+
3
+ require File.expand_path('../test_helper', __FILE__)
4
+ require 'base64'
5
+
6
+ class MethodInfoTest < Minitest::Test
7
+ def test_initialize
8
+ method_info = RubyProf::MethodInfo.new(Base64, :encode64)
9
+ assert_equal("Base64", method_info.klass_name)
10
+ assert_equal(:encode64, method_info.method_name)
11
+ assert_equal("Base64#encode64", method_info.full_name)
12
+ assert_equal(0, method_info.klass_flags)
13
+ assert_match(/base64\.rb/, method_info.source_file)
14
+ assert_kind_of(Integer, method_info.line)
15
+ refute(method_info.recursive?)
16
+
17
+ assert_kind_of(RubyProf::Measurement, method_info.measurement)
18
+ assert_kind_of(RubyProf::CallTrees, method_info.call_trees)
19
+ assert_empty(method_info.allocations)
20
+ end
21
+
22
+ def test_initialize_nil_klass
23
+ error = assert_raises(NoMethodError) do
24
+ RubyProf::MethodInfo.new(nil, nil)
25
+ end
26
+ assert_match(/undefined method `instance_method' for nil:NilClass/, error.message)
27
+ end
28
+
29
+ def test_initialize_nil_method_name
30
+ error = assert_raises(TypeError) do
31
+ RubyProf::MethodInfo.new(Base64, nil)
32
+ end
33
+ assert_equal("nil is not a symbol nor a string", error.to_s)
34
+ end
35
+
36
+ def test_initialize_unknown_location
37
+ method_info = RubyProf::MethodInfo.new(Array, :size)
38
+ assert_equal('Array', method_info.klass_name)
39
+ assert_equal(:size, method_info.method_name)
40
+ assert_nil(method_info.source_file)
41
+ assert_equal(0, method_info.line)
42
+ end
43
+
44
+ def test_measurement
45
+ method_info = RubyProf::MethodInfo.new(Base64, :encode64)
46
+ assert_equal(0, method_info.total_time)
47
+ assert_equal(0, method_info.self_time)
48
+ assert_equal(0, method_info.wait_time)
49
+ assert_equal(0, method_info.children_time)
50
+ assert_equal(0, method_info.called)
51
+ end
52
+
53
+ def test_compare
54
+ method_info_1 = RubyProf::MethodInfo.new(Base64, :encode64)
55
+ method_info_2 = RubyProf::MethodInfo.new(Base64, :encode64)
56
+ assert_equal(0, method_info_1 <=> method_info_2)
57
+
58
+ method_info_1 = RubyProf::MethodInfo.new(Base64, :decode64)
59
+ method_info_2 = RubyProf::MethodInfo.new(Base64, :encode64)
60
+ assert_equal(-1, method_info_1 <=> method_info_2)
61
+
62
+ method_info_1 = RubyProf::MethodInfo.new(Base64, :encode64)
63
+ method_info_2 = RubyProf::MethodInfo.new(Base64, :decode64)
64
+ assert_equal(1, method_info_1 <=> method_info_2)
65
+ end
66
+
67
+ def test_eql?
68
+ method_info_1 = RubyProf::MethodInfo.new(Base64, :encode64)
69
+ method_info_2 = RubyProf::MethodInfo.new(Base64, :encode64)
70
+ assert(method_info_1.eql?(method_info_2))
71
+ end
72
+
73
+ def test_equal?
74
+ method_info_1 = RubyProf::MethodInfo.new(Base64, :encode64)
75
+ method_info_2 = RubyProf::MethodInfo.new(Base64, :encode64)
76
+ refute(method_info_1.equal?(method_info_2))
77
+ end
78
+
79
+ def test_equality
80
+ method_info_1 = RubyProf::MethodInfo.new(Base64, :encode64)
81
+ method_info_2 = RubyProf::MethodInfo.new(Base64, :encode64)
82
+ assert(method_info_1 == method_info_2)
83
+ end
84
+
85
+ def test_hash
86
+ method_info_1 = RubyProf::MethodInfo.new(Base64, :encode64)
87
+ method_info_2 = RubyProf::MethodInfo.new(Base64, :encode64)
88
+ assert_equal(method_info_1.hash, method_info_2.hash)
89
+ end
90
+
91
+ def test_to_s
92
+ method_info = RubyProf::MethodInfo.new(Base64, :encode64)
93
+ assert_equal("Base64#encode64 (c: 0, tt: 0.0, st: 0.0, wt: 0.0, ct: 0.0)", method_info.to_s)
94
+ end
95
+ end
data/test/profile_test.rb CHANGED
@@ -2,6 +2,7 @@
2
2
  # encoding: UTF-8
3
3
 
4
4
  require File.expand_path('../test_helper', __FILE__)
5
+ require_relative './call_tree_builder'
5
6
 
6
7
  class ProfileTest < TestCase
7
8
  def test_measure_mode
@@ -13,4 +14,88 @@ class ProfileTest < TestCase
13
14
  profile = RubyProf::Profile.new(:measure_mode => RubyProf::PROCESS_TIME)
14
15
  assert_equal("process_time", profile.measure_mode_string)
15
16
  end
17
+
18
+ def test_add_thread
19
+ profile = RubyProf::Profile.new
20
+ assert_empty(profile.threads)
21
+
22
+ method_info = RubyProf::MethodInfo.new(Array, :size)
23
+ call_tree = RubyProf::CallTree.new(method_info)
24
+ thread = RubyProf::Thread.new(call_tree, Thread.current, Fiber.current)
25
+
26
+ profile.add_thread(thread)
27
+ assert_equal(1, profile.threads.size)
28
+ assert(thread.equal?(profile.threads.first))
29
+ end
30
+
31
+ def test_add_threads
32
+ call_tree_1 = create_call_tree_1
33
+ ruby_thread_1 = Thread.new { }
34
+ thread_1 = RubyProf::Thread.new(call_tree_1, ruby_thread_1, Fiber.current)
35
+
36
+ call_tree_2 = create_call_tree_2
37
+ ruby_thread_2 = Thread.new { }
38
+ thread_2 = RubyProf::Thread.new(call_tree_2, ruby_thread_2, Fiber.current)
39
+
40
+ profile = RubyProf::Profile.new
41
+ profile.add_thread(thread_1)
42
+ profile.add_thread(thread_2)
43
+ assert_equal(1, profile.threads.count)
44
+ end
45
+
46
+ def test_add_fibers
47
+ call_tree_1 = create_call_tree_1
48
+ fiber_1 = Fiber.new { }
49
+ thread_1 = RubyProf::Thread.new(call_tree_1, Thread.current, fiber_1)
50
+
51
+ call_tree_2 = create_call_tree_2
52
+ fiber_2 = Fiber.new { }
53
+ thread_2 = RubyProf::Thread.new(call_tree_2, Thread.current, fiber_2)
54
+
55
+ profile = RubyProf::Profile.new
56
+ profile.add_thread(thread_1)
57
+ profile.add_thread(thread_2)
58
+ assert_equal(2, profile.threads.count)
59
+ end
60
+
61
+ def test_remove_thread
62
+ profile = RubyProf::Profile.new
63
+ assert_empty(profile.threads)
64
+
65
+ method_info = RubyProf::MethodInfo.new(Array, :size)
66
+ call_tree = RubyProf::CallTree.new(method_info)
67
+ thread = RubyProf::Thread.new(call_tree, Thread.current, Fiber.current)
68
+
69
+ profile.add_thread(thread)
70
+ assert_equal(1, profile.threads.size)
71
+ assert(thread.equal?(profile.threads.first))
72
+
73
+ removed = profile.remove_thread(thread)
74
+ assert_equal(0, profile.threads.size)
75
+ assert(removed.equal?(thread))
76
+ end
77
+
78
+ def test_merge
79
+ call_tree_1 = create_call_tree_1
80
+ fiber_1 = Thread.new { }
81
+ thread_1 = RubyProf::Thread.new(call_tree_1, Thread.current, fiber_1)
82
+
83
+ call_tree_2 = create_call_tree_2
84
+ fiber_2 = Thread.new { }
85
+ thread_2 = RubyProf::Thread.new(call_tree_2, Thread.current, fiber_2)
86
+
87
+ profile = RubyProf::Profile.new
88
+ profile.add_thread(thread_1)
89
+ profile.add_thread(thread_2)
90
+
91
+ profile.merge!
92
+ assert_equal(1, profile.threads.count)
93
+
94
+ assert_equal(thread_1, profile.threads.first)
95
+
96
+ assert_in_delta(11.6, thread_1.call_tree.total_time, 0.00001)
97
+ assert_in_delta(0, thread_1.call_tree.self_time, 0.00001)
98
+ assert_in_delta(0.0, thread_1.call_tree.wait_time, 0.00001)
99
+ assert_in_delta(11.6, thread_1.call_tree.children_time, 0.00001)
100
+ end
16
101
  end
@@ -375,7 +375,7 @@ class RecursiveTest < TestCase
375
375
  assert_in_delta(5, method.total_time, 0.1)
376
376
  assert_in_delta(0, method.self_time, 0.1)
377
377
  assert_in_delta(0, method.wait_time, 0.01)
378
- assert_in_delta(5, method.children_time, 0.05)
378
+ assert_in_delta(5, method.children_time, 0.1)
379
379
 
380
380
  assert_equal(2, method.call_trees.callers.length)
381
381
  call_tree = method.call_trees.callers[0]
data/test/scheduler.rb ADDED
@@ -0,0 +1,354 @@
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
+ def initialize
18
+ @readable = {}
19
+ @writable = {}
20
+ @waiting = {}
21
+
22
+ @closed = false
23
+
24
+ @lock = Thread::Mutex.new
25
+ @blocking = Hash.new.compare_by_identity
26
+ @ready = []
27
+
28
+ @urgent = IO.pipe
29
+ end
30
+
31
+ attr :readable
32
+ attr :writable
33
+ attr :waiting
34
+
35
+ def next_timeout
36
+ _fiber, timeout = @waiting.min_by{|key, value| value}
37
+
38
+ if timeout
39
+ offset = timeout - current_time
40
+
41
+ if offset < 0
42
+ return 0
43
+ else
44
+ return offset
45
+ end
46
+ end
47
+ end
48
+
49
+ def run
50
+ # $stderr.puts [__method__, Fiber.current].inspect
51
+
52
+ while @readable.any? or @writable.any? or @waiting.any? or @blocking.any?
53
+ # Can only handle file descriptors up to 1024...
54
+ readable, writable = IO.select(@readable.keys + [@urgent.first], @writable.keys, [], next_timeout)
55
+
56
+ # puts "readable: #{readable}" if readable&.any?
57
+ # puts "writable: #{writable}" if writable&.any?
58
+
59
+ selected = {}
60
+
61
+ readable&.each do |io|
62
+ if fiber = @readable.delete(io)
63
+ @writable.delete(io) if @writable[io] == fiber
64
+ selected[fiber] = IO::READABLE
65
+ elsif io == @urgent.first
66
+ @urgent.first.read_nonblock(1024)
67
+ end
68
+ end
69
+
70
+ writable&.each do |io|
71
+ if fiber = @writable.delete(io)
72
+ @readable.delete(io) if @readable[io] == fiber
73
+ selected[fiber] = selected.fetch(fiber, 0) | IO::WRITABLE
74
+ end
75
+ end
76
+
77
+ selected.each do |fiber, events|
78
+ fiber.resume(events)
79
+ end
80
+
81
+ if @waiting.any?
82
+ time = current_time
83
+ waiting, @waiting = @waiting, {}
84
+
85
+ waiting.each do |fiber, timeout|
86
+ if fiber.alive?
87
+ if timeout <= time
88
+ fiber.resume
89
+ else
90
+ @waiting[fiber] = timeout
91
+ end
92
+ end
93
+ end
94
+ end
95
+
96
+ if @ready.any?
97
+ ready = nil
98
+
99
+ @lock.synchronize do
100
+ ready, @ready = @ready, []
101
+ end
102
+
103
+ ready.each do |fiber|
104
+ fiber.resume
105
+ end
106
+ end
107
+ end
108
+ end
109
+
110
+ def scheduler_close
111
+ close(true)
112
+ end
113
+
114
+ def close(internal = false)
115
+ # $stderr.puts [__method__, Fiber.current].inspect
116
+
117
+ unless internal
118
+ if Fiber.scheduler == self
119
+ return Fiber.set_scheduler(nil)
120
+ end
121
+ end
122
+
123
+ if @closed
124
+ raise "Scheduler already closed!"
125
+ end
126
+
127
+ self.run
128
+ ensure
129
+ if @urgent
130
+ @urgent.each(&:close)
131
+ @urgent = nil
132
+ end
133
+
134
+ @closed ||= true
135
+
136
+ # We freeze to detect any unintended modifications after the scheduler is closed:
137
+ self.freeze
138
+ end
139
+
140
+ def closed?
141
+ @closed
142
+ end
143
+
144
+ def current_time
145
+ Process.clock_gettime(Process::CLOCK_MONOTONIC)
146
+ end
147
+
148
+ def timeout_after(duration, klass, message, &block)
149
+ fiber = Fiber.current
150
+
151
+ self.fiber do
152
+ sleep(duration)
153
+
154
+ if fiber&.alive?
155
+ fiber.raise(klass, message)
156
+ end
157
+ end
158
+
159
+ begin
160
+ yield(duration)
161
+ ensure
162
+ fiber = nil
163
+ end
164
+ end
165
+
166
+ def process_wait(pid, flags)
167
+ # $stderr.puts [__method__, pid, flags, Fiber.current].inspect
168
+
169
+ # This is a very simple way to implement a non-blocking wait:
170
+ Thread.new do
171
+ Process::Status.wait(pid, flags)
172
+ end.value
173
+ end
174
+
175
+ def io_wait(io, events, duration)
176
+ # $stderr.puts [__method__, io, events, duration, Fiber.current].inspect
177
+
178
+ unless (events & IO::READABLE).zero?
179
+ @readable[io] = Fiber.current
180
+ end
181
+
182
+ unless (events & IO::WRITABLE).zero?
183
+ @writable[io] = Fiber.current
184
+ end
185
+
186
+ Fiber.yield
187
+ ensure
188
+ @readable.delete(io)
189
+ @writable.delete(io)
190
+ end
191
+
192
+ def io_select(...)
193
+ # Emulate the operation using a non-blocking thread:
194
+ Thread.new do
195
+ IO.select(...)
196
+ end.value
197
+ end
198
+
199
+ # Used for Kernel#sleep and Thread::Mutex#sleep
200
+ def kernel_sleep(duration = nil)
201
+ # $stderr.puts [__method__, duration, Fiber.current].inspect
202
+ self.block(:sleep, duration)
203
+
204
+ return true
205
+ end
206
+
207
+ # Used when blocking on synchronization (Thread::Mutex#lock,
208
+ # Thread::Queue#pop, Thread::SizedQueue#push, ...)
209
+ def block(blocker, timeout = nil)
210
+ # $stderr.puts [__method__, blocker, timeout].inspect
211
+
212
+ fiber = Fiber.current
213
+
214
+ if timeout
215
+ @waiting[fiber] = current_time + timeout
216
+ begin
217
+ Fiber.yield
218
+ ensure
219
+ # Remove from @waiting in the case #unblock was called before the timeout expired:
220
+ @waiting.delete(fiber)
221
+ end
222
+ else
223
+ @blocking[fiber] = true
224
+ begin
225
+ Fiber.yield
226
+ ensure
227
+ @blocking.delete(fiber)
228
+ end
229
+ end
230
+ end
231
+
232
+ # Used when synchronization wakes up a previously-blocked fiber
233
+ # (Thread::Mutex#unlock, Thread::Queue#push, ...).
234
+ # This might be called from another thread.
235
+ def unblock(blocker, fiber)
236
+ # $stderr.puts [__method__, blocker, fiber].inspect
237
+ # $stderr.puts blocker.backtrace.inspect
238
+ # $stderr.puts fiber.backtrace.inspect
239
+
240
+ @lock.synchronize do
241
+ @ready << fiber
242
+ end
243
+
244
+ io = @urgent.last
245
+ io.write_nonblock('.')
246
+ end
247
+
248
+ def fiber(&block)
249
+ fiber = Fiber.new(blocking: false, &block)
250
+
251
+ fiber.resume
252
+
253
+ return fiber
254
+ end
255
+
256
+ def address_resolve(hostname)
257
+ Thread.new do
258
+ Addrinfo.getaddrinfo(hostname, nil).map(&:ip_address).uniq
259
+ end.value
260
+ end
261
+ end
262
+
263
+ class IOBufferScheduler < Scheduler
264
+ EAGAIN = -Errno::EAGAIN::Errno
265
+
266
+ def io_read(io, buffer, length, offset)
267
+ total = 0
268
+ io.nonblock = true
269
+
270
+ while true
271
+ maximum_size = buffer.size - offset
272
+ result = blocking{buffer.read(io, maximum_size, offset)}
273
+
274
+ if result > 0
275
+ total += result
276
+ offset += result
277
+ break if total >= length
278
+ elsif result == 0
279
+ break
280
+ elsif result == EAGAIN
281
+ if length > 0
282
+ self.io_wait(io, IO::READABLE, nil)
283
+ else
284
+ return result
285
+ end
286
+ elsif result < 0
287
+ return result
288
+ end
289
+ end
290
+
291
+ return total
292
+ end
293
+
294
+ def io_write(io, buffer, length, offset)
295
+ total = 0
296
+ io.nonblock = true
297
+
298
+ while true
299
+ maximum_size = buffer.size - offset
300
+ result = blocking{buffer.write(io, maximum_size, offset)}
301
+
302
+ if result > 0
303
+ total += result
304
+ offset += result
305
+ break if total >= length
306
+ elsif result == 0
307
+ break
308
+ elsif result == EAGAIN
309
+ if length > 0
310
+ self.io_wait(io, IO::WRITABLE, nil)
311
+ else
312
+ return result
313
+ end
314
+ elsif result < 0
315
+ return result
316
+ end
317
+ end
318
+
319
+ return total
320
+ end
321
+
322
+ def blocking(&block)
323
+ Fiber.blocking(&block)
324
+ end
325
+ end
326
+
327
+ class BrokenUnblockScheduler < Scheduler
328
+ def unblock(blocker, fiber)
329
+ super
330
+
331
+ raise "Broken unblock!"
332
+ end
333
+ end
334
+
335
+ class SleepingUnblockScheduler < Scheduler
336
+ # This method is invoked when the thread is exiting.
337
+ def unblock(blocker, fiber)
338
+ super
339
+
340
+ # This changes the current thread state to `THREAD_RUNNING` which causes `thread_join_sleep` to hang.
341
+ sleep(0.1)
342
+ end
343
+ end
344
+
345
+ class SleepingBlockingScheduler < Scheduler
346
+ def kernel_sleep(duration = nil)
347
+ # Deliberaly sleep in a blocking state which can trigger a deadlock if the implementation is not correct.
348
+ Fiber.blocking{sleep 0.0001}
349
+
350
+ self.block(:sleep, duration)
351
+
352
+ return true
353
+ end
354
+ end
data/test/thread_test.rb CHANGED
@@ -4,6 +4,7 @@
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
@@ -12,6 +13,31 @@ class ThreadTest < TestCase
12
13
  RubyProf::measure_mode = RubyProf::WALL_TIME
13
14
  end
14
15
 
16
+ def test_initialize
17
+ method_info = RubyProf::MethodInfo.new(Array, :size)
18
+ call_tree = RubyProf::CallTree.new(method_info)
19
+ thread = RubyProf::Thread.new(call_tree, Thread.current, Fiber.current)
20
+
21
+ assert_equal(call_tree, thread.call_tree)
22
+ assert(thread)
23
+ assert(thread.id)
24
+ assert(thread.fiber_id)
25
+ end
26
+
27
+ def test_merge
28
+ call_tree_1 = create_call_tree_1
29
+ thread_1 = RubyProf::Thread.new(call_tree_1, Thread.current, Fiber.current)
30
+
31
+ call_tree_2 = create_call_tree_2
32
+ thread_2 = RubyProf::Thread.new(call_tree_2, Thread.current, Fiber.current)
33
+
34
+ thread_1.merge!(thread_2)
35
+ assert_in_delta(11.6, thread_1.call_tree.total_time, 0.00001)
36
+ assert_in_delta(0, thread_1.call_tree.self_time, 0.00001)
37
+ assert_in_delta(0.0, thread_1.call_tree.wait_time, 0.00001)
38
+ assert_in_delta(11.6, thread_1.call_tree.children_time, 0.00001)
39
+ end
40
+
15
41
  def test_thread_count
16
42
  RubyProf.start
17
43
 
@@ -71,10 +97,10 @@ class ThreadTest < TestCase
71
97
  method = methods[0]
72
98
  assert_equal('ThreadTest#test_thread_timings', method.full_name)
73
99
  assert_equal(1, method.called)
74
- assert_in_delta(1, method.total_time, 0.05)
100
+ assert_in_delta(1, method.total_time, 0.1)
75
101
  assert_in_delta(0, method.self_time, 0.05)
76
102
  assert_in_delta(0, method.wait_time, 0.05)
77
- assert_in_delta(1, method.children_time, 0.05)
103
+ assert_in_delta(1, method.children_time, 0.1)
78
104
  assert_equal(0, method.call_trees.callers.length)
79
105
 
80
106
  method = methods[1]