benchmark-ips 2.8.0 → 2.9.1

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 54899cb6088746f3b585d3e471795fa63c5fa06b9a452e7923d5211ea096eff1
4
- data.tar.gz: 21f3a97a2971d77dbf33fa05a497f7c61499497da66b8aff26987c64d6e2de3c
3
+ metadata.gz: e6c664c1e49fd7235ba573dc4a5bd92ce7446c0d4206c355a2c7b84320b26d5a
4
+ data.tar.gz: 72d1502418ff11b5e321825ad5d3d1c44889d170c7da0becbf8b6b9fd7c5f283
5
5
  SHA512:
6
- metadata.gz: 3b7dd9271181dc58b32864d0d60ecf58c8daf92dc024ab764bc07289a39650db30354d72fc8f586207c6f5ccfaccf72c41eb9ac75d4e7be7af7a18c60f6e7860
7
- data.tar.gz: 11731f19a4fbc1abcc6e31ad6c5d4ea752f26d3a5ce9573b4e07011b568c455abfbd5a53b5e41408d7e931a5327d1c6c0a2200c25d10897b9d4111d45326c7d5
6
+ metadata.gz: '0956333ead3cb5307864b8d013828fff4f8dbec88c27142314d2742ba5378dbf0388f04706bf797cb24d2fd21a38576cdf04892d62664eb418d6cba38e5bfb33'
7
+ data.tar.gz: 0a953ca0e9270f4eac9c00c51117bc2bfcba6a06e51f3508152b3dcbfd8e03ae4e0cebbf79bc6dc51efcf200e459d9a5ee457d70f371f946e1da8a75c50f7462
data/History.txt CHANGED
@@ -1,3 +1,43 @@
1
+ === 2.9.1 / 2021-05-24
2
+
3
+ * Bug fix
4
+ * Include all files in gem
5
+
6
+ === 2.9.0 / 2021-05-21
7
+
8
+ * Features
9
+ * Suite can now be set via an accessor
10
+ * Default SHARE_URL is now `ips.fastruby.io`, operated by Ombu Labs.
11
+
12
+ === 2.8.4 / 2020-12-03
13
+
14
+ * Bug fix
15
+ * Fixed hold! when results file does not exist.
16
+
17
+ === 2.8.3 / 2020-08-28
18
+
19
+ * Bug fix
20
+ * Fixed inaccuracy caused by integer overflows.
21
+
22
+ === 2.8.2 / 2020-05-04
23
+
24
+ * Bug fix
25
+ * Fixed problems with Manifest.txt.
26
+ * Empty interim results files are ignored.
27
+
28
+ === 2.8.0 / 2020-05-01
29
+
30
+ * Feature
31
+ * Allow running with empty ips block.
32
+ * Added save! method for saving interim results.
33
+ * Run more than just 1 cycle during warmup to reduce overhead.
34
+ * Optimized Job::Entry hot-path for fairer results on JRuby/TruffleRuby.
35
+
36
+ * Bug fix
37
+ * Removed the warmup section if set to 0.
38
+ * Added some RDoc docs.
39
+ * Added some examples in examples/
40
+
1
41
  === 2.7.2 / 2016-08-18
2
42
 
3
43
  * 1 bug fix:
data/Manifest.txt CHANGED
@@ -7,10 +7,13 @@ lib/benchmark/compare.rb
7
7
  lib/benchmark/ips.rb
8
8
  lib/benchmark/ips/job.rb
9
9
  lib/benchmark/ips/job/entry.rb
10
+ lib/benchmark/ips/job/noop_report.rb
10
11
  lib/benchmark/ips/job/stdout_report.rb
12
+ lib/benchmark/ips/noop_suite.rb
11
13
  lib/benchmark/ips/report.rb
12
14
  lib/benchmark/ips/share.rb
13
15
  lib/benchmark/ips/stats/bootstrap.rb
14
16
  lib/benchmark/ips/stats/sd.rb
17
+ lib/benchmark/ips/stats/stats_metric.rb
15
18
  lib/benchmark/timing.rb
16
19
  test/test_benchmark_ips.rb
data/README.md CHANGED
@@ -186,11 +186,15 @@ end
186
186
 
187
187
  ### Online sharing
188
188
 
