module Benchmark

Public Class Methods

compare(*reports) click to toggle source
# File lib/benchmark/compare.rb, line 2
def compare(*reports)
  return if reports.size < 2

  iter = false
  sorted = reports.sort do |a,b|
    if a.respond_to? :ips
      iter = true
      b.ips <=> a.ips
    else
      a.runtime <=> b.runtime
    end
  end

  best = sorted.shift

  STDOUT.puts "\nComparison:"

  if iter
    STDOUT.printf "%20s: %10.1f i/s\n", best.label, best.ips
  else
    STDOUT.puts "#{best.rjust(20)}: #{best.runtime}s"
  end

  sorted.each do |report|
    name = report.label

    if iter
      x = (best.ips.to_f / report.ips.to_f)
      STDOUT.printf "%20s: %10.1f i/s - %.2fx slower\n", name, report.ips, x
    else
      x = "%.2f" % (report.ips.to_f / best.ips.to_f)
      STDOUT.puts "#{name.rjust(20)}: #{report.runtime}s - #{x}x slower"
    end
  end

  STDOUT.puts
end
ips(time=5, warmup=2) { |job| ... } click to toggle source
# File lib/benchmark/ips.rb, line 139
def ips(time=5, warmup=2)
  suite = nil

  sync, $stdout.sync = $stdout.sync, true

  if defined? Benchmark::Suite and Suite.current
    suite = Benchmark::Suite.current
  end

  quiet = suite && !suite.quiet?

  job = IPSJob.new
  yield job

  reports = []

  timing = {}

  $stdout.puts "Calculating -------------------------------------" unless quiet

  job.list.each do |item|
    suite.warming item.label, warmup if suite

    Timing.clean_env

    unless quiet
      if item.label.size > 20
        $stdout.print "#{item.label}\n#{' ' * 20}"
      else
        $stdout.print item.label.rjust(20)
      end
    end

    before = Time.now
    target = Time.now + warmup

    warmup_iter = 0

    while Time.now < target
      item.call_times(1)
      warmup_iter += 1
    end

    after = Time.now

    warmup_time = (after.to_f - before.to_f) * 1_000_000.0

    # calculate the time to run approx 100ms
    
    cycles_per_100ms = ((100_000 / warmup_time) * warmup_iter).to_i
    cycles_per_100ms = 1 if cycles_per_100ms <= 0

    timing[item] = cycles_per_100ms

    $stdout.printf "%10d i/100ms\n", cycles_per_100ms unless quiet

    suite.warmup_stats warmup_time, cycles_per_100ms if suite
  end

  $stdout.puts "-------------------------------------------------" unless quiet

  job.list.each do |item|
    unless quiet
      if item.label.size > 20
        $stdout.print "#{item.label}\n#{' ' * 20}"
      else
        $stdout.print item.label.rjust(20)
      end
    end

    Timing.clean_env

    suite.running item.label, time if suite

    iter = 0

    target = Time.now + time

    measurements = []

    cycles_per_100ms = timing[item]

    while Time.now < target
      before = Time.now
      item.call_times cycles_per_100ms
      after = Time.now

      # If for some reason the timing said this too no time (O_o)
      # then ignore the iteration entirely and start another.
      #
      m = ((after.to_f - before.to_f) * 1_000_000.0)
      next if m <= 0.0

      iter += cycles_per_100ms

      measurements << m
    end

    measured_us = measurements.inject(0) { |a,i| a + i }

    all_ips = measurements.map { |i| cycles_per_100ms.to_f / (i.to_f / 1_000_000) }

    avg_ips = Timing.mean(all_ips)
    sd_ips =  Timing.stddev(all_ips).round

    rep = IPSReport.new(item.label, measured_us, iter, avg_ips, sd_ips, cycles_per_100ms)

    $stdout.puts " #{rep.body}" unless quiet

    suite.add_report rep, caller(1).first if suite

    reports << rep
  end

  $stdout.sync = sync

  if job.compare
    Benchmark.compare(*reports)
  end

  return reports
end