benchmark-ips 2.7.2 → 2.8.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.
- checksums.yaml +5 -5
- data/Manifest.txt +0 -1
- data/README.md +10 -4
- data/lib/benchmark/compare.rb +5 -9
- data/lib/benchmark/ips.rb +74 -3
- data/lib/benchmark/ips/job.rb +94 -71
- data/lib/benchmark/ips/job/stdout_report.rb +6 -1
- data/lib/benchmark/ips/report.rb +7 -3
- data/lib/benchmark/ips/stats/bootstrap.rb +9 -6
- data/lib/benchmark/ips/stats/sd.rb +19 -11
- data/test/test_benchmark_ips.rb +24 -0
- metadata +17 -12
- data/Gemfile.lock +0 -18
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
|
-
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: 54899cb6088746f3b585d3e471795fa63c5fa06b9a452e7923d5211ea096eff1
|
4
|
+
data.tar.gz: 21f3a97a2971d77dbf33fa05a497f7c61499497da66b8aff26987c64d6e2de3c
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 3b7dd9271181dc58b32864d0d60ecf58c8daf92dc024ab764bc07289a39650db30354d72fc8f586207c6f5ccfaccf72c41eb9ac75d4e7be7af7a18c60f6e7860
|
7
|
+
data.tar.gz: 11731f19a4fbc1abcc6e31ad6c5d4ea752f26d3a5ce9573b4e07011b568c455abfbd5a53b5e41408d7e931a5327d1c6c0a2200c25d10897b9d4111d45326c7d5
|
data/Manifest.txt
CHANGED
data/README.md
CHANGED
@@ -1,13 +1,14 @@
|
|
1
|
+
# benchmark-ips
|
2
|
+
|
3
|
+
* rdoc :: http://rubydoc.info/gems/benchmark-ips
|
4
|
+
* home :: https://github.com/evanphx/benchmark-ips
|
5
|
+
|
1
6
|
[](http://badge.fury.io/rb/benchmark-ips)
|
2
7
|
[](http://travis-ci.org/evanphx/benchmark-ips)
|
3
8
|
[](http://inch-ci.org/github/evanphx/benchmark-ips)
|
4
9
|
|
5
|
-
# benchmark-ips
|
6
|
-
|
7
10
|
* https://github.com/evanphx/benchmark-ips
|
8
11
|
|
9
|
-
* [documentation](http://rubydoc.info/gems/benchmark-ips)
|
10
|
-
|
11
12
|
## DESCRIPTION:
|
12
13
|
|
13
14
|
An iterations per second enhancement to Benchmark.
|
@@ -155,6 +156,11 @@ This will run only one benchmarks each time you run the command, storing
|
|
155
156
|
results in the specified file. The file is deleted when all results have been
|
156
157
|
gathered and the report is shown.
|
157
158
|
|
159
|
+
Alternatively, if you prefer a different approach, the `save!` command is
|
160
|
+
available. Examples for [hold!](examples/hold.rb) and [save!](examples/save.rb) are available in
|
161
|
+
the `examples/` directory.
|
162
|
+
|
163
|
+
|
158
164
|
### Multiple iterations
|
159
165
|
|
160
166
|
In some cases you may want to run multiple iterations of the warmup and
|
data/lib/benchmark/compare.rb
CHANGED
@@ -40,18 +40,14 @@ module Benchmark
|
|
40
40
|
|
41
41
|
$stdout.puts "\nComparison:"
|
42
42
|
|
43
|
-
$stdout.printf "%20s: %10.1f i/s\n", best.label, best.stats.central_tendency
|
43
|
+
$stdout.printf "%20s: %10.1f i/s\n", best.label.to_s, best.stats.central_tendency
|
44
44
|
|
45
45
|
sorted.each do |report|
|
46
46
|
name = report.label.to_s
|
47
|
-
|
47
|
+
|
48
48
|
$stdout.printf "%20s: %10.1f i/s - ", name, report.stats.central_tendency
|
49
|
-
|
50
|
-
|
51
|
-
report_high = report.stats.central_tendency + report.stats.error
|
52
|
-
overlaps = report_high > best_low
|
53
|
-
|
54
|
-
if overlaps
|
49
|
+
|
50
|
+
if report.stats.overlaps?(best.stats)
|
55
51
|
$stdout.print "same-ish: difference falls within error"
|
56
52
|
else
|
57
53
|
slowdown, error = report.stats.slowdown(best.stats)
|
@@ -61,7 +57,7 @@ module Benchmark
|
|
61
57
|
end
|
62
58
|
$stdout.print " slower"
|
63
59
|
end
|
64
|
-
|
60
|
+
|
65
61
|
$stdout.puts
|
66
62
|
end
|
67
63
|
|
data/lib/benchmark/ips.rb
CHANGED
@@ -1,6 +1,7 @@
|
|
1
1
|
# encoding: utf-8
|
2
2
|
require 'benchmark/timing'
|
3
3
|
require 'benchmark/compare'
|
4
|
+
require 'benchmark/ips/stats/stats_metric'
|
4
5
|
require 'benchmark/ips/stats/sd'
|
5
6
|
require 'benchmark/ips/stats/bootstrap'
|
6
7
|
require 'benchmark/ips/report'
|
@@ -15,10 +16,10 @@ module Benchmark
|
|
15
16
|
module IPS
|
16
17
|
|
17
18
|
# Benchmark-ips Gem version.
|
18
|
-
VERSION = "2.
|
19
|
+
VERSION = "2.8.0"
|
19
20
|
|
20
21
|
# CODENAME of current version.
|
21
|
-
CODENAME = "
|
22
|
+
CODENAME = "Tardy Turtle"
|
22
23
|
|
23
24
|
# Measure code in block, each code's benchmarked result will display in
|
24
25
|
# iteration per second with standard deviation in given time.
|
@@ -54,10 +55,17 @@ module Benchmark
|
|
54
55
|
|
55
56
|
yield job
|
56
57
|
|
57
|
-
job.load_held_results
|
58
|
+
job.load_held_results
|
58
59
|
|
59
60
|
job.run
|
60
61
|
|
62
|
+
if job.run_single? && job.all_results_have_been_run?
|
63
|
+
job.clear_held_results
|
64
|
+
else
|
65
|
+
job.save_held_results
|
66
|
+
puts '', 'Pausing here -- run Ruby again to measure the next benchmark...' if job.run_single?
|
67
|
+
end
|
68
|
+
|
61
69
|
$stdout.sync = sync
|
62
70
|
job.run_comparison
|
63
71
|
job.generate_json
|
@@ -101,5 +109,68 @@ module Benchmark
|
|
101
109
|
end
|
102
110
|
end
|
103
111
|
|
112
|
+
##
|
113
|
+
# :singleton-method: ips
|
114
|
+
#
|
115
|
+
# require 'benchmark/ips'
|
116
|
+
#
|
117
|
+
# Benchmark.ips do |x|
|
118
|
+
# # Configure the number of seconds used during
|
119
|
+
# # the warmup phase (default 2) and calculation phase (default 5)
|
120
|
+
# x.config(:time => 5, :warmup => 2)
|
121
|
+
#
|
122
|
+
# # These parameters can also be configured this way
|
123
|
+
# x.time = 5
|
124
|
+
# x.warmup = 2
|
125
|
+
#
|
126
|
+
# # Typical mode, runs the block as many times as it can
|
127
|
+
# x.report("addition") { 1 + 2 }
|
128
|
+
#
|
129
|
+
# # To reduce overhead, the number of iterations is passed in
|
130
|
+
# # and the block must run the code the specific number of times.
|
131
|
+
# # Used for when the workload is very small and any overhead
|
132
|
+
# # introduces incorrectable errors.
|
133
|
+
# x.report("addition2") do |times|
|
134
|
+
# i = 0
|
135
|
+
# while i < times
|
136
|
+
# 1 + 2
|
137
|
+
# i += 1
|
138
|
+
# end
|
139
|
+
# end
|
140
|
+
#
|
141
|
+
# # To reduce overhead even more, grafts the code given into
|
142
|
+
# # the loop that performs the iterations internally to reduce
|
143
|
+
# # overhead. Typically not needed, use the |times| form instead.
|
144
|
+
# x.report("addition3", "1 + 2")
|
145
|
+
#
|
146
|
+
# # Really long labels should be formatted correctly
|
147
|
+
# x.report("addition-test-long-label") { 1 + 2 }
|
148
|
+
#
|
149
|
+
# # Compare the iterations per second of the various reports!
|
150
|
+
# x.compare!
|
151
|
+
# end
|
152
|
+
#
|
153
|
+
# This will generate the following report:
|
154
|
+
#
|
155
|
+
# Calculating -------------------------------------
|
156
|
+
# addition 71.254k i/100ms
|
157
|
+
# addition2 68.658k i/100ms
|
158
|
+
# addition3 83.079k i/100ms
|
159
|
+
# addition-test-long-label
|
160
|
+
# 70.129k i/100ms
|
161
|
+
# -------------------------------------------------
|
162
|
+
# addition 4.955M (± 8.7%) i/s - 24.155M
|
163
|
+
# addition2 24.011M (± 9.5%) i/s - 114.246M
|
164
|
+
# addition3 23.958M (±10.1%) i/s - 115.064M
|
165
|
+
# addition-test-long-label
|
166
|
+
# 5.014M (± 9.1%) i/s - 24.545M
|
167
|
+
#
|
168
|
+
# Comparison:
|
169
|
+
# addition2: 24011974.8 i/s
|
170
|
+
# addition3: 23958619.8 i/s - 1.00x slower
|
171
|
+
# addition-test-long-label: 5014756.0 i/s - 4.79x slower
|
172
|
+
# addition: 4955278.9 i/s - 4.85x slower
|
173
|
+
#
|
174
|
+
# See also Benchmark::IPS
|
104
175
|
extend Benchmark::IPS # make ips available as module-level method
|
105
176
|
end
|
data/lib/benchmark/ips/job.rb
CHANGED
@@ -58,11 +58,12 @@ module Benchmark
|
|
58
58
|
@stdout = opts[:quiet] ? nil : StdoutReport.new
|
59
59
|
@list = []
|
60
60
|
@compare = false
|
61
|
+
@run_single = false
|
61
62
|
@json_path = false
|
62
63
|
@held_path = nil
|
63
64
|
@held_results = nil
|
64
65
|
|
65
|
-
@timing =
|
66
|
+
@timing = Hash.new 1 # default to 1 in case warmup isn't run
|
66
67
|
@full_report = Report.new
|
67
68
|
|
68
69
|
# Default warmup and calculation time in seconds.
|
@@ -94,7 +95,7 @@ module Benchmark
|
|
94
95
|
@compare
|
95
96
|
end
|
96
97
|
|
97
|
-
#
|
98
|
+
# Run comparison utility.
|
98
99
|
def compare!
|
99
100
|
@compare = true
|
100
101
|
end
|
@@ -105,9 +106,27 @@ module Benchmark
|
|
105
106
|
!!@held_path
|
106
107
|
end
|
107
108
|
|
108
|
-
#
|
109
|
+
# Hold after each iteration.
|
110
|
+
# @param held_path [String] File name to store hold file.
|
109
111
|
def hold!(held_path)
|
110
112
|
@held_path = held_path
|
113
|
+
@run_single = true
|
114
|
+
end
|
115
|
+
|
116
|
+
# Save interim results. Similar to hold, but all reports are run
|
117
|
+
# The report label must change for each invocation.
|
118
|
+
# One way to achieve this is to include the version in the label.
|
119
|
+
# @param held_path [String] File name to store hold file.
|
120
|
+
def save!(held_path)
|
121
|
+
@held_path = held_path
|
122
|
+
@run_single = false
|
123
|
+
end
|
124
|
+
|
125
|
+
# Return true if items are to be run one at a time.
|
126
|
+
# For the traditional hold, this is true
|
127
|
+
# @return [Boolean] Run just a single item?
|
128
|
+
def run_single?
|
129
|
+
@run_single
|
111
130
|
end
|
112
131
|
|
113
132
|
# Return true if job needs to generate json.
|
@@ -116,7 +135,7 @@ module Benchmark
|
|
116
135
|
!!@json_path
|
117
136
|
end
|
118
137
|
|
119
|
-
#
|
138
|
+
# Generate json to given path, defaults to "data.json".
|
120
139
|
def json!(path="data.json")
|
121
140
|
@json_path = path
|
122
141
|
end
|
@@ -166,84 +185,108 @@ module Benchmark
|
|
166
185
|
def iterations_per_sec cycles, time_us
|
167
186
|
MICROSECONDS_PER_SECOND * (cycles.to_f / time_us.to_f)
|
168
187
|
end
|
169
|
-
|
170
|
-
def held_results?
|
171
|
-
File.exist?(@held_path)
|
172
|
-
end
|
173
|
-
|
188
|
+
|
174
189
|
def load_held_results
|
190
|
+
return unless @held_path && File.exist?(@held_path)
|
191
|
+
require "json"
|
192
|
+
@held_results = {}
|
193
|
+
JSON.load(IO.read(@held_path)).each do |result|
|
194
|
+
@held_results[result['item']] = result
|
195
|
+
create_report(result['item'], result['measured_us'], result['iter'],
|
196
|
+
create_stats(result['samples']), result['cycles'])
|
197
|
+
end
|
198
|
+
end
|
199
|
+
|
200
|
+
def save_held_results
|
201
|
+
return unless @held_path
|
175
202
|
require "json"
|
176
|
-
|
177
|
-
|
178
|
-
|
179
|
-
|
203
|
+
data = full_report.entries.map { |e|
|
204
|
+
{
|
205
|
+
'item' => e.label,
|
206
|
+
'measured_us' => e.microseconds,
|
207
|
+
'iter' => e.iterations,
|
208
|
+
'samples' => e.samples,
|
209
|
+
'cycles' => e.measurement_cycle
|
210
|
+
}
|
211
|
+
}
|
212
|
+
IO.write(@held_path, JSON.generate(data) << "\n")
|
213
|
+
end
|
214
|
+
|
215
|
+
def all_results_have_been_run?
|
216
|
+
@full_report.entries.size == @list.size
|
180
217
|
end
|
181
|
-
|
218
|
+
|
219
|
+
def clear_held_results
|
220
|
+
File.delete @held_path if File.exist?(@held_path)
|
221
|
+
end
|
222
|
+
|
182
223
|
def run
|
183
|
-
@
|
184
|
-
|
185
|
-
|
224
|
+
if @warmup && @warmup != 0 then
|
225
|
+
@stdout.start_warming if @stdout
|
226
|
+
@iterations.times do
|
227
|
+
run_warmup
|
228
|
+
end
|
186
229
|
end
|
187
|
-
|
230
|
+
|
188
231
|
@stdout.start_running if @stdout
|
189
|
-
|
190
|
-
held = nil
|
191
|
-
|
232
|
+
|
192
233
|
@iterations.times do |n|
|
193
|
-
|
234
|
+
run_benchmark
|
194
235
|
end
|
195
236
|
|
196
237
|
@stdout.footer if @stdout
|
197
|
-
|
198
|
-
if held
|
199
|
-
puts
|
200
|
-
puts 'Pausing here -- run Ruby again to measure the next benchmark...'
|
201
|
-
end
|
202
238
|
end
|
203
239
|
|
204
240
|
# Run warmup.
|
205
241
|
def run_warmup
|
206
242
|
@list.each do |item|
|
207
|
-
next if
|
208
|
-
|
243
|
+
next if run_single? && @held_results && @held_results.key?(item.label)
|
244
|
+
|
209
245
|
@suite.warming item.label, @warmup if @suite
|
210
246
|
@stdout.warming item.label, @warmup if @stdout
|
211
247
|
|
212
248
|
Timing.clean_env
|
213
249
|
|
250
|
+
# Run for up to half of the configured warmup time with an increasing
|
251
|
+
# number of cycles to reduce overhead and improve accuracy.
|
252
|
+
# This also avoids running with a constant number of cycles, which a
|
253
|
+
# JIT might speculate on and then have to recompile in #run_benchmark.
|
214
254
|
before = Timing.now
|
215
|
-
target = Timing.add_second before, @warmup
|
255
|
+
target = Timing.add_second before, @warmup / 2.0
|
216
256
|
|
217
|
-
|
218
|
-
|
219
|
-
|
220
|
-
|
221
|
-
|
257
|
+
cycles = 1
|
258
|
+
warmup_iter = 1
|
259
|
+
warmup_time_us = 0.0
|
260
|
+
while Timing.now + warmup_time_us * 2 < target
|
261
|
+
t0 = Timing.now
|
262
|
+
item.call_times cycles
|
263
|
+
t1 = Timing.now
|
264
|
+
warmup_iter = cycles
|
265
|
+
warmup_time_us = Timing.time_us(t0, t1)
|
266
|
+
cycles *= 2
|
222
267
|
end
|
223
268
|
|
224
|
-
|
269
|
+
cycles = cycles_per_100ms warmup_time_us, warmup_iter
|
270
|
+
@timing[item] = cycles
|
225
271
|
|
226
|
-
|
227
|
-
|
228
|
-
|
272
|
+
# Run for the remaining of warmup in a similar way as #run_benchmark.
|
273
|
+
target = Timing.add_second before, @warmup
|
274
|
+
while Timing.now + MICROSECONDS_PER_100MS < target
|
275
|
+
item.call_times cycles
|
276
|
+
end
|
229
277
|
|
230
278
|
@stdout.warmup_stats warmup_time_us, @timing[item] if @stdout
|
231
279
|
@suite.warmup_stats warmup_time_us, @timing[item] if @suite
|
232
|
-
|
233
|
-
break if
|
280
|
+
|
281
|
+
break if run_single?
|
234
282
|
end
|
235
283
|
end
|
236
284
|
|
237
285
|
# Run calculation.
|
238
286
|
def run_benchmark
|
239
287
|
@list.each do |item|
|
240
|
-
if
|
241
|
-
|
242
|
-
create_report(item.label, result['measured_us'], result['iter'],
|
243
|
-
create_stats(result['samples']), result['cycles'])
|
244
|
-
next
|
245
|
-
end
|
246
|
-
|
288
|
+
next if run_single? && @held_results && @held_results.key?(item.label)
|
289
|
+
|
247
290
|
@suite.running item.label, @time if @suite
|
248
291
|
@stdout.running item.label, @time if @stdout
|
249
292
|
|
@@ -257,7 +300,7 @@ module Benchmark
|
|
257
300
|
cycles = @timing[item]
|
258
301
|
|
259
302
|
target = Timing.add_second Timing.now, @time
|
260
|
-
|
303
|
+
|
261
304
|
while (before = Timing.now) < target
|
262
305
|
item.call_times cycles
|
263
306
|
after = Timing.now
|
@@ -288,29 +331,9 @@ module Benchmark
|
|
288
331
|
|
289
332
|
@stdout.add_report rep, caller(1).first if @stdout
|
290
333
|
@suite.add_report rep, caller(1).first if @suite
|
291
|
-
|
292
|
-
if
|
293
|
-
File.open @held_path, "a" do |f|
|
294
|
-
require "json"
|
295
|
-
f.write JSON.generate({
|
296
|
-
:item => item.label,
|
297
|
-
:measured_us => measured_us,
|
298
|
-
:iter => iter,
|
299
|
-
:samples => samples,
|
300
|
-
:cycles => cycles
|
301
|
-
})
|
302
|
-
f.write "\n"
|
303
|
-
end
|
304
|
-
|
305
|
-
return true
|
306
|
-
end
|
307
|
-
end
|
308
|
-
|
309
|
-
if hold? && @full_report.entries.size == @list.size
|
310
|
-
File.delete @held_path if File.exist?(@held_path)
|
334
|
+
|
335
|
+
break if run_single?
|
311
336
|
end
|
312
|
-
|
313
|
-
false
|
314
337
|
end
|
315
338
|
|
316
339
|
def create_stats(samples)
|
@@ -2,10 +2,14 @@ module Benchmark
|
|
2
2
|
module IPS
|
3
3
|
class Job
|
4
4
|
class StdoutReport
|
5
|
+
def initialize
|
6
|
+
@last_item = nil
|
7
|
+
end
|
8
|
+
|
5
9
|
def start_warming
|
6
10
|
$stdout.puts "Warming up --------------------------------------"
|
7
11
|
end
|
8
|
-
|
12
|
+
|
9
13
|
def start_running
|
10
14
|
$stdout.puts "Calculating -------------------------------------"
|
11
15
|
end
|
@@ -31,6 +35,7 @@ module Benchmark
|
|
31
35
|
end
|
32
36
|
|
33
37
|
def footer
|
38
|
+
return unless @last_item
|
34
39
|
footer = @last_item.stats.footer
|
35
40
|
$stdout.puts footer.rjust(40) if footer
|
36
41
|
end
|
data/lib/benchmark/ips/report.rb
CHANGED
@@ -52,6 +52,10 @@ module Benchmark
|
|
52
52
|
@stats.error
|
53
53
|
end
|
54
54
|
|
55
|
+
def samples
|
56
|
+
@stats.samples
|
57
|
+
end
|
58
|
+
|
55
59
|
# Number of Cycles.
|
56
60
|
# @return [Integer] number of cycles.
|
57
61
|
attr_reader :measurement_cycle
|
@@ -72,7 +76,7 @@ module Benchmark
|
|
72
76
|
# Return entry's standard deviation of iteration per second in percentage.
|
73
77
|
# @return [Float] +@ips_sd+ in percentage.
|
74
78
|
def error_percentage
|
75
|
-
|
79
|
+
@stats.error_percentage
|
76
80
|
end
|
77
81
|
|
78
82
|
alias_method :runtime, :seconds
|
@@ -84,7 +88,7 @@ module Benchmark
|
|
84
88
|
def body
|
85
89
|
case Benchmark::IPS.options[:format]
|
86
90
|
when :human
|
87
|
-
left = "%s (±%4.1f%%) i/s" % [Helpers.scale(@stats.central_tendency), error_percentage]
|
91
|
+
left = "%s (±%4.1f%%) i/s" % [Helpers.scale(@stats.central_tendency), @stats.error_percentage]
|
88
92
|
iters = Helpers.scale(@iterations)
|
89
93
|
|
90
94
|
if @show_total_time
|
@@ -93,7 +97,7 @@ module Benchmark
|
|
93
97
|
left.ljust(20) + (" - %s" % iters)
|
94
98
|
end
|
95
99
|
else
|
96
|
-
left = "%10.1f (±%.1f%%) i/s" % [@stats.central_tendency, error_percentage]
|
100
|
+
left = "%10.1f (±%.1f%%) i/s" % [@stats.central_tendency, @stats.error_percentage]
|
97
101
|
|
98
102
|
if @show_total_time
|
99
103
|
left.ljust(20) + (" - %10d in %10.6fs" % [@iterations, runtime])
|
@@ -3,27 +3,30 @@ module Benchmark
|
|
3
3
|
module Stats
|
4
4
|
|
5
5
|
class Bootstrap
|
6
|
-
|
7
|
-
attr_reader :data
|
6
|
+
include StatsMetric
|
7
|
+
attr_reader :data, :error, :samples
|
8
8
|
|
9
9
|
def initialize(samples, confidence)
|
10
10
|
dependencies
|
11
11
|
@iterations = 10_000
|
12
12
|
@confidence = (confidence / 100.0).to_s
|
13
|
+
@samples = samples
|
13
14
|
@data = Kalibera::Data.new({[0] => samples}, [1, samples.size])
|
14
15
|
interval = @data.bootstrap_confidence_interval(@iterations, @confidence)
|
15
16
|
@median = interval.median
|
16
17
|
@error = interval.error
|
17
18
|
end
|
18
19
|
|
20
|
+
# Average stat value
|
21
|
+
# @return [Float] central_tendency
|
19
22
|
def central_tendency
|
20
23
|
@median
|
21
24
|
end
|
22
25
|
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
26
|
+
# Determines how much slower this stat is than the baseline stat
|
27
|
+
# if this average is lower than the faster baseline, higher average is better (e.g. ips) (calculate accordingly)
|
28
|
+
# @param baseline [SD|Bootstrap] faster baseline
|
29
|
+
# @returns [Array<Float, nil>] the slowdown and the error (not calculated for standard deviation)
|
27
30
|
def slowdown(baseline)
|
28
31
|
low, slowdown, high = baseline.data.bootstrap_quotient(@data, @iterations, @confidence)
|
29
32
|
error = Timing.mean([slowdown - low, high - slowdown])
|
@@ -1,33 +1,41 @@
|
|
1
1
|
module Benchmark
|
2
2
|
module IPS
|
3
3
|
module Stats
|
4
|
-
|
4
|
+
|
5
5
|
class SD
|
6
|
-
|
6
|
+
include StatsMetric
|
7
|
+
attr_reader :error, :samples
|
8
|
+
|
7
9
|
def initialize(samples)
|
10
|
+
@samples = samples
|
8
11
|
@mean = Timing.mean(samples)
|
9
12
|
@error = Timing.stddev(samples, @mean).round
|
10
13
|
end
|
11
|
-
|
14
|
+
|
15
|
+
# Average stat value
|
16
|
+
# @return [Float] central_tendency
|
12
17
|
def central_tendency
|
13
18
|
@mean
|
14
19
|
end
|
15
|
-
|
16
|
-
def error
|
17
|
-
@error
|
18
|
-
end
|
19
20
|
|
21
|
+
# Determines how much slower this stat is than the baseline stat
|
22
|
+
# if this average is lower than the faster baseline, higher average is better (e.g. ips) (calculate accordingly)
|
23
|
+
# @param baseline [SD|Bootstrap] faster baseline
|
24
|
+
# @returns [Array<Float, nil>] the slowdown and the error (not calculated for standard deviation)
|
20
25
|
def slowdown(baseline)
|
21
|
-
|
22
|
-
|
26
|
+
if baseline.central_tendency > central_tendency
|
27
|
+
[baseline.central_tendency.to_f / central_tendency, 0]
|
28
|
+
else
|
29
|
+
[central_tendency.to_f / baseline.central_tendency, 0]
|
30
|
+
end
|
23
31
|
end
|
24
32
|
|
25
33
|
def footer
|
26
34
|
nil
|
27
35
|
end
|
28
|
-
|
36
|
+
|
29
37
|
end
|
30
|
-
|
38
|
+
|
31
39
|
end
|
32
40
|
end
|
33
41
|
end
|
data/test/test_benchmark_ips.rb
CHANGED
@@ -20,6 +20,19 @@ class TestBenchmarkIPS < Minitest::Test
|
|
20
20
|
assert $stdout.string.size > 0
|
21
21
|
end
|
22
22
|
|
23
|
+
def test_warmup0
|
24
|
+
$stdout = @old_stdout
|
25
|
+
|
26
|
+
out, err = capture_io do
|
27
|
+
Benchmark.ips(:time => 1, :warmup => 0, :quiet => false) do |x|
|
28
|
+
x.report("sleep 0.25") { sleep(0.25) }
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
refute_match(/Warming up -+/, out)
|
33
|
+
assert_empty err
|
34
|
+
end
|
35
|
+
|
23
36
|
def test_output
|
24
37
|
Benchmark.ips(1) do |x|
|
25
38
|
x.report("operation") { 100 * 100 }
|
@@ -140,6 +153,17 @@ class TestBenchmarkIPS < Minitest::Test
|
|
140
153
|
assert all_data[0][:stddev]
|
141
154
|
end
|
142
155
|
|
156
|
+
def test_ips_empty
|
157
|
+
report = Benchmark.ips do |_x|
|
158
|
+
|
159
|
+
end
|
160
|
+
|
161
|
+
all_data = report.data
|
162
|
+
|
163
|
+
assert all_data
|
164
|
+
assert_equal [], all_data
|
165
|
+
end
|
166
|
+
|
143
167
|
def test_json_output
|
144
168
|
json_file = Tempfile.new("data.json")
|
145
169
|
|
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.
|
4
|
+
version: 2.8.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Evan Phoenix
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2020-05-01 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: minitest
|
@@ -16,42 +16,48 @@ dependencies:
|
|
16
16
|
requirements:
|
17
17
|
- - "~>"
|
18
18
|
- !ruby/object:Gem::Version
|
19
|
-
version: '5.
|
19
|
+
version: '5.14'
|
20
20
|
type: :development
|
21
21
|
prerelease: false
|
22
22
|
version_requirements: !ruby/object:Gem::Requirement
|
23
23
|
requirements:
|
24
24
|
- - "~>"
|
25
25
|
- !ruby/object:Gem::Version
|
26
|
-
version: '5.
|
26
|
+
version: '5.14'
|
27
27
|
- !ruby/object:Gem::Dependency
|
28
28
|
name: rdoc
|
29
29
|
requirement: !ruby/object:Gem::Requirement
|
30
30
|
requirements:
|
31
|
-
- - "
|
31
|
+
- - ">="
|
32
32
|
- !ruby/object:Gem::Version
|
33
33
|
version: '4.0'
|
34
|
+
- - "<"
|
35
|
+
- !ruby/object:Gem::Version
|
36
|
+
version: '7'
|
34
37
|
type: :development
|
35
38
|
prerelease: false
|
36
39
|
version_requirements: !ruby/object:Gem::Requirement
|
37
40
|
requirements:
|
38
|
-
- - "
|
41
|
+
- - ">="
|
39
42
|
- !ruby/object:Gem::Version
|
40
43
|
version: '4.0'
|
44
|
+
- - "<"
|
45
|
+
- !ruby/object:Gem::Version
|
46
|
+
version: '7'
|
41
47
|
- !ruby/object:Gem::Dependency
|
42
48
|
name: hoe
|
43
49
|
requirement: !ruby/object:Gem::Requirement
|
44
50
|
requirements:
|
45
51
|
- - "~>"
|
46
52
|
- !ruby/object:Gem::Version
|
47
|
-
version: '3.
|
53
|
+
version: '3.22'
|
48
54
|
type: :development
|
49
55
|
prerelease: false
|
50
56
|
version_requirements: !ruby/object:Gem::Requirement
|
51
57
|
requirements:
|
52
58
|
- - "~>"
|
53
59
|
- !ruby/object:Gem::Version
|
54
|
-
version: '3.
|
60
|
+
version: '3.22'
|
55
61
|
description: An iterations per second enhancement to Benchmark.
|
56
62
|
email:
|
57
63
|
- evan@phx.io
|
@@ -63,7 +69,6 @@ extra_rdoc_files:
|
|
63
69
|
- README.md
|
64
70
|
files:
|
65
71
|
- ".autotest"
|
66
|
-
- Gemfile.lock
|
67
72
|
- History.txt
|
68
73
|
- Manifest.txt
|
69
74
|
- README.md
|
@@ -82,7 +87,8 @@ files:
|
|
82
87
|
homepage: https://github.com/evanphx/benchmark-ips
|
83
88
|
licenses:
|
84
89
|
- MIT
|
85
|
-
metadata:
|
90
|
+
metadata:
|
91
|
+
homepage_uri: https://github.com/evanphx/benchmark-ips
|
86
92
|
post_install_message:
|
87
93
|
rdoc_options:
|
88
94
|
- "--main"
|
@@ -100,8 +106,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
100
106
|
- !ruby/object:Gem::Version
|
101
107
|
version: '0'
|
102
108
|
requirements: []
|
103
|
-
|
104
|
-
rubygems_version: 2.5.1
|
109
|
+
rubygems_version: 3.0.3
|
105
110
|
signing_key:
|
106
111
|
specification_version: 4
|
107
112
|
summary: An iterations per second enhancement to Benchmark.
|
data/Gemfile.lock
DELETED