Module: Optimize::Demo::Benchmark

Defined in:
lib/optimize/demo/benchmark.rb

Defined Under Namespace

Classes: Report, Result

Constant Summary collapse

LIB_DIR =

optimizer/lib

File.expand_path("../..", __dir__)

Class Method Summary collapse

Class Method Details

.build_script(label:, with_harness:, fixture_path:, entry_setup:, entry_call:, warmup:, time:) ⇒ Object



52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
# File 'lib/optimize/demo/benchmark.rb', line 52

def build_script(label:, with_harness:, fixture_path:, entry_setup:, entry_call:, warmup:, time:)
  preamble = with_harness ? <<~HARNESS : ""
    require "optimize/harness"
    require "optimize/pipeline"
    hook = Optimize::Harness::LoadIseqHook.new(passes: Optimize::Pipeline.default.passes)
    hook.install
  HARNESS

  <<~SCRIPT
    # frozen_string_literal: true
    require "bundler/setup"
    $LOAD_PATH.unshift(#{LIB_DIR.inspect})
    require "benchmark/ips"
    #{preamble}
    require #{fixture_path.inspect}
    #{entry_setup}
    $stdout.sync = true
    _job = ::Benchmark.ips do |x|
      x.config(warmup: #{warmup}, time: #{time}, quiet: false)
      x.report(#{label.inspect}) { #{entry_call} }
    end
    _entry = _job.entries.last
    printf("IPS_RESULT: %s %.6f\\n", #{label.inspect}, _entry.ips)
  SCRIPT
end

.compare(fixture_path:, entry_setup:, entry_call:, warmup: 2, time: 5) ⇒ Object



16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
# File 'lib/optimize/demo/benchmark.rb', line 16

def compare(fixture_path:, entry_setup:, entry_call:, warmup: 2, time: 5)
  plain     = run_one(label: "plain",     with_harness: false,
                      fixture_path: fixture_path,
                      entry_setup: entry_setup, entry_call: entry_call,
                      warmup: warmup, time: time)
  optimized = run_one(label: "optimized", with_harness: true,
                      fixture_path: fixture_path,
                      entry_setup: entry_setup, entry_call: entry_call,
                      warmup: warmup, time: time)

  Result.new(
    stdout: compose(plain, optimized),
    plain_ips: plain.ips,
    optimized_ips: optimized.ips,
  )
end

.compose(plain, optimized) ⇒ Object



78
79
80
81
82
83
84
85
86
87
88
# File 'lib/optimize/demo/benchmark.rb', line 78

def compose(plain, optimized)
  faster, slower = [plain, optimized].sort_by(&:ips).reverse
  ratio = faster.ips / slower.ips
  <<~OUT
    #{plain.raw.rstrip}
    #{optimized.raw.rstrip}
    Comparison:
      #{faster.label}:   #{format('%.1f', faster.ips)} i/s
      #{slower.label}:   #{format('%.1f', slower.ips)} i/s - #{format('%.2f', ratio)}x  slower
  OUT
end

.run_one(label:, with_harness:, fixture_path:, entry_setup:, entry_call:, warmup:, time:) ⇒ Object



33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
# File 'lib/optimize/demo/benchmark.rb', line 33

def run_one(label:, with_harness:, fixture_path:, entry_setup:, entry_call:, warmup:, time:)
  script = build_script(
    label: label, with_harness: with_harness,
    fixture_path: fixture_path,
    entry_setup: entry_setup, entry_call: entry_call,
    warmup: warmup, time: time,
  )
  Tempfile.create(["demo_bench_#{label}", ".rb"]) do |f|
    f.write(script)
    f.flush
    stdout, status = Open3.capture2e(RbConfig.ruby, "-I", LIB_DIR, f.path)
    raise "benchmark subprocess (#{label}) failed:\n#{stdout}" unless status.success?
    ips_line = stdout.lines.grep(/\AIPS_RESULT:/).last
    raise "IPS_RESULT not found in subprocess output:\n#{stdout}" unless ips_line
    ips = ips_line.strip.split[2].to_f
    Report.new(label: label, ips: ips, raw: stdout.sub(/^IPS_RESULT:.*\n/, ""))
  end
end