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.
Files changed (58) hide show
  1. checksums.yaml +5 -5
  2. data/.travis.yml +1 -3
  3. data/CHANGELOG.md +9 -0
  4. data/Gemfile +1 -6
  5. data/README.md +51 -52
  6. data/benchmark_driver.gemspec +3 -2
  7. data/bin/console +4 -11
  8. data/examples/exec_blank.rb +2 -2
  9. data/examples/exec_blank_simple.rb +2 -3
  10. data/exe/benchmark-driver +74 -83
  11. data/lib/benchmark_driver.rb +12 -1
  12. data/lib/benchmark_driver/config.rb +36 -0
  13. data/lib/benchmark_driver/default_job.rb +12 -0
  14. data/lib/benchmark_driver/default_job_parser.rb +68 -0
  15. data/lib/benchmark_driver/job_parser.rb +42 -0
  16. data/lib/benchmark_driver/metrics.rb +17 -0
  17. data/lib/benchmark_driver/output.rb +27 -0
  18. data/lib/benchmark_driver/output/compare.rb +196 -0
  19. data/lib/benchmark_driver/output/markdown.rb +102 -0
  20. data/lib/benchmark_driver/output/simple.rb +97 -0
  21. data/lib/benchmark_driver/rbenv.rb +11 -0
  22. data/lib/benchmark_driver/ruby_interface.rb +51 -0
  23. data/lib/benchmark_driver/runner.rb +42 -0
  24. data/lib/benchmark_driver/runner/ips.rb +239 -0
  25. data/lib/benchmark_driver/runner/memory.rb +142 -0
  26. data/lib/benchmark_driver/runner/time.rb +18 -0
  27. data/lib/benchmark_driver/struct.rb +85 -0
  28. data/lib/benchmark_driver/version.rb +3 -0
  29. metadata +21 -33
  30. data/bin/bench +0 -4
  31. data/examples/call.rb +0 -12
  32. data/examples/call_blank.rb +0 -13
  33. data/examples/call_erb.rb +0 -33
  34. data/examples/call_interpolation.rb +0 -13
  35. data/examples/eval_blank.rb +0 -12
  36. data/examples/eval_blank_loop.rb +0 -13
  37. data/examples/eval_interpolation.rb +0 -15
  38. data/lib/benchmark/driver.rb +0 -101
  39. data/lib/benchmark/driver/benchmark_result.rb +0 -21
  40. data/lib/benchmark/driver/bundle_installer.rb +0 -45
  41. data/lib/benchmark/driver/bundler.rb +0 -12
  42. data/lib/benchmark/driver/configuration.rb +0 -77
  43. data/lib/benchmark/driver/duration_runner.rb +0 -24
  44. data/lib/benchmark/driver/error.rb +0 -16
  45. data/lib/benchmark/driver/repeatable_runner.rb +0 -18
  46. data/lib/benchmark/driver/ruby_dsl_parser.rb +0 -78
  47. data/lib/benchmark/driver/time.rb +0 -12
  48. data/lib/benchmark/driver/version.rb +0 -5
  49. data/lib/benchmark/driver/yaml_parser.rb +0 -55
  50. data/lib/benchmark/output.rb +0 -20
  51. data/lib/benchmark/output/ips.rb +0 -143
  52. data/lib/benchmark/output/markdown.rb +0 -73
  53. data/lib/benchmark/output/memory.rb +0 -57
  54. data/lib/benchmark/output/time.rb +0 -57
  55. data/lib/benchmark/runner.rb +0 -14
  56. data/lib/benchmark/runner/call.rb +0 -97
  57. data/lib/benchmark/runner/eval.rb +0 -147
  58. 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
@@ -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