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.

confidence[RW]

Confidence. @return [Integer]

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

stats[RW]

Statistics model. @return [Object]

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 56
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

  # Default statistical model
  @stats = :sd
  @confidence = 95
end

Public Instance Methods

compare!() click to toggle source

Set @compare to true.

# File lib/benchmark/ips/job.rb, line 98
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 93
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 82
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]
  @stats = opts[:stats] if opts[:stats]
  @confidence = opts[:confidence] if opts[:confidence]
end
create_report(label, measured_us, iter, samples, 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 samples [Array<Float>] Sampled iterations per second. @param cycles [Integer] Number of Cycles. @return [Report::Entry] Entry with data.

# File lib/benchmark/ips/job.rb, line 344
def create_report(label, measured_us, iter, samples, cycles)
  @full_report.add_entry label, measured_us, iter, samples, cycles
end
create_stats(samples) click to toggle source
# File lib/benchmark/ips/job.rb, line 316
def create_stats(samples)
  case @stats
    when :sd
      Stats::SD.new(samples)
    when :bootstrap
      Stats::Bootstrap.new(samples, @confidence)
    else
      raise "unknown stats #{@stats}"
  end
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 148
def cycles_per_100ms time_msec, iters
  cycles = ((MICROSECONDS_PER_100MS / time_msec) * iters).to_i
  cycles <= 0 ? 1 : cycles
end
generate_json() click to toggle source

Generate json from +@full_report+.

# File lib/benchmark/ips/job.rb, line 333
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 170
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 109
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 104
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 130
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 166
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 120
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 115
def json?
  !!@json_path
end
load_held_results() click to toggle source
# File lib/benchmark/ips/job.rb, line 174
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 182
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

  @stdout.footer if @stdout
  
  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 238
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'],
                    create_stats(result['samples']), 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 = Timing.add_second Timing.now, @time
    
    while (before = Timing.now) < target
      item.call_times cycles
      after = Timing.now

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

      iter += cycles

      measurements_us << iter_us
    end

    final_time = before

    measured_us = measurements_us.inject(:+)

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

    rep = create_report(item.label, measured_us, iter, create_stats(samples), 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,
          :samples => samples,
          :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 328
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 205
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 = Timing.now
    target = Timing.add_second before, @warmup

    warmup_iter = 0

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

    after = Timing.now

    warmup_time_us = Timing.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 157
def time_us before, after
  (after.to_f - before.to_f) * MICROSECONDS_PER_SECOND
end