benchmark_driver 0.8.6 → 0.9.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +5 -5
- data/.travis.yml +1 -3
- data/CHANGELOG.md +9 -0
- data/Gemfile +1 -6
- data/README.md +51 -52
- data/benchmark_driver.gemspec +3 -2
- data/bin/console +4 -11
- data/examples/exec_blank.rb +2 -2
- data/examples/exec_blank_simple.rb +2 -3
- data/exe/benchmark-driver +74 -83
- data/lib/benchmark_driver.rb +12 -1
- data/lib/benchmark_driver/config.rb +36 -0
- data/lib/benchmark_driver/default_job.rb +12 -0
- data/lib/benchmark_driver/default_job_parser.rb +68 -0
- data/lib/benchmark_driver/job_parser.rb +42 -0
- data/lib/benchmark_driver/metrics.rb +17 -0
- data/lib/benchmark_driver/output.rb +27 -0
- data/lib/benchmark_driver/output/compare.rb +196 -0
- data/lib/benchmark_driver/output/markdown.rb +102 -0
- data/lib/benchmark_driver/output/simple.rb +97 -0
- data/lib/benchmark_driver/rbenv.rb +11 -0
- data/lib/benchmark_driver/ruby_interface.rb +51 -0
- data/lib/benchmark_driver/runner.rb +42 -0
- data/lib/benchmark_driver/runner/ips.rb +239 -0
- data/lib/benchmark_driver/runner/memory.rb +142 -0
- data/lib/benchmark_driver/runner/time.rb +18 -0
- data/lib/benchmark_driver/struct.rb +85 -0
- data/lib/benchmark_driver/version.rb +3 -0
- metadata +21 -33
- data/bin/bench +0 -4
- data/examples/call.rb +0 -12
- data/examples/call_blank.rb +0 -13
- data/examples/call_erb.rb +0 -33
- data/examples/call_interpolation.rb +0 -13
- data/examples/eval_blank.rb +0 -12
- data/examples/eval_blank_loop.rb +0 -13
- data/examples/eval_interpolation.rb +0 -15
- data/lib/benchmark/driver.rb +0 -101
- data/lib/benchmark/driver/benchmark_result.rb +0 -21
- data/lib/benchmark/driver/bundle_installer.rb +0 -45
- data/lib/benchmark/driver/bundler.rb +0 -12
- data/lib/benchmark/driver/configuration.rb +0 -77
- data/lib/benchmark/driver/duration_runner.rb +0 -24
- data/lib/benchmark/driver/error.rb +0 -16
- data/lib/benchmark/driver/repeatable_runner.rb +0 -18
- data/lib/benchmark/driver/ruby_dsl_parser.rb +0 -78
- data/lib/benchmark/driver/time.rb +0 -12
- data/lib/benchmark/driver/version.rb +0 -5
- data/lib/benchmark/driver/yaml_parser.rb +0 -55
- data/lib/benchmark/output.rb +0 -20
- data/lib/benchmark/output/ips.rb +0 -143
- data/lib/benchmark/output/markdown.rb +0 -73
- data/lib/benchmark/output/memory.rb +0 -57
- data/lib/benchmark/output/time.rb +0 -57
- data/lib/benchmark/runner.rb +0 -14
- data/lib/benchmark/runner/call.rb +0 -97
- data/lib/benchmark/runner/eval.rb +0 -147
- data/lib/benchmark/runner/exec.rb +0 -193
@@ -1,73 +0,0 @@
|
|
1
|
-
class Benchmark::Output::Markdown
|
2
|
-
# This class requires runner to measure following fields in `Benchmark::Driver::BenchmarkResult` to show output.
|
3
|
-
REQUIRED_FIELDS = [:real]
|
4
|
-
|
5
|
-
# @param [Array<Benchmark::Driver::Configuration::Job>] jobs
|
6
|
-
# @param [Array<Benchmark::Driver::Configuration::Executable>] executables
|
7
|
-
# @param [Benchmark::Driver::Configuration::OutputOptions] options
|
8
|
-
def initialize(jobs:, executables:, options:)
|
9
|
-
@jobs = jobs
|
10
|
-
@executables = executables
|
11
|
-
@options = options
|
12
|
-
@name_length = jobs.map { |j| j.name.size }.max
|
13
|
-
end
|
14
|
-
|
15
|
-
def start_warming
|
16
|
-
$stdout.print 'warming up...'
|
17
|
-
end
|
18
|
-
|
19
|
-
# @param [String] name
|
20
|
-
def warming(name)
|
21
|
-
# noop
|
22
|
-
end
|
23
|
-
|
24
|
-
# @param [Benchmark::Driver::BenchmarkResult] result
|
25
|
-
def warmup_stats(result)
|
26
|
-
$stdout.print '.'
|
27
|
-
end
|
28
|
-
|
29
|
-
def start_running
|
30
|
-
$stdout.puts if @jobs.any?(&:warmup_needed?)
|
31
|
-
|
32
|
-
$stdout.print("|#{' ' * @name_length}|")
|
33
|
-
@executables.each do |executable|
|
34
|
-
$stdout.print('%-10s |' % executable.name)
|
35
|
-
end
|
36
|
-
$stdout.puts
|
37
|
-
|
38
|
-
$stdout.print("|:#{'-' * (@name_length-1)}|")
|
39
|
-
@executables.each do |executable|
|
40
|
-
$stdout.print(":#{'-' * 10}|")
|
41
|
-
end
|
42
|
-
$stdout.puts
|
43
|
-
end
|
44
|
-
|
45
|
-
# @param [String] name
|
46
|
-
def running(name)
|
47
|
-
$stdout.print("|%-#{@name_length}s|" % name)
|
48
|
-
@ran_num = 0
|
49
|
-
end
|
50
|
-
|
51
|
-
# @param [Benchmark::Driver::BenchmarkResult] result
|
52
|
-
def benchmark_stats(result)
|
53
|
-
if @options.compare
|
54
|
-
if @ran_num == 0
|
55
|
-
@base_real = result.real
|
56
|
-
$stdout.print('%-10.2f |' % 1)
|
57
|
-
else
|
58
|
-
$stdout.print('%-10.2f |' % (@base_real / result.real))
|
59
|
-
end
|
60
|
-
else
|
61
|
-
$stdout.print('%-10.3f |' % result.real)
|
62
|
-
end
|
63
|
-
|
64
|
-
@ran_num += 1
|
65
|
-
if @ran_num == @executables.size
|
66
|
-
$stdout.puts
|
67
|
-
end
|
68
|
-
end
|
69
|
-
|
70
|
-
def finish
|
71
|
-
# compare is done in table
|
72
|
-
end
|
73
|
-
end
|
@@ -1,57 +0,0 @@
|
|
1
|
-
class Benchmark::Output::Memory
|
2
|
-
# This class requires runner to measure following fields in `Benchmark::Driver::BenchmarkResult` to show output.
|
3
|
-
REQUIRED_FIELDS = [:max_rss]
|
4
|
-
|
5
|
-
# @param [Array<Benchmark::Driver::Configuration::Job>] jobs
|
6
|
-
# @param [Array<Benchmark::Driver::Configuration::Executable>] executables
|
7
|
-
# @param [Benchmark::Driver::Configuration::OutputOptions] options
|
8
|
-
def initialize(jobs:, executables:, options:)
|
9
|
-
@jobs = jobs
|
10
|
-
@executables = executables
|
11
|
-
@options = options
|
12
|
-
@name_length = jobs.map { |j| j.name.size }.max
|
13
|
-
end
|
14
|
-
|
15
|
-
def start_warming
|
16
|
-
$stdout.print 'warming up...'
|
17
|
-
end
|
18
|
-
|
19
|
-
# @param [String] name
|
20
|
-
def warming(name)
|
21
|
-
# noop
|
22
|
-
end
|
23
|
-
|
24
|
-
# @param [Benchmark::Driver::BenchmarkResult] result
|
25
|
-
def warmup_stats(result)
|
26
|
-
$stdout.print '.'
|
27
|
-
end
|
28
|
-
|
29
|
-
def start_running
|
30
|
-
$stdout.puts if @jobs.any?(&:warmup_needed?)
|
31
|
-
$stdout.puts 'max resident memory (KB):'
|
32
|
-
$stdout.print("%-#{@name_length}s " % 'ruby')
|
33
|
-
@executables.each do |executable|
|
34
|
-
$stdout.print('%-6s ' % executable.name)
|
35
|
-
end
|
36
|
-
$stdout.puts
|
37
|
-
end
|
38
|
-
|
39
|
-
# @param [String] name
|
40
|
-
def running(name)
|
41
|
-
$stdout.print("%-#{@name_length}s " % name)
|
42
|
-
@ran_num = 0
|
43
|
-
end
|
44
|
-
|
45
|
-
# @param [Benchmark::Driver::BenchmarkResult] result
|
46
|
-
def benchmark_stats(result)
|
47
|
-
$stdout.print('%-6d ' % result.max_rss)
|
48
|
-
@ran_num += 1
|
49
|
-
if @ran_num == @executables.size
|
50
|
-
$stdout.puts
|
51
|
-
end
|
52
|
-
end
|
53
|
-
|
54
|
-
def finish
|
55
|
-
# compare is not implemented yet
|
56
|
-
end
|
57
|
-
end
|
@@ -1,57 +0,0 @@
|
|
1
|
-
class Benchmark::Output::Time
|
2
|
-
# This class requires runner to measure following fields in `Benchmark::Driver::BenchmarkResult` to show output.
|
3
|
-
REQUIRED_FIELDS = [:real]
|
4
|
-
|
5
|
-
# @param [Array<Benchmark::Driver::Configuration::Job>] jobs
|
6
|
-
# @param [Array<Benchmark::Driver::Configuration::Executable>] executables
|
7
|
-
# @param [Benchmark::Driver::Configuration::OutputOptions] options
|
8
|
-
def initialize(jobs:, executables:, options:)
|
9
|
-
@jobs = jobs
|
10
|
-
@executables = executables
|
11
|
-
@options = options
|
12
|
-
@name_length = jobs.map { |j| j.name.size }.max
|
13
|
-
end
|
14
|
-
|
15
|
-
def start_warming
|
16
|
-
$stdout.print 'warming up...'
|
17
|
-
end
|
18
|
-
|
19
|
-
# @param [String] name
|
20
|
-
def warming(name)
|
21
|
-
# noop
|
22
|
-
end
|
23
|
-
|
24
|
-
# @param [Benchmark::Driver::BenchmarkResult] result
|
25
|
-
def warmup_stats(result)
|
26
|
-
$stdout.print '.'
|
27
|
-
end
|
28
|
-
|
29
|
-
def start_running
|
30
|
-
$stdout.puts if @jobs.any?(&:warmup_needed?)
|
31
|
-
$stdout.puts 'benchmark results (s):'
|
32
|
-
$stdout.print("%-#{@name_length}s " % 'ruby')
|
33
|
-
@executables.each do |executable|
|
34
|
-
$stdout.print('%-6s ' % executable.name)
|
35
|
-
end
|
36
|
-
$stdout.puts
|
37
|
-
end
|
38
|
-
|
39
|
-
# @param [String] name
|
40
|
-
def running(name)
|
41
|
-
$stdout.print("%-#{@name_length}s " % name)
|
42
|
-
@ran_num = 0
|
43
|
-
end
|
44
|
-
|
45
|
-
# @param [Benchmark::Driver::BenchmarkResult] result
|
46
|
-
def benchmark_stats(result)
|
47
|
-
$stdout.print('%-6.3f ' % result.real)
|
48
|
-
@ran_num += 1
|
49
|
-
if @ran_num == @executables.size
|
50
|
-
$stdout.puts
|
51
|
-
end
|
52
|
-
end
|
53
|
-
|
54
|
-
def finish
|
55
|
-
# compare is not implemented yet
|
56
|
-
end
|
57
|
-
end
|
data/lib/benchmark/runner.rb
DELETED
@@ -1,14 +0,0 @@
|
|
1
|
-
module Benchmark::Runner
|
2
|
-
# Benchmark::Runner is pluggable.
|
3
|
-
# Create `Benchmark::Runner::FooBar` as benchmark-runner-foo_bar.gem and specify `runner: foo_bar`.
|
4
|
-
#
|
5
|
-
# @param [Symbol] name
|
6
|
-
def self.find(name)
|
7
|
-
class_name = Benchmark::Driver::Configuration.camelize(name.to_s)
|
8
|
-
Benchmark::Runner.const_get(class_name, false)
|
9
|
-
end
|
10
|
-
end
|
11
|
-
|
12
|
-
require 'benchmark/runner/call'
|
13
|
-
require 'benchmark/runner/eval'
|
14
|
-
require 'benchmark/runner/exec'
|
@@ -1,97 +0,0 @@
|
|
1
|
-
require 'benchmark/driver/benchmark_result'
|
2
|
-
require 'benchmark/driver/duration_runner'
|
3
|
-
require 'benchmark/driver/repeatable_runner'
|
4
|
-
require 'benchmark/driver/time'
|
5
|
-
|
6
|
-
# Run benchmark by calling #call on running ruby.
|
7
|
-
#
|
8
|
-
# Multiple Ruby binaries: x
|
9
|
-
# Memory output: x
|
10
|
-
class Benchmark::Runner::Call
|
11
|
-
# This class can provide fields in `Benchmark::Driver::BenchmarkResult` if required by output plugins.
|
12
|
-
SUPPORTED_FIELDS = [:real]
|
13
|
-
|
14
|
-
WARMUP_DURATION = 2
|
15
|
-
BENCHMARK_DURATION = 5
|
16
|
-
|
17
|
-
# @param [Benchmark::Driver::Configuration::RunnerOptions] options
|
18
|
-
# @param [Benchmark::Output::*] output - Object that responds to methods used in this class
|
19
|
-
def initialize(options, output:)
|
20
|
-
@options = options
|
21
|
-
@output = output
|
22
|
-
end
|
23
|
-
|
24
|
-
# @param [Benchmark::Driver::Configuration] config
|
25
|
-
def run(config)
|
26
|
-
validate_config(config)
|
27
|
-
|
28
|
-
if config.jobs.any?(&:warmup_needed?)
|
29
|
-
run_warmup(config.jobs)
|
30
|
-
end
|
31
|
-
|
32
|
-
@output.start_running
|
33
|
-
|
34
|
-
config.jobs.each do |job|
|
35
|
-
@output.running(job.name)
|
36
|
-
|
37
|
-
result = Benchmark::Driver::RepeatableRunner.new(job).run(
|
38
|
-
runner: method(:call_times),
|
39
|
-
repeat_count: @options.repeat_count,
|
40
|
-
)
|
41
|
-
|
42
|
-
@output.benchmark_stats(result)
|
43
|
-
end
|
44
|
-
|
45
|
-
@output.finish
|
46
|
-
end
|
47
|
-
|
48
|
-
private
|
49
|
-
|
50
|
-
def validate_config(config)
|
51
|
-
if config.runner_options.executables_specified?
|
52
|
-
raise ArgumentError.new("Benchmark::Runner::Call can't run other Ruby executables")
|
53
|
-
end
|
54
|
-
|
55
|
-
config.jobs.each do |job|
|
56
|
-
unless job.script.respond_to?(:call)
|
57
|
-
raise NotImplementedError.new(
|
58
|
-
"#{self.class.name} only accepts objects that respond to :call, but got #{job.script.inspect}"
|
59
|
-
)
|
60
|
-
end
|
61
|
-
end
|
62
|
-
end
|
63
|
-
|
64
|
-
# @param [Array<Benchmark::Driver::Configuration::Job>] jobs
|
65
|
-
# @return [Hash{ Benchmark::Driver::Configuration::Job => Integer }] iters_by_job
|
66
|
-
def run_warmup(jobs)
|
67
|
-
@output.start_warming
|
68
|
-
|
69
|
-
jobs.each do |job|
|
70
|
-
next if job.loop_count
|
71
|
-
@output.warming(job.name)
|
72
|
-
|
73
|
-
result = Benchmark::Driver::DurationRunner.new(job).run(
|
74
|
-
seconds: WARMUP_DURATION,
|
75
|
-
unit_iters: 1,
|
76
|
-
runner: method(:call_times),
|
77
|
-
)
|
78
|
-
job.guessed_count = (result.ips.to_f * BENCHMARK_DURATION).to_i
|
79
|
-
|
80
|
-
@output.warmup_stats(result)
|
81
|
-
end
|
82
|
-
end
|
83
|
-
|
84
|
-
def call_times(job, times)
|
85
|
-
script = job.script
|
86
|
-
i = 0
|
87
|
-
|
88
|
-
before = Benchmark::Driver::Time.now
|
89
|
-
while i < times
|
90
|
-
script.call
|
91
|
-
i += 1
|
92
|
-
end
|
93
|
-
after = Benchmark::Driver::Time.now
|
94
|
-
|
95
|
-
after.to_f - before.to_f
|
96
|
-
end
|
97
|
-
end
|
@@ -1,147 +0,0 @@
|
|
1
|
-
require 'benchmark/driver/benchmark_result'
|
2
|
-
require 'benchmark/driver/duration_runner'
|
3
|
-
require 'benchmark/driver/repeatable_runner'
|
4
|
-
require 'benchmark/driver/time'
|
5
|
-
|
6
|
-
# Run benchmark by calling compiled script on running ruby.
|
7
|
-
#
|
8
|
-
# Multiple Ruby binaries: x
|
9
|
-
# Memory output: x
|
10
|
-
class Benchmark::Runner::Eval
|
11
|
-
# This class can provide fields in `Benchmark::Driver::BenchmarkResult` if required by output plugins.
|
12
|
-
SUPPORTED_FIELDS = [:real]
|
13
|
-
|
14
|
-
WARMUP_DURATION = 2
|
15
|
-
BENCHMARK_DURATION = 5
|
16
|
-
GUESS_TIMES = [1, 1_000, 1_000_000, 10_000_000, 100_000_000]
|
17
|
-
GUESS_THRESHOLD = 0.4 # 400ms
|
18
|
-
|
19
|
-
# @param [Benchmark::Driver::Configuration::RunnerOptions] options
|
20
|
-
# @param [Benchmark::Output::*] output - Object that responds to methods used in this class
|
21
|
-
def initialize(options, output:)
|
22
|
-
@options = options
|
23
|
-
@output = output
|
24
|
-
end
|
25
|
-
|
26
|
-
# @param [Benchmark::Driver::Configuration] config
|
27
|
-
def run(config)
|
28
|
-
validate_config(config)
|
29
|
-
|
30
|
-
if config.jobs.any?(&:warmup_needed?)
|
31
|
-
run_warmup(config.jobs)
|
32
|
-
end
|
33
|
-
|
34
|
-
@output.start_running
|
35
|
-
|
36
|
-
config.jobs.each do |job|
|
37
|
-
@output.running(job.name)
|
38
|
-
|
39
|
-
result = Benchmark::Driver::RepeatableRunner.new(job).run(
|
40
|
-
runner: method(:eval_times),
|
41
|
-
repeat_count: @options.repeat_count,
|
42
|
-
)
|
43
|
-
|
44
|
-
@output.benchmark_stats(result)
|
45
|
-
end
|
46
|
-
|
47
|
-
@output.finish
|
48
|
-
end
|
49
|
-
|
50
|
-
private
|
51
|
-
|
52
|
-
def validate_config(config)
|
53
|
-
if config.runner_options.executables_specified?
|
54
|
-
raise ArgumentError.new("#{self.class.name} can't run other Ruby executables")
|
55
|
-
end
|
56
|
-
|
57
|
-
config.jobs.each do |job|
|
58
|
-
unless job.script.is_a?(String)
|
59
|
-
raise NotImplementedError.new(
|
60
|
-
"#{self.class.name} only accepts String, but got #{job.script.inspect}"
|
61
|
-
)
|
62
|
-
end
|
63
|
-
end
|
64
|
-
end
|
65
|
-
|
66
|
-
# @param [Array<Benchmark::Driver::Configuration::Job>] jobs
|
67
|
-
# @return [Hash{ Benchmark::Driver::Configuration::Job => Integer }] iters_by_job
|
68
|
-
def run_warmup(jobs)
|
69
|
-
@output.start_warming
|
70
|
-
|
71
|
-
jobs.each do |job|
|
72
|
-
next if job.loop_count
|
73
|
-
@output.warming(job.name)
|
74
|
-
|
75
|
-
result = Benchmark::Driver::DurationRunner.new(job).run(
|
76
|
-
seconds: WARMUP_DURATION,
|
77
|
-
unit_iters: guess_ip100ms(job),
|
78
|
-
runner: method(:eval_times),
|
79
|
-
)
|
80
|
-
job.guessed_count = (result.ips.to_f * BENCHMARK_DURATION).to_i
|
81
|
-
|
82
|
-
@output.warmup_stats(result)
|
83
|
-
end
|
84
|
-
end
|
85
|
-
|
86
|
-
# @param [Benchmark::Driver::Configuration::Job] job
|
87
|
-
def guess_ip100ms(job)
|
88
|
-
ip100ms = 0
|
89
|
-
GUESS_TIMES.each do |times|
|
90
|
-
seconds = eval_times(job, times)
|
91
|
-
ip100ms = (times.to_f / (seconds * 10.0)).ceil # ceil for times=1
|
92
|
-
if GUESS_THRESHOLD < seconds
|
93
|
-
return ip100ms
|
94
|
-
end
|
95
|
-
end
|
96
|
-
if ip100ms < 0
|
97
|
-
raise Benchmark::Driver::ExecutionTimeTooShort.new(job, GUESS_TIMES.last)
|
98
|
-
end
|
99
|
-
ip100ms
|
100
|
-
end
|
101
|
-
|
102
|
-
def eval_times(job, times)
|
103
|
-
benchmark = BenchmarkScript.new(job.prelude, job.script)
|
104
|
-
overhead = benchmark.overhead(times)
|
105
|
-
full_script = benchmark.full_script(times)
|
106
|
-
|
107
|
-
before = Benchmark::Driver::Time.now
|
108
|
-
eval(overhead, TOPLEVEL_BINDING)
|
109
|
-
after = Benchmark::Driver::Time.now
|
110
|
-
overhead_duration = after.to_f - before.to_f
|
111
|
-
|
112
|
-
before = Benchmark::Driver::Time.now
|
113
|
-
eval(full_script, TOPLEVEL_BINDING)
|
114
|
-
after = Benchmark::Driver::Time.now
|
115
|
-
full_script_duration = after.to_f - before.to_f
|
116
|
-
|
117
|
-
full_script_duration - overhead_duration
|
118
|
-
end
|
119
|
-
|
120
|
-
class BenchmarkScript < Struct.new(:prelude, :script)
|
121
|
-
BATCH_SIZE = 1000
|
122
|
-
|
123
|
-
def overhead(times)
|
124
|
-
raise ArgumentError.new("Negative times: #{times}") if times < 0
|
125
|
-
<<-RUBY
|
126
|
-
#{prelude}
|
127
|
-
__benchmark_driver_i = 0
|
128
|
-
while __benchmark_driver_i < #{times / BATCH_SIZE}
|
129
|
-
__benchmark_driver_i += 1
|
130
|
-
end
|
131
|
-
RUBY
|
132
|
-
end
|
133
|
-
|
134
|
-
def full_script(times)
|
135
|
-
raise ArgumentError.new("Negative times: #{times}") if times < 0
|
136
|
-
<<-RUBY
|
137
|
-
#{prelude}
|
138
|
-
__benchmark_driver_i = 0
|
139
|
-
while __benchmark_driver_i < #{times / BATCH_SIZE}
|
140
|
-
__benchmark_driver_i += 1
|
141
|
-
#{"#{script};" * BATCH_SIZE}
|
142
|
-
end
|
143
|
-
#{"#{script};" * (times % BATCH_SIZE)}
|
144
|
-
RUBY
|
145
|
-
end
|
146
|
-
end
|
147
|
-
end
|