class Benchkit

Constants

DEFAULT_IPS_DURATION
DEFAULT_LOOP_COUNT
MEASURE_TYPES
VERSION

Public Class Methods

new(measure_type: 'loop_count', measure_num: nil, execs: ['ruby'], verbose: false) click to toggle source

@param [String] measure_type - “loop_count”|“ips” @param [Integer,nil] measure_num - Loop count for “loop_type”, duration seconds for “ips” @param [Array<String>] execs - [“path1”, “path2”] or `[“ruby1::path1”, “ruby2::path2”]` @param [Boolean] verbose

# File lib/benchkit.rb, line 14
def initialize(measure_type: 'loop_count', measure_num: nil, execs: ['ruby'], verbose: false)
  unless MEASURE_TYPES.include?(measure_type)
    abort "unsupported measure type: #{measure_type.dump}"
  end
  @measure_type = measure_type
  @measure_num = measure_num
  @execs = execs.map do |exec|
    name, path = exec.split('::', 2)
    Executable.new(name, path || name)
  end
  @verbose = verbose
end

Public Instance Methods

run(root_hash) click to toggle source

@param [Hash] root_hash

# File lib/benchkit.rb, line 28
def run(root_hash)
  root = BenchmarkRoot.new(Hash[root_hash.map { |k, v| [k.to_sym, v] }])

  results = root.benchmarks.map do |benchmark|
    metrics_by_exec = {}
    iterations = calc_iterations(@execs.first, benchmark)
    @execs.each do |exec|
      if @verbose
        puts "--- Running #{benchmark.name.dump} with #{exec.name.dump} #{iterations} times ---"
        puts "#{benchmark.benchmark_script(iterations)}\n"
      end
      elapsed_time = run_benchmark(exec, benchmark, iterations)
      metrics_by_exec[exec] = BenchmarkMetrics.new(iterations, elapsed_time)
    end
    BenchmarkResult.new(benchmark.name, metrics_by_exec)
  end
  puts if @verbose

  case @measure_type
  when 'loop_count'
    LoopCountReporter.report(@execs, results)
  when 'ips'
    IpsReporter.report(@execs, results)
  else
    raise "unexpected measure type: #{@measure_type.dump}"
  end
end

Private Instance Methods

calc_iterations(exec, benchmark) click to toggle source

Estimate iterations to finish benchmark within `@duration`.

# File lib/benchkit.rb, line 59
def calc_iterations(exec, benchmark)
  case @measure_type
  when 'loop_count'
    @measure_num || benchmark.loop_count || DEFAULT_LOOP_COUNT
  when 'ips'
    # TODO: Change to try from 1, 10, 100 ...
    base = 1000
    time = run_benchmark(exec, benchmark, base)
    duration = @measure_num || DEFAULT_IPS_DURATION
    (duration / time * base).to_i
  else
    raise "unexpected measure type: #{@measure_type.dump}"
  end
end
measure_script(ruby, script) click to toggle source
# File lib/benchkit.rb, line 80
def measure_script(ruby, script)
  Tempfile.create(File.basename(__FILE__)) do |f|
    f.write(script)
    f.close

    cmd = "#{ruby} #{f.path}"
    Benchmark.measure { system(cmd, out: File::NULL) }.real
  end
end
run_benchmark(exec, benchmark, iterations) click to toggle source
# File lib/benchkit.rb, line 74
def run_benchmark(exec, benchmark, iterations)
  # TODO: raise error if negative
  measure_script(exec.path, benchmark.benchmark_script(iterations)) -
    measure_script(exec.path, benchmark.overhead_script(iterations))
end