benchmark_driver 0.3.0 → 0.4.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 (49) hide show
  1. checksums.yaml +5 -5
  2. data/.gitignore +0 -4
  3. data/.travis.yml +10 -6
  4. data/Gemfile +7 -2
  5. data/Gemfile.lock +30 -0
  6. data/README.md +125 -117
  7. data/Rakefile +14 -7
  8. data/benchmark_driver.gemspec +2 -4
  9. data/bin/console +1 -1
  10. data/examples/call.rb +12 -0
  11. data/examples/call_blank.rb +13 -0
  12. data/examples/call_erb.rb +33 -0
  13. data/examples/call_interpolation.rb +13 -0
  14. data/examples/exec_blank.rb +14 -0
  15. data/examples/exec_interpolation.rb +15 -0
  16. data/examples/yaml/array_duration_time.yml +3 -0
  17. data/examples/yaml/array_loop.yml +3 -0
  18. data/examples/yaml/array_loop_memory.yml +6 -0
  19. data/examples/yaml/array_loop_time.yml +4 -0
  20. data/examples/yaml/blank_hash.yml +8 -0
  21. data/examples/yaml/blank_hash_array.yml +10 -0
  22. data/examples/yaml/blank_loop.yml +9 -0
  23. data/examples/yaml/blank_loop_time.yml +10 -0
  24. data/examples/yaml/blank_string.yml +6 -0
  25. data/examples/yaml/blank_string_array.yml +8 -0
  26. data/examples/yaml/example_multi.yml +6 -0
  27. data/{benchmarks → examples/yaml}/example_single.yml +0 -0
  28. data/exe/benchmark-driver +44 -18
  29. data/lib/benchmark/driver.rb +52 -257
  30. data/lib/benchmark/driver/benchmark_result.rb +21 -0
  31. data/lib/benchmark/driver/configuration.rb +65 -0
  32. data/lib/benchmark/driver/duration_runner.rb +24 -0
  33. data/lib/benchmark/driver/error.rb +16 -0
  34. data/lib/benchmark/driver/repeatable_runner.rb +18 -0
  35. data/lib/benchmark/driver/ruby_dsl_parser.rb +57 -0
  36. data/lib/benchmark/driver/time.rb +12 -0
  37. data/lib/benchmark/driver/version.rb +2 -2
  38. data/lib/benchmark/driver/yaml_parser.rb +103 -0
  39. data/lib/benchmark/output.rb +16 -0
  40. data/lib/benchmark/output/ips.rb +114 -0
  41. data/lib/benchmark/output/memory.rb +57 -0
  42. data/lib/benchmark/output/time.rb +57 -0
  43. data/lib/benchmark/runner.rb +13 -0
  44. data/lib/benchmark/runner/call.rb +97 -0
  45. data/lib/benchmark/runner/exec.rb +190 -0
  46. metadata +40 -10
  47. data/benchmarks/core/array.yml +0 -4
  48. data/benchmarks/example_multi.yml +0 -10
  49. data/benchmarks/lib/erb.yml +0 -30
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
- SHA256:
3
- metadata.gz: 95e89d2f7ab5cee3192bf505ab51a848615bee2c2b2f021cd9c41e62d23c641a
4
- data.tar.gz: 3973aae7876002ae741bb6443a5054f3e7a8be4069e4989d61ef2a0b02615766
2
+ SHA1:
3
+ metadata.gz: 771d93093383594ac93a9f3456b646f9ef484578
4
+ data.tar.gz: 41b2b41209e834a8983dad25843188325f8fb009
5
5
  SHA512:
6
- metadata.gz: 546445be415fd833e7f180d853c5b44440f4ca76cf2a77cd5dfbef0d38fba7441aeefa71a99dc3ab97f6d2f7050d293670c70fc520d446228da680041a1d9b75
7
- data.tar.gz: b309b8421f76a5039788556786678d863ed11d85bd891a6ab1bb1ffdf203a96db8d536cb3cc4ff1973b78bdaf296e87464ae00a8dbff6e3537045ffc5e844991
6
+ metadata.gz: 697ed2bab69c631bb9104adae293105b323b7ccb3321c123c85a18f44f5bb5a4e352fc06257b637233d8dbe73cb7ebc19aa63f93c8f53e8b9dbf10daa4c13bf9
7
+ data.tar.gz: ba4fd20c4dc8b506fa2971416446ba86594604c336b0a728aef071d385a3f46e7ea41f34e6061c0ace32bb61412d488fdfd7d2719b39cd2541b9ef8cb3f453c3
data/.gitignore CHANGED
@@ -1,12 +1,8 @@
1
1
  /.bundle/