189
- If you want to share quickly your benchmark result with others. Run you benchmark
190
- with `SHARE=1` argument. I.e.: `SHARE=1 ruby my_benchmark.rb`.
191
- Result will be sent to [benchmark.fyi](https://benchmark.fyi/) and benchmark-ips
189
+ If you want to quickly share your benchmark result with others, run you benchmark
190
+ with `SHARE=1` argument. For example: `SHARE=1 ruby my_benchmark.rb`.
191
+
192
+ Result will be sent to [benchmark.fyi](https://ips.fastruby.io/) and benchmark-ips
192
193
  will display the link to share the benchmark's result.
193
194
 
195
+ If you want to run your own instance of [benchmark.fyi](https://github.com/evanphx/benchmark.fyi)
196
+ and share it to that instance, you can do this: `SHARE_URL=https://ips.example.com ruby my_benchmark.rb`
197
+
194
198
  ### Advanced Statistics
195
199
 
196
200
  By default, the margin of error shown is plus-minus one standard deviation. If
@@ -227,7 +231,7 @@ Benchmark.ips do |x|
227
231
 
228
232
  x.stats = :bootstrap
229
233
  x.confidence = 95
230
-
234
+
231
235
  # confidence is 95% by default, so it can be omitted
232
236
 
233
237
  end
data/lib/benchmark/ips.rb CHANGED
@@ -5,8 +5,10 @@ require 'benchmark/ips/stats/stats_metric'
5
5
  require 'benchmark/ips/stats/sd'
6
6
  require 'benchmark/ips/stats/bootstrap'
7
7
  require 'benchmark/ips/report'
8
+ require 'benchmark/ips/noop_suite'
8
9
  require 'benchmark/ips/job/entry'
9
10
  require 'benchmark/ips/job/stdout_report'
11
+ require 'benchmark/ips/job/noop_report'
10
12
  require 'benchmark/ips/job'
11
13
 
12
14
  # Performance benchmarking library
@@ -16,10 +18,10 @@ module Benchmark
16
18
  module IPS
17
19
 
18
20
  # Benchmark-ips Gem version.
19
- VERSION = "2.8.0"
21
+ VERSION = "2.9.1"
20
22
 
21
23
  # CODENAME of current version.
22
- CODENAME = "Tardy Turtle"
24
+ CODENAME = "Sleepy Sasquatch"
23
25
 
24
26
  # Measure code in block, each code's benchmarked result will display in
25
27
  # iteration per second with standard deviation in given time.
@@ -33,23 +35,14 @@ module Benchmark
33
35
  time, warmup, quiet = args
34
36
  end
35
37
 
36
- suite = nil
37
-
38
38
  sync, $stdout.sync = $stdout.sync, true
39
39
 
40
- if defined? Benchmark::Suite and Suite.current
41
- suite = Benchmark::Suite.current
42
- end
43
-
44
- quiet ||= (suite && suite.quiet?)
45
-
46
- job = Job.new({:suite => suite,
47
- :quiet => quiet
48
- })
40
+ job = Job.new
49
41
 
50
42
  job_opts = {}
51
43
  job_opts[:time] = time unless time.nil?
52
44
  job_opts[:warmup] = warmup unless warmup.nil?
45
+ job_opts[:quiet] = quiet unless quiet.nil?
53
46
 
54
47
  job.config job_opts
55
48
 
@@ -109,6 +102,8 @@ module Benchmark
109
102
  end
110
103
  end
111
104
 
105
+ extend Benchmark::IPS # make ips available as module-level method
106
+
112
107
  ##
113
108
  # :singleton-method: ips
114
109
  #
@@ -172,5 +167,4 @@ module Benchmark
172
167
  # addition: 4955278.9 i/s - 4.85x slower
173
168
  #
174
169
  # See also Benchmark::IPS
175
- extend Benchmark::IPS # make ips available as module-level method
176
170
  end
@@ -9,6 +9,7 @@ module Benchmark
9
9
  # The percentage of the expected runtime to allow
10
10
  # before reporting a weird runtime
11
11
  MAX_TIME_SKEW = 0.05
12
+ POW_2_30 = 1 << 30
12
13
 
13
14
  # Two-element arrays, consisting of label and block pairs.
14
15
  # @return [Array<Entry>] list of entries
@@ -50,16 +51,20 @@ module Benchmark
50
51
  # @return [Integer]
51
52
  attr_accessor :confidence
52
53
 
54
+ # Silence output
55
+ # @return [Boolean]
56
+ attr_reader :quiet
57
+
58
+ # Suite
59
+ # @return [Benchmark::IPS::NoopSuite]
60
+ attr_reader :suite
61
+
53
62
  # Instantiate the Benchmark::IPS::Job.
54
- # @option opts [Benchmark::Suite] (nil) :suite Specify Benchmark::Suite.
55
- # @option opts [Boolean] (false) :quiet Suppress the printing of information.
56
63
  def initialize opts={}
57
- @suite = opts[:suite] || nil
58
- @stdout = opts[:quiet] ? nil : StdoutReport.new
59
64
  @list = []
60
- @compare = false
61
65
  @run_single = false
62
66
  @json_path = false
67
+ @compare = false
63
68
  @held_path = nil
64
69
  @held_results = nil
65
70
 
@@ -87,6 +92,20 @@ module Benchmark
87
92
  @iterations = opts[:iterations] if opts[:iterations]
88
93
  @stats = opts[:stats] if opts[:stats]
89
94
  @confidence = opts[:confidence] if opts[:confidence]
95
+ self.quiet = opts[:quiet]
96
+ self.suite = opts[:suite]
97
+ end
98
+
99
+ def quiet=(val)
100
+ @stdout = reporter(quiet: val)
101
+ end
102
+
103
+ def suite=(suite)
104
+ @suite = suite || Benchmark::IPS::NoopSuite.new
105
+ end
106
+
107
+ def reporter(quiet:)
108
+ quiet ? NoopReport.new : StdoutReport.new
90
109
  end
91
110
 
92
111
  # Return true if job needs to be compared.
@@ -187,7 +206,7 @@ module Benchmark
187
206
  end
188
207
 
189
208
  def load_held_results
190
- return unless @held_path && File.exist?(@held_path)
209
+ return unless @held_path && File.exist?(@held_path) && !File.zero?(@held_path)
191
210
  require "json"
192
211
  @held_results = {}
193
212
  JSON.load(IO.read(@held_path)).each do |result|
@@ -222,19 +241,19 @@ module Benchmark
222
241
 
223
242
  def run
224
243
  if @warmup && @warmup != 0 then
225
- @stdout.start_warming if @stdout
244
+ @stdout.start_warming
226
245
  @iterations.times do
227
246
  run_warmup
228
247
  end
229
248
  end
230
249
 
231
- @stdout.start_running if @stdout
250
+ @stdout.start_running
232
251
 
233
252
  @iterations.times do |n|
234
253
  run_benchmark
235
254
  end
236
255
 
237
- @stdout.footer if @stdout
256
+ @stdout.footer
238
257
  end
239
258
 
240
259
  # Run warmup.
@@ -242,8 +261,8 @@ module Benchmark
242
261
  @list.each do |item|
243
262
  next if run_single? && @held_results && @held_results.key?(item.label)
244
263
 
245
- @suite.warming item.label, @warmup if @suite
246
- @stdout.warming item.label, @warmup if @stdout
264
+ @suite.warming item.label, @warmup
265
+ @stdout.warming item.label, @warmup
247
266
 
248
267
  Timing.clean_env
249
268
 
@@ -263,6 +282,10 @@ module Benchmark
263
282
  t1 = Timing.now
264
283
  warmup_iter = cycles
265
284
  warmup_time_us = Timing.time_us(t0, t1)
285
+
286
+ # If the number of cycles would go outside the 32-bit signed integers range
287
+ # then exit the loop to avoid overflows and start the 100ms warmup runs
288
+ break if cycles >= POW_2_30
266
289
  cycles *= 2
267
290
  end
268
291
 
@@ -275,8 +298,8 @@ module Benchmark
275
298
  item.call_times cycles
276
299
  end
277
300
 
278
- @stdout.warmup_stats warmup_time_us, @timing[item] if @stdout
279
- @suite.warmup_stats warmup_time_us, @timing[item] if @suite
301
+ @stdout.warmup_stats warmup_time_us, @timing[item]
302
+ @suite.warmup_stats warmup_time_us, @timing[item]
280
303
 
281
304
  break if run_single?
282
305
  end
@@ -287,8 +310,8 @@ module Benchmark
287
310
  @list.each do |item|
288
311
  next if run_single? && @held_results && @held_results.key?(item.label)
289
312
 
290
- @suite.running item.label, @time if @suite
291
- @stdout.running item.label, @time if @stdout
313
+ @suite.running item.label, @time
314
+ @stdout.running item.label, @time
292
315
 
293
316
  Timing.clean_env
294
317
 
@@ -329,8 +352,8 @@ module Benchmark
329
352
  rep.show_total_time!
330
353
  end
331
354
 
332
- @stdout.add_report rep, caller(1).first if @stdout
333
- @suite.add_report rep, caller(1).first if @suite
355
+ @stdout.add_report rep, caller(1).first
356
+ @suite.add_report rep, caller(1).first
334
357
 
335
358
  break if run_single?
336
359
  end
@@ -11,10 +11,12 @@ module Benchmark
11
11
  def initialize(label, action)
12
12
  @label = label
13
13
 
14
+ # We define #call_times on the singleton class of each Entry instance.
15
+ # That way, there is no polymorphism for `@action.call` inside #call_times.
16
+
14
17
  if action.kind_of? String
15
- compile action
18
+ compile_string action
16
19
  @action = self
17
- @as_action = true
18
20
  else
19
21
  unless action.respond_to? :call
20
22
  raise ArgumentError, "invalid action, must respond to #call"
@@ -23,12 +25,10 @@ module Benchmark
23
25
  @action = action
24
26
 
25
27
  if action.respond_to? :arity and action.arity > 0
26
- @call_loop = true
28
+ compile_block_with_manual_loop
27
29
  else
28
- @call_loop = false
30
+ compile_block
29
31
  end
30
-
31
- @as_action = false
32
32
  end
33
33
  end
34
34
 
@@ -40,25 +40,43 @@ module Benchmark
40
40
  # @return [String, Proc] Code to be called, could be String / Proc.
41
41
  attr_reader :action
42
42
 
43
- # Call action by given times, return if +@call_loop+ is present.
43
+ # Call action by given times.
44
44
  # @param times [Integer] Times to call +@action+.
45
45
  # @return [Integer] Number of times the +@action+ has been called.
46
46
  def call_times(times)
47
- return @action.call(times) if @call_loop
47
+ raise '#call_times should be redefined per Benchmark::IPS::Job::Entry instance'
48
+ end
48
49
 
49
- act = @action
50
+ def compile_block
51
+ m = (class << self; self; end)
52
+ code = <<-CODE
53
+ def call_times(times)
54
+ act = @action
50
55
 
51
- i = 0
52
- while i < times
53
- act.call
54
- i += 1
55
- end
56
+ i = 0
57
+ while i < times
58
+ act.call
59
+ i += 1
60
+ end
61
+ end
62
+ CODE
63
+ m.class_eval code
64
+ end
65
+
66
+ def compile_block_with_manual_loop
67
+ m = (class << self; self; end)
68
+ code = <<-CODE
69
+ def call_times(times)
70
+ @action.call(times)
71
+ end
72
+ CODE
73
+ m.class_eval code
56
74
  end
57
75
 
58
76
  # Compile code into +call_times+ method.
59
77
  # @param str [String] Code to be compiled.
60
78
  # @return [Symbol] :call_times.
61
- def compile(str)
79
+ def compile_string(str)
62
80
  m = (class << self; self; end)
63
81
  code = <<-CODE
64
82
  def call_times(__total);
@@ -0,0 +1,27 @@
1
+ module Benchmark
2
+ module IPS
3
+ class Job
4
+ class NoopReport
5
+ def start_warming
6
+ end
7
+
8
+ def start_running
9
+ end
10
+
11
+ def footer
12
+ end
13
+
14
+ def warming(a, b)
15
+ end
16
+
17
+ def warmup_stats(a, b)
18
+ end
19
+
20
+ def add_report(a, b)
21
+ end
22
+
23
+ alias_method :running, :warming
24
+ end
25
+ end
26
+ end
27
+ end
@@ -0,0 +1,25 @@
1
+ module Benchmark
2
+ module IPS
3
+ class NoopSuite
4
+ def start_warming
5
+ end
6
+
7
+ def start_running
8
+ end
9
+
10
+ def footer
11
+ end
12
+
13
+ def warming(a, b)
14
+ end
15
+
16
+ def warmup_stats(a, b)
17
+ end
18
+
19
+ def add_report(a, b)
20
+ end
21
+
22
+ alias_method :running, :warming
23
+ end
24
+ end
25
+ end
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'net/http'
2
4
  require 'net/https'
3
5
  require 'json'
@@ -5,7 +7,7 @@ require 'json'
5
7
  module Benchmark
6
8
  module IPS
7
9
  class Share
8
- DEFAULT_URL = "https://benchmark.fyi"
10
+ DEFAULT_URL = "https://ips.fastruby.io"
9
11
  def initialize(report, job)
10
12
  @report = report
11
13
  @job = job
@@ -0,0 +1,21 @@
1
+ module Benchmark
2
+ module IPS
3
+ module Stats
4
+ module StatsMetric
5
+ # Return entry's standard deviation of iteration per second in percentage.
6
+ # @return [Float] +@ips_sd+ in percentage.
7
+ def error_percentage
8
+ 100.0 * (error.to_f / central_tendency)
9
+ end
10
+
11
+ def overlaps?(baseline)
12
+ baseline_low = baseline.central_tendency - baseline.error
13
+ baseline_high = baseline.central_tendency + baseline.error
14
+ my_high = central_tendency + error
15
+ my_low = central_tendency - error
16
+ my_high > baseline_low && my_low < baseline_high
17
+ end
18
+ end
19
+ end
20
+ end
21
+ end
@@ -1,6 +1,7 @@
1
1
  require "minitest/autorun"
2
2
  require "benchmark/ips"
3
3
  require "stringio"
4
+ require "tmpdir"
4
5
 
5
6
  class TestBenchmarkIPS < Minitest::Test
6
7
  def setup
@@ -53,6 +54,13 @@ class TestBenchmarkIPS < Minitest::Test
53
54
  end
54
55
 
55
56
  assert $stdout.string.size.zero?
57
+
58
+ Benchmark.ips do |x|
59
+ x.quiet = true
60
+ x.report("operation") { 100 * 100 }
61
+ end
62
+
63
+ assert $stdout.string.size.zero?
56
64
  end
57
65
 
58
66
  def test_ips
@@ -116,6 +124,21 @@ class TestBenchmarkIPS < Minitest::Test
116
124
  assert_equal [:warming, :warmup_stats, :running, :add_report], suite.calls
117
125
  end
118
126
 
127
+ def test_ips_config_suite_by_accsr
128
+ suite = Struct.new(:calls) do
129
+ def method_missing(method, *args)
130
+ calls << method
131
+ end
132
+ end.new([])
133
+
134
+ Benchmark.ips(0.1, 0.1) do |x|
135
+ x.suite = suite
136
+ x.report("job") {}
137
+ end
138
+
139
+ assert_equal [:warming, :warmup_stats, :running, :add_report], suite.calls
140
+ end
141
+
119
142
  def test_ips_defaults
120
143
  report = Benchmark.ips do |x|
121
144
  x.report("sleep 0.25") { sleep(0.25) }
@@ -182,4 +205,17 @@ class TestBenchmarkIPS < Minitest::Test
182
205
  assert data[0]["ips"]
183
206
  assert data[0]["stddev"]
184
207
  end
208
+
209
+ def test_hold!
210
+ temp_file_name = Dir::Tmpname.create(["benchmark-ips", ".tmp"]) { }
211
+
212
+ Benchmark.ips(:time => 0.001, :warmup => 0.001) do |x|
213
+ x.report("operation") { 100 * 100 }
214
+ x.report("operation2") { 100 * 100 }
215
+ x.hold! temp_file_name
216
+ end
217
+
218
+ assert File.exist?(temp_file_name)
219
+ File.unlink(temp_file_name)
220
+ end
185
221
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: benchmark-ips
3
3
  version: !ruby/object:Gem::Version
4
- version: 2.8.0
4
+ version: 2.9.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Evan Phoenix
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2020-05-01 00:00:00.000000000 Z
11
+ date: 2021-05-24 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: minitest
@@ -77,11 +77,14 @@ files:
77
77
  - lib/benchmark/ips.rb
78
78
  - lib/benchmark/ips/job.rb
79
79
  - lib/benchmark/ips/job/entry.rb
80
+ - lib/benchmark/ips/job/noop_report.rb
80
81
  - lib/benchmark/ips/job/stdout_report.rb
82
+ - lib/benchmark/ips/noop_suite.rb
81
83
  - lib/benchmark/ips/report.rb
82
84
  - lib/benchmark/ips/share.rb
83
85
  - lib/benchmark/ips/stats/bootstrap.rb
84
86
  - lib/benchmark/ips/stats/sd.rb
87
+ - lib/benchmark/ips/stats/stats_metric.rb
85
88
  - lib/benchmark/timing.rb
86
89
  - test/test_benchmark_ips.rb
87
90
  homepage: https://github.com/evanphx/benchmark-ips
@@ -106,7 +109,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
106
109
  - !ruby/object:Gem::Version
107
110
  version: '0'
108
111
  requirements: []
109
- rubygems_version: 3.0.3
112
+ rubygems_version: 3.2.9
110
113
  signing_key:
111
114
  specification_version: 4
112
115
  summary: An iterations per second enhancement to Benchmark.