Allowing Ruby Benchmark reports to return values

I’ve recently started using Benchmark to record basic timings. It’s hardly profiling, more just a running record of where the time goes.

One annoyance (for me) was that Benchmark::report returns timing information, not the return value from the block being benchmarked. This means adding benchmarking to a function like:

def a_function
  a = an_expensive_function
  b = another_expensive_function
  c = a_third_function(a,b)
  puts c
end

Requires pre-defining a,b,c outside of the report blocks … otherwise they get scoped out:

require 'benchmark'

def a_function
  Benchmark.bm do |bm|
    a = b = c = nil

    bm.report("A") { a = an_expensive_function }
    bm.report("B") { b = another_expensive_function }
    bm.report("C") { c = a_third_function(a,b) }
    puts c
  end
end

which is an annoyance.

I’ve redefined Benchmark::report as:

module Benchmark
  class Report
    def report( label="", *format, &blk )
      retval = nil
      item( label, format ) { retval = blk.yield }
      retval
    end
  end
end

Which lets you do the (slightly more intuitive):

def a_function
  Benchmark.bm do |bm|
    a = bm.report("A") { an_expensive_function }
    b = bm.report("B") { another_expensive_function }
    c = bm.report("C") { a_third_function(a,b) }
    puts c
  end
end