2
2
  /.yardoc
3
- /Gemfile.lock
4
3
  /_yardoc/
5
4
  /coverage/
6
5
  /doc/
7
6
  /pkg/
8
7
  /spec/reports/
9
8
  /tmp/
10
-
11
- # rspec failure tracking
12
- .rspec_status
data/.travis.yml CHANGED
@@ -1,11 +1,15 @@
1
- sudo: false
2
1
  language: ruby
3
2
  rvm:
3
+ - 2.1.10
4
+ - 2.2.8
5
+ - 2.3.5
4
6
  - 2.4.2
7
+ - ruby-head
8
+ cache: bundler
9
+ branches:
10
+ only:
11
+ - master
5
12
  before_install: gem install bundler -v 1.15.4
6
13
  script:
7
- - bundle exec rake
8
-
9
- # Test some options
10
- - bundle exec exe/benchmark-driver benchmarks/example_single.yml -e ruby1::ruby -e ruby2::ruby -i
11
- - bundle exec exe/benchmark-driver benchmarks/example_single.yml -e ruby1::ruby -e ruby2::ruby -i 2
14
+ - bundle exec rake ruby_examples
15
+ - bundle exec rake yaml_examples
data/Gemfile CHANGED
@@ -1,8 +1,13 @@
1
- source "https://rubygems.org"
1
+ source 'https://rubygems.org'
2
2
 
3
- git_source(:github) { |repo_name| "https://github.com/#{repo_name}" }
3
+ git_source(:github) {|repo_name| "https://github.com/#{repo_name}" }
4
4
 
5
5
  # Specify your gem's dependencies in benchmark_driver.gemspec
6
6
  gemspec
7
7
 
8
+ # For my debugging
8
9
  gem 'pry'
10
+
11
+ # For benchmark examples
12
+ gem 'erubi'
13
+ gem 'erubis'
data/Gemfile.lock ADDED
@@ -0,0 +1,30 @@
1
+ PATH
2
+ remote: .
3
+ specs:
4
+ benchmark_driver (0.4.0)
5
+
6
+ GEM
7
+ remote: https://rubygems.org/
8
+ specs:
9
+ coderay (1.1.2)
10
+ erubi (1.7.0)
11
+ erubis (2.7.0)
12
+ method_source (0.9.0)
13
+ pry (0.11.1)
14
+ coderay (~> 1.1.0)
15
+ method_source (~> 0.9.0)
16
+ rake (12.3.0)
17
+
18
+ PLATFORMS
19
+ ruby
20
+
21
+ DEPENDENCIES
22
+ benchmark_driver!
23
+ bundler
24
+ erubi
25
+ erubis
26
+ pry
27
+ rake
28
+
29
+ BUNDLED WITH
30
+ 1.16.0
data/README.md CHANGED
@@ -1,23 +1,104 @@
1
1
  # Benchmark::Driver [![Build Status](https://travis-ci.org/k0kubun/benchmark_driver.svg?branch=master)](https://travis-ci.org/k0kubun/benchmark_driver)
2
2
 
3
- Benchmark driver for different Ruby executables
3
+ Fully-featured accurate benchmark driver for Ruby
4
+
5
+ ## Project Status
6
+
7
+ **Under Construction**
8
+
9
+ ## Features
10
+ NOTE: Pending ones are ~slashed~.
11
+
12
+ ### Accurate Measurement
13
+
14
+ - Low overhead benchmark by running generated script instead of calling Proc
15
+ - Running multiple times to minimize measurement errors
16
+ - Profiling memory, high-precision real time, ~user time and system time~
17
+
18
+ ### Pluggable & Fully Featured
19
+
20
+ - Flexible and real-time output format in ips, execution time, ~markdown table~, etc.
21
+ - Runner and output are all pluggable
22
+ - ~Integrated benchmark support using external libraries~
23
+
24
+ ### Flexible Interface
25
+
26
+ - Ruby interface similar to benchmark stdlib, benchmark-ips
27
+ - YAML input to easily manage structured benchmark set
28
+ - Comparing multiple Ruby binaries, even with miniruby
4
29
 
