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
@@ -0,0 +1,18 @@
1
+ require 'benchmark_driver/runner/ips'
2
+
3
+ class BenchmarkDriver::Runner::Time < BenchmarkDriver::Runner::Ips
4
+ # JobParser returns this, `BenchmarkDriver::Runner.runner_for` searches "*::Job"
5
+ Job = Class.new(BenchmarkDriver::DefaultJob)
6
+ # Dynamically fetched and used by `BenchmarkDriver::JobParser.parse`
7
+ JobParser = BenchmarkDriver::DefaultJobParser.for(Job)
8
+ # Passed to `output` by `BenchmarkDriver::Runner.run`
9
+ MetricsType = BenchmarkDriver::Metrics::Type.new(unit: 's')
10
+
11
+ # Overriding BenchmarkDriver::Runner::Ips#build_metrics
12
+ def build_metrics(duration:, executable:, loop_count:)
13
+ BenchmarkDriver::Metrics.new(
14
+ value: duration,
15
+ executable: executable,
16
+ )
17
+ end
18
+ end
@@ -0,0 +1,85 @@
1
+ # Extended Struct with:
2
+ # * Polyfilled `keyword_init: true`
3
+ # * Default value configuration
4
+ # * Deeply freezing members
5
+ module BenchmarkDriver
6
+ class << Struct = Module.new
7
+ # @param [Array<Symbol>] args
8
+ # @param [Hash{ Symbol => Object }] defaults
9
+ def new(*args, defaults: {}, &block)
10
+ # Polyfill `keyword_init: true`
11
+ if Gem::Version.new(RUBY_VERSION) >= Gem::Version.new('2.5.0')
12
+ klass = ::Struct.new(*args, keyword_init: true, &block)
13
+ else
14
+ klass = keyword_init_struct(*args, &block)
15
+ end
16
+
17
+ # Default value config
18
+ configure_defaults(klass, defaults)
19
+
20
+ # Force deeply freezing members
21
+ force_deep_freeze(klass)
22
+
23
+ klass
24
+ end
25
+
26
+ private
27
+
28
+ # Polyfill for Ruby < 2.5.0
29
+ def keyword_init_struct(*args, &block)
30
+ ::Struct.new(*args).tap do |klass|
31
+ klass.prepend(Module.new {
32
+ # @param [Hash{ Symbol => Object }] args
33
+ def initialize(**args)
34
+ args.each do |key, value|
35
+ unless members.include?(key)
36
+ raise ArgumentError.new("unknwon keywords: #{key}")
37
+ next
38
+ end
39
+
40
+ public_send("#{key}=", value)
41
+ end
42
+ end
43
+ })
44
+ klass.prepend(Module.new(&block))
45
+ end
46
+ end
47
+
48
+ def configure_defaults(klass, defaults)
49
+ class << klass
50
+ attr_accessor :defaults
51
+ end
52
+ klass.defaults = defaults
53
+
54
+ klass.prepend(Module.new {
55
+ def initialize(**)
56
+ super
57
+ self.class.defaults.each do |key, value|
58
+ if public_send(key).nil?
59
+ public_send("#{key}=", value)
60
+ end
61
+ end
62
+ end
63
+ })
64
+
65
+ def klass.inherited(child)
66
+ child.defaults = self.defaults
67
+ end
68
+ end
69
+
70
+ def force_deep_freeze(klass)
71
+ klass.class_eval do
72
+ def freeze
73
+ members.each do |member|
74
+ value = public_send(member)
75
+ if value.is_a?(Array)
76
+ value.each(&:freeze)
77
+ end
78
+ value.freeze
79
+ end
80
+ super
81
+ end
82
+ end
83
+ end
84
+ end
85
+ end
@@ -0,0 +1,3 @@
1
+ module BenchmarkDriver
2
+ VERSION = '0.9.0'
3
+ end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: benchmark_driver
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.8.6
4
+ version: 0.9.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Takashi Kokubun
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2018-01-28 00:00:00.000000000 Z
11
+ date: 2018-02-24 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler
@@ -54,16 +54,8 @@ files:
54
54
  - README.md
55
55
  - Rakefile
56
56
  - benchmark_driver.gemspec
57
- - bin/bench
58
57
  - bin/console
