# 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