5
30
  ## Installation
6
31
 
7
- $ gem install benchmark_driver
32
+ ```
33
+ $ gem install benchmark_driver
34
+ ```
8
35
 
9
36
  ## Usage
10
37
 
38
+ ### Ruby Interface: Compatible Mode
39
+
40
+ This interface is compatible with `Benchmark.bm` and `Benchmark.ips`, so it's good for migration.
41
+
42
+ ```rb
43
+ require 'benchmark/driver'
44
+ require 'active_support/all'
45
+ array = []
46
+
47
+ Benchmark.driver do |x|
48
+ x.report('blank?') { array.blank? }
49
+ x.report('empty?') { array.empty? }
50
+ x.compare!
51
+ end
52
+ ```
53
+
54
+ ### Ruby Interface: Low Overhead Mode
55
+
56
+ This interface generates code to profile with low overhead and executes it.
57
+
58
+ ```rb
59
+ require 'benchmark/driver'
60
+
61
+ Benchmark.driver do |x|
62
+ x.prelude = <<~RUBY
63
+ require 'active_support/all'
64
+ array = []
65
+ RUBY
66
+
67
+ x.report('blank?', script: 'array.blank?')
68
+ x.report('empty?', script: 'array.empty?')
69
+ end
70
+ ```
71
+
72
+ or simply:
73
+
74
+ ```rb
75
+ require 'benchmark/driver'
76
+
77
+ Benchmark.driver do |x|
78
+ x.prelude = <<~RUBY
79
+ require 'active_support/all'
80
+ array = []
81
+ RUBY
82
+
83
+ x.report(script: 'array.blank?')
84
+ x.report(script: 'array.empty?')
85
+ end
86
+ ```
87
+
88
+ ### Structured YAML Input
89
+
90
+ With `benchmark-driver` command, you can describe benchmark with YAML input.
91
+
11
92
  ```
12
93
  $ benchmark-driver -h
13
94
  Usage: benchmark-driver [options] [YAML]
14
95
  -e, --executables [EXECS] Ruby executables (e1::path1; e2::path2; e3::path3;...)
15
- -i, --ips [SECONDS] Measure IPS in duration seconds (default: 1)
16
- -l, --loop-count [COUNT] Measure execution time with loop count (default: 100000)
17
- -v, --verbose
96
+ --rbenv [VERSIONS] Ruby executables in rbenv (2.3.5;2.4.2;...)
97
+ -c, --compare Compare results (currently only supported in ips output)
98
+ -r, --repeat-count [NUM] Try benchmark NUM times and use the fastest result
18
99
  ```
19
100
 
20
- ### Running single script
101
+ #### Running single script
21
102
 
22
103
  With following `example_single.yml`,
23
104
 
@@ -31,31 +112,19 @@ benchmark: erb.result
31
112
  you can benchmark the script with multiple ruby executables.
32
113
 
33
114
  ```
34
- $ benchmark-driver benchmarks/example_single.yml -e ruby1::ruby -e ruby2::ruby
35
- benchmark results:
36
- Execution time (sec)
37
- name ruby1 ruby2
38
- example_single 0.958 0.972
39
-
40
- Speedup ratio: compare with the result of `ruby1' (greater is better)
41
- name ruby2
42
- example_single 0.986
43
- ```
44
-
45
- And you can change benchmark output to IPS (iteration per second) by `-i` option.
115
+ $ exe/benchmark-driver examples/yaml/example_single.yml --rbenv '2.4.2;trunk' --compare
116
+ Warming up --------------------------------------
117
+ erb.result 10.973k i/100ms
118
+ Calculating -------------------------------------
119
+ 2.4.2 trunk
120
+ erb.result 109.268k 123.611k i/s - 548.675k in 4.017080s 4.438720s
46
121
 
47
- ```
48
- $ benchmark-driver benchmarks/example_single.yml -e ruby1::ruby -e ruby2::ruby -i
49
- Result -------------------------------------------
50
- ruby1 ruby2
51
- example_single 99414.1 i/s 99723.3 i/s
52
-
53
- Comparison: example_single
54
- ruby2: 99723.3 i/s
55
- ruby1: 99414.1 i/s - 1.00x slower
122
+ Comparison:
123
+ erb.result (trunk): 123611.1 i/s
124
+ erb.result (2.4.2): 109268.4 i/s - 1.13x slower
56
125
  ```
57
126
 
58
- ### Running multiple scripts
127
+ #### Running multiple scripts
59
128
 
60
129
  One YAML file can contain multiple benchmark scripts.
61
130
  With following `example_multi.yml`,
@@ -64,103 +133,42 @@ With following `example_multi.yml`,
64
133
  prelude: |
65
134
  a = 'a' * 100
66
135
  b = 'b' * 100
67
- benchmarks:
68
- - name: join
69
- benchmark: |
70
- [a, b].join
71
- - name: interpolation
72
- benchmark: |
73
- "#{a}#{b}"
136
+ benchmark:
137
+ join: '[a, b].join'
138
+ str-interp: '"#{a}#{b}"'
74
139
  ```
