class RubybenchRunner::BaseRunner

Constants

COPY_FOLDERS
DEFAULT_OPTS
HELPERS_VERSION_FILE

Attributes

opts[R]
repo_path[R]
script_url[R]

Public Class Methods

new(script, opts = {}) click to toggle source
# File lib/rubybench_runner/base_runner.rb, line 33
def initialize(script, opts = {})
  @script_name = script
  @opts = OpenStruct.new(DEFAULT_OPTS.merge(opts))
  @script_url = @opts.url || script_full_url(script)
  @results = []
  @error = nil
  @output = ""
end

Public Instance Methods

benchmark_name() click to toggle source
# File lib/rubybench_runner/base_runner.rb, line 137
def benchmark_name
  raise "Override the `benchmark_name` method in your class"
end
bundle_install() click to toggle source
# File lib/rubybench_runner/base_runner.rb, line 259
def bundle_install
  return if without_bundle?

  log("Installing gems...")
  comm = "bundle install"
  if opts.db == "mysql2"
    comm += " --without postgres"
  elsif opts.db == "postgres"
    comm += " --without mysql"
  else
    comm += " --without mysql postgres"
  end
  comm += " > /dev/null 2>&1" if !opts.verbose
  Dir.chdir(File.dirname(gemfile_location)) do
    system(comm)
  end

  if require_db?
    Dir.chdir(File.join(dest_dir, "support", "setup")) do
      system(comm)
    end
  end
end
check_dependencies() click to toggle source
# File lib/rubybench_runner/base_runner.rb, line 145
def check_dependencies
  return if opts.skip_dependencies_check || !require_db?

  if opts.db == "postgres"
    require_gem 'pg'
  elsif opts.db == "mysql2"
    require_gem 'mysql2'
  end

  log("Checking dependencies...")
  RubybenchRunner::DependenciesChecker.check(pg: opts.db == "postgres", mysql: opts.db == "mysql2")
end
command() click to toggle source
# File lib/rubybench_runner/base_runner.rb, line 129
def command
  if without_bundle?
    "ruby #{script_name}"
  else
    "BUNDLE_GEMFILE=#{gemfile_location} bundle exec ruby #{script_name}"
  end
end
copy_helpers(dest) click to toggle source
# File lib/rubybench_runner/base_runner.rb, line 95
def copy_helpers(dest)
  gem_helpers_version_path = File.join(__dir__, HELPERS_VERSION_FILE)
  current_helpers_version_path = File.join(dest, HELPERS_VERSION_FILE)
  if !File.exists?(current_helpers_version_path) ||
    File.read(gem_helpers_version_path) != File.read(current_helpers_version_path)
    FileUtils.cp(gem_helpers_version_path, current_helpers_version_path)
    COPY_FOLDERS.each do |folder|
      origin = File.join(__dir__, folder)
      destination = File.join(dest, folder)
      FileUtils.cp_r(origin, destination)
    end
  end
end
create_tmpdir() click to toggle source
# File lib/rubybench_runner/base_runner.rb, line 90
def create_tmpdir
  FileUtils.mkdir_p(dest_dir)
  copy_helpers(dest_dir)
end
dest_dir() click to toggle source
# File lib/rubybench_runner/base_runner.rb, line 85
def dest_dir
  # directory where all helpers and gems will be installed/copied to
  @dest_dir ||= File.join(Dir.tmpdir, "rubybench_runner_tmp")
end
download_script() click to toggle source
# File lib/rubybench_runner/base_runner.rb, line 283
def download_script
  log("Downloading script...")
  content = open(script_url).read
  File.write(script_full_path, content)
rescue OpenURI::HTTPError => e
  log("Script download failed #{script_url}", f: true)
  @error = e
end
gemfile_content() click to toggle source
# File lib/rubybench_runner/base_runner.rb, line 113
def gemfile_content
  nil
end
is_repo_path_valid?() click to toggle source
# File lib/rubybench_runner/base_runner.rb, line 62
def is_repo_path_valid?
  true
end
possible_repo_path() click to toggle source
# File lib/rubybench_runner/base_runner.rb, line 58
def possible_repo_path
  File.join(Dir.home, benchmark_name.downcase)
end
print_results() click to toggle source
process_results() click to toggle source
# File lib/rubybench_runner/base_runner.rb, line 212
def process_results
  return if @error
  @results.map! do |res|
    res.each do |key, val|
      if Float === val
        res[key] = val.round(opts.round)
      end
    end
    res
  end

  @results.sort_by! do |res|
    res['iterations_per_second']
  end
end
require_db?() click to toggle source
# File lib/rubybench_runner/base_runner.rb, line 141
def require_db?
  false
end
run() click to toggle source
# File lib/rubybench_runner/base_runner.rb, line 42
def run
  set_repo_path
  cleanup(before: true)
  create_tmpdir
  check_dependencies
  write_gemfile
  bundle_install
  setup_db
  download_script
  run_benchmarks
  process_results
  print_results
ensure
  cleanup(after: true)
end
run_benchmarks() click to toggle source
# File lib/rubybench_runner/base_runner.rb, line 194
def run_benchmarks
  return if @error
  log("Running benchmarks...")
  Dir.chdir(script_path) do
    opts.repeat_count.times do |n|
      res, err = Open3.capture3(command)
      if err.size == 0
        @results[n] = res
        @results[n] = JSON.parse(res)
      else
        raise ShellError.new(err)
      end
    end
  end
