class Benchmark::IPS::Job

Benchmark jobs.

Benchmark jobs.

Constants

MAX_TIME_SKEW

The percentage of the expected runtime to allow before reporting a weird runtime

MICROSECONDS_PER_100MS

Microseconds per 100 millisecond.

MICROSECONDS_PER_SECOND

Microseconds per second.

Attributes

compare[R]

Determining whether to run comparison utility. @return [Boolean] true if needs to run compare.

full_report[R]

Report object containing information about the run. @return [Report] the report object.

hold[RW]

Determining whether to hold results between Ruby invocations @return [Boolean]

iterations[RW]

Warmup and calculation iterations. @return [Integer]

list[R]

Two-element arrays, consisting of label and block pairs. @return [Array<Entry>] list of entries

time[RW]

Calculation time setter and getter (in seconds). @return [Integer]

timing[R]

Storing Iterations in time period. @return [Hash]

warmup[RW]

Warmup time setter and getter (in seconds). @return [Integer]

Public Class Methods

new(opts={}) click to toggle source

Instantiate the Benchmark::IPS::Job. @option opts [Benchmark::Suite] (nil) :suite Specify Benchmark::Suite. @option opts [Boolean] (false) :quiet Suppress the printing of information.

# File lib/benchmark/ips/job.rb, line 48
def initialize opts={}
  @suite = opts[:suite] || nil
  @stdout = opts[:quiet] ? nil : StdoutReport.new
  @list = []
  @compare = false
  @json_path = false
  @held_path = nil
  @held_results = nil

  @timing = {}
  @full_report = Report.new

  # Default warmup and calculation time in seconds.
  @warmup = 2
  @time = 5
  @iterations = 1
end

Public Instance Methods

compare!() click to toggle source

Set @compare to true.

# File lib/benchmark/ips/job.rb, line 84
def compare!
  @compare = true
end
compare?() click to toggle source

Return true if job needs to be compared. @return [Boolean] Need to compare?

# File lib/benchmark/ips/job.rb, line 79
def compare?
  @compare
end
config(opts) click to toggle source

Job configuration options, set +@warmup+ and +@time+. @option opts [Integer] :warmup Warmup time. @option opts [Integer] :time Calculation time. @option iterations [Integer] :time Warmup and calculation iterations.

# File lib/benchmark/ips/job.rb, line 70
def config opts
  @warmup = opts[:warmup] if opts[:warmup]
  @time = opts[:time] if opts[:time]
  @suite = opts[:suite] if opts[:suite]
  @iterations = opts[:iterations] if opts[:iterations]
end
create_report(label, measured_us, iter, avg_ips, sd_ips, cycles) click to toggle source

Create report by add entry to +@full_report+. @param label [String] Report item label. @param measured_us [Integer] Measured time in microsecond. @param iter [Integer] Iterations. @param avg_ips [Float] Average iterations per second. @param sd_ips [Float] Standard deviation iterations per second. @param cycles [Integer] Number of Cycles. @return [Report::Entry] Entry with data.

# File lib/benchmark/ips/job.rb, line 324
def create_report(label, measured_us, iter, avg_ips, sd_ips, cycles)
  @full_report.add_entry label, measured_us, iter, avg_ips, sd_ips, cycles
end
cycles_per_100ms(time_msec, iters) click to toggle source

Calculate the cycles needed to run for approx 100ms, given the number of iterations to run the given time. @param [Float] time_msec Each iteration's time in ms. @param [Integer] iters Iterations. @return [Integer] Cycles per 100ms.

# File lib/benchmark/ips/job.rb, line 134
def cycles_per_100ms time_msec, iters
  cycles = ((MICROSECONDS_PER_100MS / time_msec) * iters).to_i
  cycles = 1 if cycles <= 0
  cycles
end
generate_json() click to toggle source

Generate json from +@full_report+.

# File lib/benchmark/ips/job.rb, line 312
def generate_json
  @full_report.generate_json @json_path if json?
end
held_results?() click to toggle source
# File lib/benchmark/ips/job.rb, line 157
def held_results?
  File.exist?(@held_path)
end
hold!(held_path) click to toggle source

Set @hold to true.

# File lib/benchmark/ips/job.rb, line 95
def hold!(held_path)
  @held_path = held_path
end
hold?() click to toggle source

Return true if results are held while multiple Ruby invocations @return [Boolean] Need to hold results between multiple Ruby invocations?

# File lib/benchmark/ips/job.rb, line 90
def hold?
  !!@held_path
end
item(label="", str=nil) { || ... } click to toggle source

Registers the given label and block pair in the job list. @param label [String] Label of benchmarked code. @param str [String] Code to be benchmarked. @param blk [Proc] Code to be benchmarked. @raise [ArgumentError] Raises if str and blk are both present. @raise [ArgumentError] Raises if str and blk are both absent.