75
140
 
76
141
  you can benchmark the scripts with multiple ruby executables.
77
142
 
78
143
  ```
79
- $ benchmark-driver benchmarks/example_multi.yml -e ruby1::ruby -e ruby2::ruby
80
- benchmark results:
81
- Execution time (sec)
82
- name ruby1 ruby2
83
- join 0.022 0.022
84
- interpolation 0.026 0.026
85
-
86
- Speedup ratio: compare with the result of `ruby1' (greater is better)
87
- name ruby2
88
- join 1.045
89
- interpolation 1.002
90
- ```
144
+ $ exe/benchmark-driver examples/yaml/example_multi.yml --rbenv '2.4.2;trunk' --compare
145
+ Warming up --------------------------------------
146
+ join 515.787k i/100ms
147
+ str-interp 438.646k i/100ms
148
+ Calculating -------------------------------------
149
+ 2.4.2 trunk
150
+ join 5.200M 4.740M i/s - 20.631M in 3.967750s 4.352565s
151
+ str-interp 4.306M 6.034M i/s - 21.932M in 4.075159s 3.634986s
91
152
 
92
- ```
93
- $ benchmark-driver benchmarks/example_multi.yml -e ruby1::ruby -e ruby2::ruby -i
94
- Result -------------------------------------------
95
- ruby1 ruby2
96
- join 4701954.3 i/s 4639520.3 i/s
97
- interpolation 4263170.0 i/s 4044083.0 i/s
98
-
99
- Comparison: join
100
- ruby1: 4701954.3 i/s
101
- ruby2: 4639520.3 i/s - 1.01x slower
102
-
103
- Comparison: interpolation
104
- ruby1: 4263170.0 i/s
105
- ruby2: 4044083.0 i/s - 1.05x slower
106
- ```
107
-
108
- ### Configuring modes
109
-
110
- There are 2 modes:
111
-
112
- - Loop count: Enabled by `-l`. Optionally you can change count to loop by `-l COUNT`.
113
- - IPS: Enabled by `-i`. Optionally you can change duration by `-i DURATION`.
114
-
115
- Specifying both `-l` and `-i` is nonsense.
116
-
117
- ### YAML syntax
118
- You can specify `benchmark:` or `benchmarks:`.
119
-
120
- #### Single
121
- ```yml
122
- name: String # optional (default: file name)
123
- prelude: String # optional
124
- loop_count: Integer # optional
125
- benchmark: String # required
126
- ```
127
-
128
- #### Multi
129
-
130
- ```yml
131
- prelude: String # optional (shared)
132
- loop_count: Integer # optional (shared)
133
- benchmarks:
134
- - name: String # required
135
- prelude: String # optional (benchmark specific)
136
- loop_count: Integer # optional (benchmark specific)
137
- benchmark: String # required
138
- ```
139
-
140
- ### Debugging
141
-
142
- If you have a trouble like an unexpectedly fast result, you should check benchmark script by `-v`.
143
-
144
- ```
145
- $ benchmark-driver benchmarks/example_multi.yml -v
146
- --- Running "join" with "ruby" 957780 times ---
147
- a = 'a' * 100
148
- b = 'b' * 100
149
-
150
-
151
- i = 0
152
- while i < 957780
153
- i += 1
154
- [a, b].join
155
-
156
- end
153
+ Comparison:
154
+ str-interp (trunk): 6033674.6 i/s
155
+ join (2.4.2): 5199794.6 i/s - 1.16x slower
156
+ join (trunk): 4740075.1 i/s - 1.27x slower
157
+ str-interp (2.4.2): 4305563.1 i/s - 1.40x slower
157
158
  ```
158
159
 
159
160
  ## TODO
160
-
161
- - Measure multiple times and use minimum result
162
- - Retry and reject negative result in ips mode
163
- - Change not to take long time for iteration count estimation in ips mode
161
+ ### Runner
162
+ - [x] Call
163
+ - [x] Exec
164
+ - [ ] Eval
165
+
166
+ ### Output
167
+ - [x] IPS
168
+ - [x] Time
169
+ - [ ] CPU/System/Real Time
170
+ - [ ] Memory
171
+ - [ ] Markdown Table
164
172
 
165
173
  ## Contributing
166
174
 
@@ -168,4 +176,4 @@ Bug reports and pull requests are welcome on GitHub at https://github.com/k0kubu
168
176
 
169
177
  ## License
170
178
 
171
- The gem is available as open source under the terms of the [MIT License](http://opensource.org/licenses/MIT).
179
+ The gem is available as open source under the terms of the [MIT License](https://opensource.org/licenses/MIT).
data/Rakefile CHANGED
@@ -1,15 +1,22 @@
1
1
  require 'bundler/gem_tasks'
2
+ require 'shellwords'
2
3
 
3
- desc 'Run benchmarks in benchmarks'
4
- task :benchmarks do
5
- require 'bundler'
6
- require 'shellwords'
4
+ task :ruby_examples do
5
+ Dir.glob(File.expand_path('./examples/*.rb', __dir__)).sort.each do |file|
6
+ Bundler.with_clean_env do
7
+ sh ['time', 'bundle', 'exec', 'ruby', file].shelljoin
8
+ end
9
+ puts
10
+ end
11
+ end
7
12
 
8
- Dir.glob(File.expand_path('./benchmarks/**/*.yml', __dir__)).sort.each do |path|
13
+ task :yaml_examples do
14
+ Dir.glob(File.expand_path('./examples/yaml/*.yml', __dir__)).sort.each do |file|
9
15
  Bundler.with_clean_env do
10
- sh [File.expand_path('./exe/benchmark-driver', __dir__), path].shelljoin
16
+ sh ['time', 'bundle', 'exec', 'exe/benchmark-driver', file].shelljoin
11
17
  end
18
+ puts
12
19
  end
13
20
  end
14
21
 
15
- task default: :benchmarks
22
+ task default: [:ruby_examples, :yaml_examples]
@@ -1,4 +1,3 @@
1
- # coding: utf-8
2
1
  lib = File.expand_path('../lib', __FILE__)
3
2
  $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
3
  require 'benchmark/driver/version'
@@ -9,8 +8,8 @@ Gem::Specification.new do |spec|
9
8
  spec.authors = ['Takashi Kokubun']
10
9
  spec.email = ['takashikkbn@gmail.com']
11
10
 
12
- spec.summary = %q{Benchmark driver for different Ruby executables}
13
- spec.description = %q{Benchmark driver for different Ruby executables}
11
+ spec.summary = 'Fully-featured accurate benchmark driver for Ruby'
12
+ spec.description = 'Fully-featured accurate benchmark driver for Ruby'
14
13
  spec.homepage = 'https://github.com/k0kubun/benchmark_driver'
15
14
  spec.license = 'MIT'
16
15
 
@@ -20,7 +19,6 @@ Gem::Specification.new do |spec|
20
19
  spec.bindir = 'exe'
21
20
  spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
22
21
  spec.require_paths = ['lib']
23
- spec.required_ruby_version = '>= 2.3.0'
24
22
 
25
23
  spec.add_development_dependency 'bundler'
26
24
  spec.add_development_dependency 'rake'
data/bin/console CHANGED
@@ -1,7 +1,7 @@
1
1
  #!/usr/bin/env ruby
2
2
 
3
3
  require "bundler/setup"
4
- require "benchmark_driver"
4
+ require "benchmark/driver"
5
5
 
6
6
  # You can add fixtures and/or initialization code here to make experimenting
7
7
  # with your gem easier. You can also use a different console, if you like.