Module: TrickBag::Timing

Defined in:
lib/trick_bag/timing/timing.rb,
lib/trick_bag/timing/elapser.rb

Defined Under Namespace

Classes: Elapser

Class Method Summary collapse

Class Method Details

.benchmark(caption, out_stream = $stdout, &block) ⇒ Object

Executes the passed block with the Ruby Benchmark standard library. Prints the benchmark string to the specified output stream. Returns the passed block’s return value.

e.g. benchmark(‘time to loop 1,000,000 times’) { 1_000_000.times { 42 }; ‘hi’ } outputs the following string:

 0.050000   0.000000   0.050000 (  0.042376): time to loop 1,000,000 times
and returns: 'hi'

Parameters:

  • caption

    the text fragment to print after the timing data

  • out_stream (defaults to: $stdout)

    object responding to << that will get the output string defaults to $stdout



98
99
100
101
102
103
# File 'lib/trick_bag/timing/timing.rb', line 98

def benchmark(caption, out_stream = $stdout, &block)
  return_value = nil
  bm = Benchmark.measure { return_value = block.call }
  out_stream << bm.to_s.chomp << ": #{caption}\n"
  return_value
end

.retry_until_true_or_timeout(sleep_interval, timeout_secs, output_stream = $stdout, predicate = nil) ⇒ Object

Calls a predicate proc repeatedly, sleeping the specified interval between calls, returning if the predicate returns true, and giving up after the specified number of seconds. Displays elapsed and remaining times on the terminal. Outputs the time elapsed and the time to go.

Ex: TrickBag::Timing.retry_until_true_or_timeout(->false, 1.0, 5)

Example Code:

require ‘trick_bag’ predicate = -> { false } print “Waiting 10 seconds for true to be returned (but it won’t):n” TrickBag::Timing.retry_until_true_or_timeout(predicate, 1, 10)

Parameters:

  • predicate (defaults to: nil)

    something that can be called with .() or .call that returns a truthy value that indicates no further retries are necessary

  • sleep_interval

    number of seconds (fractions ok) to wait between tries

  • timeout_secs

    maximum number of seconds (fractions ok) during which to retry

Returns:

  • true if/when the predicate returns true, false if it times out



31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
# File 'lib/trick_bag/timing/timing.rb', line 31

def retry_until_true_or_timeout(
    sleep_interval, timeout_secs, output_stream = $stdout, predicate = nil)

  test_preconditions = -> do

    # Method signature has changed from:
    # (predicate, sleep_interval, timeout_secs, output_stream = $stdout)
    # to:
    # (sleep_interval, timeout_secs, output_stream = $stdout, predicate = nil)
    #
    # Test to see that when old signature is used, a descriptive error is raised.
    #
    # This test should be removed when we go to version 1.0.
    if sleep_interval.respond_to?(:call)
      raise ArgumentError.new('Sorry, method signature has changed to: ' \
            '(sleep_interval, timeout_secs, output_stream = $stdout, predicate = nil).' \
            '  Also a code block can now be provided instead of a lambda.')
    end

    if block_given? && predicate
      raise ArgumentError.new('Both a predicate lambda and a code block were specified.' \
          '  Please specify one or the other but not both.')
    end
  end

  test_preconditions.()

  success = false
  start_time = Time.now
  end_time = start_time + timeout_secs

  text_generator = ->() do
    now = Time.now
    elapsed = now - start_time
    to_go = end_time - now
    '%9.3f   %9.3f' % [elapsed, to_go]
  end
  status_updater = ::TrickBag::Io::TextModeStatusUpdater.new(text_generator, output_stream)

  loop do

    break if Time.now >= end_time

    success = !! (block_given? ? yield : predicate.())
    break if success

    status_updater.print
    sleep(sleep_interval)
  end
  output_stream.print "\n"
  success
end

.try_with_timeout(max_seconds, check_interval_in_secs, &block) ⇒ true, block return value

Runs the passed block in a new thread, ensuring that its execution time does not exceed the specified duration.

Parameters:

  • max_seconds

    maximum number of seconds to wait for completion

  • check_interval_in_secs

    interval in seconds at which to check for completion

Returns:

  • (true, block return value)

    if the block completes before timeout or [false, nil] if the block is still active (i.e. the thread is still alive) when max_seconds is reached



116
117
118
119
120
121
122
123
124
125
126
127
128
129
# File 'lib/trick_bag/timing/timing.rb', line 116

def try_with_timeout(max_seconds, check_interval_in_secs, &block)
  raise "Must pass block to this method" unless block_given?
  end_time = Time.now + max_seconds
  block_return_value = nil
  thread = Thread.new { block_return_value = block.call }
  while Time.now < end_time
    unless thread.alive?
      return [true, block_return_value]
    end
    sleep(check_interval_in_secs)
  end
  thread.kill
  [false, nil]
end