# File lib/benchmark/ips/job.rb, line 116
def item(label="", str=nil, &blk) # :yield:
  if blk and str
    raise ArgumentError, "specify a block and a str, but not both"
  end

  action = str || blk
  raise ArgumentError, "no block or string" unless action

  @list.push Entry.new(label, action)
  self
end
Also aliased as: report
iterations_per_sec(cycles, time_us) click to toggle source

Calculate the interations per second given the number of cycles run and the time in microseconds that elapsed. @param [Integer] cycles Cycles. @param [Integer] #time_us Time in microsecond. @return [Float] Iteration per second.

# File lib/benchmark/ips/job.rb, line 153
def iterations_per_sec cycles, time_us
  MICROSECONDS_PER_SECOND * (cycles.to_f / time_us.to_f)
end
json!(path="data.json") click to toggle source

Set @json_path to given path, defaults to “data.json”.

# File lib/benchmark/ips/job.rb, line 106
def json!(path="data.json")
  @json_path = path
end
json?() click to toggle source

Return true if job needs to generate json. @return [Boolean] Need to generate json?

# File lib/benchmark/ips/job.rb, line 101
def json?
  !!@json_path
end
load_held_results() click to toggle source
# File lib/benchmark/ips/job.rb, line 161
def load_held_results
  require "json"
  @held_results = Hash[File.open(@held_path).map { |line|
    result = JSON.parse(line)
    [result['item'], result]
  }]
end
report(label="", str=nil)
Alias for: item
run() click to toggle source
# File lib/benchmark/ips/job.rb, line 169
def run
  @stdout.start_warming if @stdout
  @iterations.times do
    run_warmup
  end
  
  @stdout.start_running if @stdout
  
  held = nil
  
  @iterations.times do |n|
    held = run_benchmark
  end
  
  if held
    puts
    puts 'Pausing here -- run Ruby again to measure the next benchmark...'
  end
end
run_benchmark() click to toggle source

Run calculation.

# File lib/benchmark/ips/job.rb, line 223
def run_benchmark
  @list.each do |item|
    if hold? && @held_results && @held_results.key?(item.label)
     result = @held_results[item.label]
      create_report(item.label, result['measured_us'], result['iter'],
        result['avg_ips'], result['sd_ips'], result['cycles'])
      next
    end
    
    @suite.running item.label, @time if @suite
    @stdout.running item.label, @time if @stdout

    Timing.clean_env

    iter = 0

    measurements_us = []

    # Running this number of cycles should take around 100ms.
    cycles = @timing[item]

    target = Time.now + @time
    
    while Time.now < target
      before = Time.now
      item.call_times cycles
      after = Time.now

      # If for some reason the timing said this took no time (O_o)
      # then ignore the iteration entirely and start another.
      iter_us = time_us before, after
      next if iter_us <= 0.0

      iter += cycles

      measurements_us << iter_us
    end

    final_time = Time.now

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

    all_ips = measurements_us.map { |time_us|
      iterations_per_sec cycles, time_us
    }

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

    rep = create_report(item.label, measured_us, iter, avg_ips, sd_ips, cycles)

    if (final_time - target).abs >= (@time.to_f * MAX_TIME_SKEW)
      rep.show_total_time!
    end

    @stdout.add_report rep, caller(1).first if @stdout
    @suite.add_report rep, caller(1).first if @suite
    
    if hold? && item != @list.last
      File.open @held_path, "a" do |f|
        require "json"
        f.write JSON.generate({
          :item => item.label,
          :measured_us => measured_us,
          :iter => iter,
          :avg_ips => avg_ips,
          :sd_ips => sd_ips,
          :cycles => cycles
        })
        f.write "\n"
      end
      
      return true
    end
  end
  
  if hold? && @full_report.entries.size == @list.size
    File.delete @held_path if File.exist?(@held_path)
  end
  
  false
end
run_comparison() click to toggle source

Run comparison of entries in +@full_report+.

# File lib/benchmark/ips/job.rb, line 307
def run_comparison
  @full_report.run_comparison if compare?
end
run_warmup() click to toggle source

Run warmup.

# File lib/benchmark/ips/job.rb, line 190
def run_warmup
  @list.each do |item|
    next if hold? && @held_results && @held_results.key?(item.label)
    
    @suite.warming item.label, @warmup if @suite
    @stdout.warming item.label, @warmup if @stdout

    Timing.clean_env

    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_us = time_us before, after

    @timing[item] = cycles_per_100ms warmup_time_us, warmup_iter

    @stdout.warmup_stats warmup_time_us, @timing[item] if @stdout
    @suite.warmup_stats warmup_time_us, @timing[item] if @suite
    
    break if hold?
  end
end
time_us(before, after) click to toggle source

Calculate the time difference of before and after in microseconds. @param [Time] before time. @param [Time] after time. @return [Float] Time difference of before and after.

# File lib/benchmark/ips/job.rb, line 144
def time_us before, after
  (after.to_f - before.to_f) * MICROSECONDS_PER_SECOND
end