Project

General

Profile

Actions

Feature #10165

closed

Use Process.clock_gettime to speed up Benchmark.realtime.

Feature #10165: Use Process.clock_gettime to speed up Benchmark.realtime.

Added by phiggins (Pete Higgins) about 11 years ago. Updated about 11 years ago.

Status:
Closed
Assignee:
-
Target version:
-
[ruby-core:64511]

Description

This patch changes the Benchmark.realtime method to use the Process.clock_gettime internally when generating the time elapsed. Calling Process.clock_gettime is faster than the current way of creating Time objects.

I wrote a benchmark script (also attached) to demonstrate the difference:

require 'benchmark'

def old_benchmark
  r0 = Time.now
  yield
  Time.now - r0
end

def new_benchmark
  r0 = Process.clock_gettime(Process::CLOCK_MONOTONIC)
  yield
  Process.clock_gettime(Process::CLOCK_MONOTONIC) - r0
end

n = (ARGV.first || 1_000_000).to_i

puts "#{n} iterations."

Benchmark.bmbm do |b|
  b.report("old") { n.times { old_benchmark { nil } } }
  b.report("new") { n.times { new_benchmark { nil } } }
end

When I run this on my local machine I see this output:

1000000 iterations.
Rehearsal ---------------------------------------
old   0.860000   0.000000   0.860000 (  0.863118)
new   0.360000   0.000000   0.360000 (  0.355242)
------------------------------ total: 1.220000sec

          user     system      total        real
old   0.870000   0.010000   0.880000 (  0.866577)
new   0.330000   0.000000   0.330000 (  0.328982)

I discussed this idea originally with Eric Hodel, but he has not reviewed this code.


Files

benchmark_benchmark_realtime.rb (424 Bytes) benchmark_benchmark_realtime.rb phiggins (Pete Higgins), 08/23/2014 08:58 PM
faster_benchmark_realtime.diff (909 Bytes) faster_benchmark_realtime.diff phiggins (Pete Higgins), 08/23/2014 08:59 PM
faster_benchmark_realtime_2.diff (1.1 KB) faster_benchmark_realtime_2.diff phiggins (Pete Higgins), 08/24/2014 12:22 AM

Updated by normalperson (Eric Wong) about 11 years ago Actions #1 [ruby-core:64515]

I like this. The speedup is from reduction of allocations+GC

I think you need to fall back to CLOCK_REALTIME on systems w/o
CLOCK_MONOTONIC, though. Based on my reading of process.c,
CLOCK_REALTIME is always available. So something like this:

if defined?(Process::CLOCK_MONOTONIC)
  BENCHMARK_CLOCK = Process::CLOCK_MONOTONIC
else
  # Ruby may use gettimeofday to emulate:
  BENCHMARK_CLOCK = Process::CLOCK_REALTIME
end

def realtime # :yield:
  r0 = Process.clock_gettime(BENCHMARK_CLOCK)
  yield
  Process.clock_gettime(BENCHMARK_CLOCK) - r0
end

Updated by phiggins (Pete Higgins) about 11 years ago Actions #2 [ruby-core:64521]

Eric Wong wrote:

I like this. The speedup is from reduction of allocations+GC

I think you need to fall back to CLOCK_REALTIME on systems w/o
CLOCK_MONOTONIC, though. Based on my reading of process.c,
CLOCK_REALTIME is always available. So something like this:

It wasn't clear from the docs if there was a way to tell which modes were supported. Thanks for looking into that!

I've made an updated patch with the changes Eric Wong suggested.

Updated by Anonymous about 11 years ago Actions #3

  • Status changed from Open to Closed
  • % Done changed from 0 to 100

Applied in changeset r47260.


lib/benchmark.rb: speedup by reducing allocations

  • lib/benchmark.rb (module Benchmark): define BENCHMARK_CLOCK
    (realtime): use Process.clock_gettime(BENCHMARK_CLOCK)
    [Feature #10165]

  • test/benchmark/test_benchmark.rb (test_realtime_output): new test

Updated by normalperson (Eric Wong) about 11 years ago Actions #4 [ruby-core:64522]

Thanks Pete! I committed your patch as r47260.
I couldn't resist, so I also made r47622 to modify measure, too.
(smaller improvement, 1.30s vs 1.44s on my VM)

require 'benchmark'
p(Benchmark.measure { 100000.times { Benchmark.measure {} } })
Actions

Also available in: PDF Atom