benchmark-ips 2.8.0 → 2.9.1

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.
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.