benchmark_driver 0.3.0 → 0.4.0

Sign up to get free protection for your applications and to get access to all the features.
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.