rescue => err
  @error = err
end
save_dir() click to toggle source
# File lib/rubybench_runner/base_runner.rb, line 109
def save_dir
  raise "Override the `save_dir` method in your subclass #{self.class.name}"
end
script_full_path() click to toggle source
# File lib/rubybench_runner/base_runner.rb, line 121
def script_full_path
  @script_full_path ||= File.join(script_path, script_name)
end
script_name() click to toggle source
# File lib/rubybench_runner/base_runner.rb, line 125
def script_name
  "script.rb"
end
script_path() click to toggle source
# File lib/rubybench_runner/base_runner.rb, line 117
def script_path
  @script_path ||= File.join(save_dir, "benchmarks")
end
set_repo_path() click to toggle source
# File lib/rubybench_runner/base_runner.rb, line 66
def set_repo_path
  name = benchmark_name.downcase
  from_opts = false
  if path = opts.send(name)
    from_opts = true
    @repo_path = path
  else
    @repo_path = possible_repo_path
    log("Running #{name} benchmark #{@script_name}: #{name} path is #{possible_repo_path}\n")
  end

  unless is_repo_path_valid?
    output = "Cannot find #{name} at #{@repo_path}."
    output += "Perhaps try:\n\nrubybench_runner run #{name}/#{@script_name} --#{name}=/path/to/#{name}" unless from_opts
    log(output, f: true)
    exit 1
  end
end
setup_db() click to toggle source
# File lib/rubybench_runner/base_runner.rb, line 158
def setup_db
  return if !require_db?

  log("Checking database...")
  config = RubybenchRunner::Configurations.new(mysql_map: true)
  if opts.db == "postgres"
    conn_config = config["postgres"]
    rubybench_db = conn_config[:dbname]
    conn_config[:dbname] = "postgres"
    conn = PG.connect(conn_config)
    begin
      res = conn.exec("SELECT 1 FROM pg_database WHERE datname = '#{rubybench_db}'")
      if !res.first
        conn.exec("CREATE DATABASE #{rubybench_db}")
        log("Created PostgreSQL database with the name '#{rubybench_db}'")
      end
    ensure
      conn.close
    end
  elsif opts.db == "mysql2"
    conn_config = config["mysql2"]
    rubybench_db = conn_config[:database]
    conn_config[:database] = "mysql"
    client = Mysql2::Client.new(conn_config)
    begin
      res = client.query("SHOW DATABASES LIKE '#{rubybench_db}'")
      if !res.first
        client.query("CREATE DATABASE #{rubybench_db}")
        log("Created MySQL database with the name '#{rubybench_db}'")
      end
    ensure
      client.close
    end
  end
end
write_gemfile() click to toggle source
# File lib/rubybench_runner/base_runner.rb, line 292
def write_gemfile
  return if without_bundle?
  File.write(gemfile_location, gemfile_content)
end

Private Instance Methods

cleanup(before: false, after: false) click to toggle source
# File lib/rubybench_runner/base_runner.rb, line 312
def cleanup(before: false, after: false)
  FileUtils.rm_f(script_full_path)
  FileUtils.rm_rf(dest_dir) if (opts.fresh_run && before) || (opts.cleanup && after)
end
gemfile_location() click to toggle source
# File lib/rubybench_runner/base_runner.rb, line 308
def gemfile_location
  File.join(save_dir, "Gemfile")
end
install_gem(gem_name) click to toggle source
# File lib/rubybench_runner/base_runner.rb, line 345
def install_gem(gem_name)
  cmd = Gem::Commands::InstallCommand.new
  cmd.handle_options [gem_name]     

  cmd.execute
rescue Gem::SystemExitException => e
  puts "FAILURE: #{e.exit_code} -- #{e.message}" if e.exit_code != 0
end
log(msg, f: false) click to toggle source
# File lib/rubybench_runner/base_runner.rb, line 299
def log(msg, f: false)
  return if opts.quiet && !f
  puts msg
end
require_gem(gem_name) click to toggle source

small hack for dynamically installing/requiring gems. some benchmarks don't require db at all so having mysql2 and pg in the gemspec file means everyone must have postgres and mysql installed on their machine in order to use this gem. this hack allows us to not require mysql/postgres until the user tries to run a benchmark that needs db. – source stackoverflow.com/a/36570445

# File lib/rubybench_runner/base_runner.rb, line 334
def require_gem(gem_name)
  require 'rubygems/commands/install_command'
  Gem::Specification::find_by_name(gem_name)
rescue Gem::LoadError
  log("Installing the '#{opts.db}' gem...")
  install_gem(gem_name)
ensure
  log("Using the '#{opts.db}' gem...")
  require gem_name
end
script_full_url(script) click to toggle source
# File lib/rubybench_runner/base_runner.rb, line 317
def script_full_url(script)
  if script !~ /\.rb$/
    script += ".rb"
  end
  "https://raw.githubusercontent.com/ruby-bench/ruby-bench-suite/master/#{benchmark_name.downcase}/benchmarks/#{script}"
end
without_bundle?() click to toggle source
# File lib/rubybench_runner/base_runner.rb, line 304
def without_bundle?
  !gemfile_content
end