59
58
  - bin/setup
60
- - examples/call.rb
61
- - examples/call_blank.rb
62
- - examples/call_erb.rb
63
- - examples/call_interpolation.rb
64
- - examples/eval_blank.rb
65
- - examples/eval_blank_loop.rb
66
- - examples/eval_interpolation.rb
67
59
  - examples/exec_blank.rb
68
60
  - examples/exec_blank_simple.rb
69
61
  - examples/yaml/array_duration_time.yml
@@ -76,28 +68,24 @@ files:
76
68
  - examples/yaml/example_multi.yml
77
69
  - examples/yaml/example_single.yml
78
70
  - exe/benchmark-driver
79
- - lib/benchmark/driver.rb
80
- - lib/benchmark/driver/benchmark_result.rb
81
- - lib/benchmark/driver/bundle_installer.rb
82
- - lib/benchmark/driver/bundler.rb
83
- - lib/benchmark/driver/configuration.rb
84
- - lib/benchmark/driver/duration_runner.rb
85
- - lib/benchmark/driver/error.rb
86
- - lib/benchmark/driver/repeatable_runner.rb
87
- - lib/benchmark/driver/ruby_dsl_parser.rb
88
- - lib/benchmark/driver/time.rb
89
- - lib/benchmark/driver/version.rb
90
- - lib/benchmark/driver/yaml_parser.rb
91
- - lib/benchmark/output.rb
92
- - lib/benchmark/output/ips.rb
93
- - lib/benchmark/output/markdown.rb
94
- - lib/benchmark/output/memory.rb
95
- - lib/benchmark/output/time.rb
96
- - lib/benchmark/runner.rb
97
- - lib/benchmark/runner/call.rb
98
- - lib/benchmark/runner/eval.rb
99
- - lib/benchmark/runner/exec.rb
100
71
  - lib/benchmark_driver.rb
72
+ - lib/benchmark_driver/config.rb
73
+ - lib/benchmark_driver/default_job.rb
74
+ - lib/benchmark_driver/default_job_parser.rb
75
+ - lib/benchmark_driver/job_parser.rb
76
+ - lib/benchmark_driver/metrics.rb
77
+ - lib/benchmark_driver/output.rb
78
+ - lib/benchmark_driver/output/compare.rb
79
+ - lib/benchmark_driver/output/markdown.rb
80
+ - lib/benchmark_driver/output/simple.rb
81
+ - lib/benchmark_driver/rbenv.rb
82
+ - lib/benchmark_driver/ruby_interface.rb
83
+ - lib/benchmark_driver/runner.rb
84
+ - lib/benchmark_driver/runner/ips.rb
85
+ - lib/benchmark_driver/runner/memory.rb
86
+ - lib/benchmark_driver/runner/time.rb
87
+ - lib/benchmark_driver/struct.rb
88
+ - lib/benchmark_driver/version.rb
101
89
  homepage: https://github.com/k0kubun/benchmark_driver
102
90
  licenses:
103
91
  - MIT
@@ -110,7 +98,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
110
98
  requirements:
111
99
  - - ">="
112
100
  - !ruby/object:Gem::Version
113
- version: '0'
101
+ version: 2.1.0
114
102
  required_rubygems_version: !ruby/object:Gem::Requirement
115
103
  requirements:
116
104
  - - ">="
@@ -118,7 +106,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
118
106
  version: '0'
119
107
  requirements: []
120
108
  rubyforge_project:
121
- rubygems_version: 2.7.3
109
+ rubygems_version: 2.6.13
122
110
  signing_key:
123
111
  specification_version: 4
124
112
  summary: Fully-featured accurate benchmark driver for Ruby
data/bin/bench DELETED
@@ -1,4 +0,0 @@
1
- #!/bin/bash
2
- exec bundle exec exe/benchmark-driver \
3
- --compare \
4
- $@
data/examples/call.rb DELETED
@@ -1,12 +0,0 @@
1
- require 'benchmark/driver'
2
-
3
- Benchmark.driver do |x|
4
- large_a = "Hellooooooooooooooooooooooooooooooooooooooooooooooooooo"
5
- large_b = "Wooooooooooooooooooooooooooooooooooooooooooooooooooorld"
6
-
7
- small_a = "Hello"
8
- small_b = "World"
9
-
10
- x.report('large') { "#{large_a}, #{large_b}!" }
11
- x.report('small') { "#{small_a}, #{small_b}!" }
12
- end
@@ -1,13 +0,0 @@
1
- require 'benchmark/driver'
2
-
3
- class Array
4
- alias_method :blank?, :empty?
5
- end
6
-
7
- Benchmark.driver(runner: :call) do |x|
8
- array = []
9
-
10
- x.report('array.empty?') { array.empty? }
11
- x.report('array.blank?') { array.blank? }
12
- x.compare!
13
- end
data/examples/call_erb.rb DELETED
@@ -1,33 +0,0 @@
1
- require 'benchmark/driver'
2
- require 'erb'
3
- require 'erubi'
4
- require 'erubis'
5
-
6
- data = DATA.read
7
-
8
- mod = Module.new
9
- mod.instance_eval("def self.erb(title, content); #{ERB.new(data).src}; end", "(ERB)")
10
- mod.instance_eval("def self.erubis(title, content); #{Erubi::Engine.new(data).src}; end", "(Erubi)")
11
- mod.instance_eval("def self.erubi(title, content); #{Erubis::Eruby.new(data).src}; end", "(Erubis)")
12
-
13
- title = "hello world!"
14
- content = "hello world!\n" * 10
15
-
16
- Benchmark.driver do |x|
17
- x.report("ERB #{RUBY_VERSION}") { mod.erb(title, content) }
18
- x.report("Erubis #{Erubis::VERSION}") { mod.erubis(title, content) }
19
- x.report("Erubi #{Erubi::VERSION}") { mod.erubi(title, content) }
20
- x.compare!
21
- end
22
-
23
- __END__
24
-
25
- <html>
26
- <head> <%= title %> </head>
27
- <body>
28
- <h1> <%= title %> </h1>
29
- <p>
30
- <%= content %>
31
- </p>
32
- </body>
33
- </html>
@@ -1,13 +0,0 @@
1
- require 'benchmark/driver'
2
-
3
- Benchmark.driver do |x|
4
- large_a = "Hellooooooooooooooooooooooooooooooooooooooooooooooooooo"
5
- large_b = "Wooooooooooooooooooooooooooooooooooooooooooooooooooorld"
6
-
7
- small_a = "Hello"
8
- small_b = "World"
9
-
10
- x.report('large') { "#{large_a}, #{large_b}!" }
11
- x.report('small') { "#{small_a}, #{small_b}!" }
12
- x.compare!
13
- end
@@ -1,12 +0,0 @@
1
- require 'benchmark/driver'
2
-
3
- class Array
4
- alias_method :blank?, :empty?
5
- end
6
-
7
- Benchmark.driver(runner: :eval) do |x|
8
- x.prelude %{ array = [] }
9
- x.report 'Array#empty?', %{ array.empty? }
10
- x.report 'Array#blank?', %{ array.blank? }
11
- x.compare!
12
- end
@@ -1,13 +0,0 @@
1
- require 'benchmark/driver'
2
-
3
- class Array
4
- alias_method :blank?, :empty?
5
- end
6
-
7
- Benchmark.driver do |x|
8
- x.prelude %{ array = [] }
9
- x.report 'Array#empty?', %{ array.empty? }
10
- x.report 'Array#blank?', %{ array.blank? }
11
- x.loop_count 10000000
12
- x.compare!
13
- end
@@ -1,15 +0,0 @@
1
- require 'benchmark/driver'
2
-
3
- Benchmark.driver do |x|
4
- x.prelude <<-EOS
5
- large_a = "Hellooooooooooooooooooooooooooooooooooooooooooooooooooo"
6
- large_b = "Wooooooooooooooooooooooooooooooooooooooooooooooooooorld"
7
-
8
- small_a = "Hello"
9
- small_b = "World"
10
- EOS
11
-
12
- x.report('large', '"#{large_a}, #{large_b}!"')
13
- x.report('small', '"#{small_a}, #{small_b}!"')
14
- x.compare!
15
- end
@@ -1,101 +0,0 @@
1
- module Benchmark
2
- # RubyDriver entrypoint.
3
- def self.driver(*args, &block)
4
- dsl = Driver::RubyDslParser.new(*args)
5
- block.call(dsl)
6
-
7
- Driver.run(dsl.configuration)
8
- end
9
-
10
- module Driver
11
- class InvalidConfig < StandardError; end
12
-
13
- class << self
14
- # Main function which is used by both RubyDriver and YamlDriver.
15
- # @param [Benchmark::Driver::Configuration] config
16
- def run(config)
17
- validate_config(config)
18
- if config.runner_options.type.nil?
19
- config.runner_options.type = runner_type_for(config)
20
- end
21
-
22
- if config.runner_options.bundler
23
- config.runner_options.executables.each do |executable|
24
- Benchmark::Driver::BundleInstaller.bundle_install_for(executable)
25
- executable.command << '-rbundler/setup'
26
- end
27
- end
28
-
29
- runner_class = Runner.find(config.runner_options.type)
30
- output_class = Output.find(config.output_options.type)
31
-
32
- missing_fields = output_class::REQUIRED_FIELDS - runner_class::SUPPORTED_FIELDS
33
- unless missing_fields.empty?
34
- raise ArgumentError.new(
35
- "#{output_class.name} requires #{missing_fields.inspect} fields "\
36
- "which are not supported by #{runner_class.name}. Try using another runner."
37
- )
38
- end
39
-
40
- without_stdout_buffering do
41
- runner = runner_class.new(
42
- config.runner_options,
43
- output: output_class.new(
44
- jobs: config.jobs,
45
- executables: config.runner_options.executables,
46
- options: config.output_options,
47
- ),
48
- )
49
- runner.run(config)
50
- end
51
- rescue Benchmark::Driver::Error => e
52
- $stderr.puts "\n\nFailed to execute benchmark!\n\n#{e.class.name}:\n #{e.message}"
53
- exit 1
54
- end
55
-
56
- private
57
-
58
- def validate_config(config)
59
- if config.jobs.empty?
60
- raise InvalidConfig.new('No benchmark script is specified')
61
- end
62
-
63
- script_class = config.jobs.first.script.class
64
- unless config.jobs.all? { |j| j.script.is_a?(script_class) }
65
- raise InvalidConfig.new('Benchmark scripts include both String and Proc. Only either of them should be specified.')
66
- end
67
-
68
- # TODO: invalidate prelude for call runner
69
- end
70
-
71
- def runner_type_for(config)
72
- script_class = config.jobs.first.script.class
73
- if script_class == Proc
74
- :call
75
- elsif config.runner_options.executables_specified?
76
- :exec
77
- else
78
- :eval
79
- end
80
- end
81
-
82
- # benchmark_driver ouputs logs ASAP. This enables sync flag for it.
83
- #
84
- # Currently benchmark_driver supports only output to stdout.
85
- # In future exetension, this may be included in Output plugins.
86
- def without_stdout_buffering
87
- sync, $stdout.sync = $stdout.sync, true
88
- yield
89
- ensure
90
- $stdout.sync = sync
91
- end
92
- end
93
- end
94
- end
95
-
96
- require 'benchmark/output'
97
- require 'benchmark/runner'
98
- require 'benchmark/driver/bundle_installer'
99
- require 'benchmark/driver/error'
100
- require 'benchmark/driver/ruby_dsl_parser'
101
- require 'benchmark/driver/version'
@@ -1,21 +0,0 @@
1
- # @param [Benchmark::Driver::Configuration::Job] job
2
- # @param [Integer] iterations - Executed iterations of benchmark script in the job
3
- # @param [Float] real - Real time taken by the job
4
- # @param [Integer] max_rss - Maximum resident set size of the process during its lifetime, in Kilobytes.
5
- class Benchmark::Driver::BenchmarkResult < Struct.new(:job, :iterations, :real, :max_rss)
6
- alias :duration :real
7
-
8
- def ips
9
- iterations / real
10
- end
11
-
12
- def ip100ms
13
- ips / 10
14
- end
15
-
16
- def iterations
17
- # runner's warmup uses `result.ips` to calculate `job.loop_count`, and thus
18
- # at that moment `job.loop_count` isn't available and we need to use `super`.
19
- super || job.loop_count
20
- end
21
- end