rspec-benchmark 0.5.1 → 0.6.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 +4 -4
- data/CHANGELOG.md +18 -0
- data/README.md +14 -1
- data/lib/rspec-benchmark.rb +1 -1
- data/lib/rspec/benchmark.rb +3 -3
- data/lib/rspec/benchmark/allocation_matcher.rb +6 -6
- data/lib/rspec/benchmark/comparison_matcher.rb +4 -4
- data/lib/rspec/benchmark/configuration.rb +8 -0
- data/lib/rspec/benchmark/formatter.rb +51 -0
- data/lib/rspec/benchmark/iteration_matcher.rb +18 -5
- data/lib/rspec/benchmark/matchers.rb +16 -16
- data/lib/rspec/benchmark/timing_matcher.rb +13 -13
- data/lib/rspec/benchmark/version.rb +1 -1
- metadata +21 -66
- data/Rakefile +0 -10
- data/lib/rspec/benchmark/format_time.rb +0 -29
- data/rspec-benchmark.gemspec +0 -37
- data/spec/spec_helper.rb +0 -37
- data/spec/unit/comparison_matcher_spec.rb +0 -212
- data/spec/unit/composable_spec.rb +0 -9
- data/spec/unit/configuration_spec.rb +0 -84
- data/spec/unit/format_time_spec.rb +0 -21
- data/spec/unit/perform_allocation_spec.rb +0 -128
- data/spec/unit/perform_at_least_spec.rb +0 -45
- data/spec/unit/perform_constant_spec.rb +0 -46
- data/spec/unit/perform_exponential_spec.rb +0 -42
- data/spec/unit/perform_linear_spec.rb +0 -80
- data/spec/unit/perform_logarithmic_spec.rb +0 -49
- data/spec/unit/perform_power_spec.rb +0 -55
- data/spec/unit/perform_under_spec.rb +0 -74
- data/tasks/coverage.rake +0 -11
- data/tasks/spec.rake +0 -34
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 907b4211a79dbed8db1edb3b2c6a694536302ef576111d6cab8e16ebe0c628f3
|
4
|
+
data.tar.gz: 1ed51ed22ab19a877fafb4c074161b2b4d5c9f2cfc87ac840c552a1b33046825
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: e312397def220c32daa2a2b3f385560cf12852096722434c508279ffcb41d38b2110ca2ce8179c73a83c8d5abb1faeac3b20b4bc2a6af0cf83aed4781489cb61
|
7
|
+
data.tar.gz: a2a1a4f205ee93369b88b354edc6742651a5bd4d0cd8773993c33769227ef1b8e7e62053a05719f8818ef3db96da05af3b1c4ae8ce03ae9bdb8466f7ce68a334
|
data/CHANGELOG.md
CHANGED
@@ -1,5 +1,22 @@
|
|
1
1
|
# Change log
|
2
2
|
|
3
|
+
## [v0.6.0] - 2020-03-09
|
4
|
+
|
5
|
+
### Added
|
6
|
+
* Add Formatter#format_unit for making numbers more readable
|
7
|
+
* Add :format configuration option
|
8
|
+
|
9
|
+
### Changed
|
10
|
+
* Change TimingMatcher to use new #cpu interface
|
11
|
+
* Change IterationMatcher to use new #ips interface
|
12
|
+
* Change IterationMatcher to format iterations with units
|
13
|
+
* Change gemspec to add metadata, remove test artefacts
|
14
|
+
* Change benchmark-perf, benchmark-trend & benchmark-malloc versions
|
15
|
+
|
16
|
+
### Fixed
|
17
|
+
* Fix Ruby 2.7 warnings converting hash into keywowrd arguments
|
18
|
+
* Fix IterationMatcher to stop raising FloatDomainError
|
19
|
+
|
3
20
|
## [v0.5.1] - 2019-09-11
|
4
21
|
|
5
22
|
### Fixed
|
@@ -54,6 +71,7 @@
|
|
54
71
|
|
55
72
|
Initial release
|
56
73
|
|
74
|
+
[v0.6.0]: https://github.com/peter-murach/rspec-benchmark/compare/v0.5.1...v0.6.0
|
57
75
|
[v0.5.1]: https://github.com/peter-murach/rspec-benchmark/compare/v0.5.0...v0.5.1
|
58
76
|
[v0.5.0]: https://github.com/peter-murach/rspec-benchmark/compare/v0.4.0...v0.5.0
|
59
77
|
[v0.4.0]: https://github.com/peter-murach/rspec-benchmark/compare/v0.3.0...v0.4.0
|
data/README.md
CHANGED
@@ -41,6 +41,7 @@ If you are new to performance testing you may find [Caveats](#5-caveats) section
|
|
41
41
|
* [3.1 :disable_gc](#31-disable_gc)
|
42
42
|
* [3.2 :run_in_subprocess](#32-run_in_subprocess)
|
43
43
|
* [3.3 :samples](#33-samples)
|
44
|
+
* [3.4 :format](#34-format)
|
44
45
|
* [4. Filtering](#4-filtering)
|
45
46
|
* [5. Caveats](#5-caveats)
|
46
47
|
|
@@ -269,7 +270,9 @@ expect { |n, i|
|
|
269
270
|
|
270
271
|
The `perform_allocation` matcher checks how much memory or objects have been allocated during a piece of Ruby code execution.
|
271
272
|
|
272
|
-
By default the matcher
|
273
|
+
By default the matcher verifies the number of object allocations. The specified number serves as the _upper limit_ of allocations, so your tests won't become brittle as different Ruby versions change internally how many objects are allocated for some operations.
|
274
|
+
|
275
|
+
Note that you can also check for memory allocation using the `bytes` matcher.
|
273
276
|
|
274
277
|
To check number of objects allocated do:
|
275
278
|
|
@@ -356,6 +359,16 @@ RSpec::Benchmark.configure do |config|
|
|
356
359
|
end
|
357
360
|
```
|
358
361
|
|
362
|
+
### 3.4 `:format`
|
363
|
+
|
364
|
+
The `perform_at_least` matcher uses the `:format` option to format the number of iterations when a failure message gets displayed. By default, the `:human` values is used to make numbers more readable. For example, the `12300 i/s` gets turned into `12.3k i/s`. If you rather have an exact numbers presented do:
|
365
|
+
|
366
|
+
```ruby
|
367
|
+
RSpec::Benchmark.configure do |config|
|
368
|
+
config.format = :raw
|
369
|
+
end
|
370
|
+
```
|
371
|
+
|
359
372
|
## 4. Filtering
|
360
373
|
|
361
374
|
Usually performance tests are best left for CI or occasional runs that do not affect TDD/BDD cycle.
|
data/lib/rspec-benchmark.rb
CHANGED
@@ -1 +1 @@
|
|
1
|
-
require_relative
|
1
|
+
require_relative "rspec/benchmark"
|
data/lib/rspec/benchmark.rb
CHANGED
@@ -1,8 +1,8 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
require_relative
|
4
|
-
require_relative
|
5
|
-
require_relative
|
3
|
+
require_relative "benchmark/configuration"
|
4
|
+
require_relative "benchmark/matchers"
|
5
|
+
require_relative "benchmark/version"
|
6
6
|
|
7
7
|
module RSpec
|
8
8
|
module Benchmark
|
@@ -1,6 +1,6 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
require
|
3
|
+
require "benchmark-malloc"
|
4
4
|
|
5
5
|
module RSpec
|
6
6
|
module Benchmark
|
@@ -31,7 +31,7 @@ module RSpec
|
|
31
31
|
# @api private
|
32
32
|
def matches?(block)
|
33
33
|
@block = block
|
34
|
-
alloc_stats = @bench.
|
34
|
+
alloc_stats = @bench.trace(&block)
|
35
35
|
@actual = nil
|
36
36
|
@actual_retained = nil
|
37
37
|
|
@@ -150,10 +150,10 @@ module RSpec
|
|
150
150
|
|
151
151
|
def objects_to_s(value)
|
152
152
|
if value.respond_to?(:to_hash)
|
153
|
-
value
|
154
|
-
sort_by { |k,v| k.to_s }
|
155
|
-
map { |key, val| "#{val} #{key}" if @objects.keys.include?(key) }
|
156
|
-
compact.join(" and ")
|
153
|
+
value
|
154
|
+
.sort_by { |k, v| k.to_s }
|
155
|
+
.map { |key, val| "#{val} #{key}" if @objects.keys.include?(key) }
|
156
|
+
.compact.join(" and ")
|
157
157
|
else
|
158
158
|
value
|
159
159
|
end
|
@@ -1,6 +1,6 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
require
|
3
|
+
require "benchmark-perf"
|
4
4
|
|
5
5
|
module RSpec
|
6
6
|
module Benchmark
|
@@ -152,9 +152,9 @@ module RSpec
|
|
152
152
|
return "was not a block" unless @actual.is_a?(Proc)
|
153
153
|
|
154
154
|
if @ratio < 1
|
155
|
-
"performed slower by #{format(
|
155
|
+
"performed slower by #{format("%.2f", (@ratio**-1))} times"
|
156
156
|
elsif @ratio > 1
|
157
|
-
"performed faster by #{format(
|
157
|
+
"performed faster by #{format("%.2f", @ratio)} times"
|
158
158
|
else
|
159
159
|
"performed by the same time"
|
160
160
|
end
|
@@ -264,7 +264,7 @@ module RSpec
|
|
264
264
|
|
265
265
|
def check_comparison(type)
|
266
266
|
[:slower, :faster].include?(type) ||
|
267
|
-
(raise ArgumentError,
|
267
|
+
(raise ArgumentError, "comparison_type must be " \
|
268
268
|
":faster or :slower, not `:#{type}`")
|
269
269
|
end
|
270
270
|
end # Matcher
|
@@ -28,11 +28,19 @@ module RSpec
|
|
28
28
|
# @api public
|
29
29
|
attr_accessor :fit_quality
|
30
30
|
|
31
|
+
# The formatting for number of iterations
|
32
|
+
#
|
33
|
+
# @return [String]
|
34
|
+
#
|
35
|
+
# @api public
|
36
|
+
attr_accessor :format
|
37
|
+
|
31
38
|
# @api private
|
32
39
|
def initialize
|
33
40
|
@disable_gc = false
|
34
41
|
@samples = 1
|
35
42
|
@fit_quality = 0.9
|
43
|
+
@format = :human
|
36
44
|
@run_in_subprocess = false
|
37
45
|
end
|
38
46
|
end # Configuration
|
@@ -0,0 +1,51 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module RSpec
|
4
|
+
module Benchmark
|
5
|
+
module Formatter
|
6
|
+
# Format time for easy matcher reporting
|
7
|
+
#
|
8
|
+
# @param [Float] time
|
9
|
+
# the time to format
|
10
|
+
#
|
11
|
+
# @return [String]
|
12
|
+
# the human readable time value
|
13
|
+
#
|
14
|
+
# @api public
|
15
|
+
def format_time(time)
|
16
|
+
if time >= 100.0
|
17
|
+
"%.0f sec" % [time]
|
18
|
+
elsif time >= 1.0
|
19
|
+
"%.3g sec" % [time]
|
20
|
+
elsif time >= 1e-3
|
21
|
+
"%.3g ms" % [time * 1e3]
|
22
|
+
elsif time >= 1e-6
|
23
|
+
"%.3g μs" % [time * 1e6]
|
24
|
+
else
|
25
|
+
"%.3g ns" % [time * 1e9]
|
26
|
+
end
|
27
|
+
end
|
28
|
+
module_function :format_time
|
29
|
+
|
30
|
+
UNITS = ([""] + %w[k M B T Q]).freeze
|
31
|
+
|
32
|
+
# Format large numbers and replace thousands with a unit
|
33
|
+
# for increased readability
|
34
|
+
#
|
35
|
+
# @param [Numeric] number
|
36
|
+
# the number to format
|
37
|
+
#
|
38
|
+
# @return [String]
|
39
|
+
#
|
40
|
+
# @api pubic
|
41
|
+
def format_unit(number)
|
42
|
+
scale = (Math.log10(number) / 3).to_i
|
43
|
+
scale = 0 if scale > 5
|
44
|
+
suffix = UNITS[scale]
|
45
|
+
|
46
|
+
"%.3g#{suffix}" % [number.to_f / (1000 ** scale)]
|
47
|
+
end
|
48
|
+
module_function :format_unit
|
49
|
+
end
|
50
|
+
end # Benchmark
|
51
|
+
end # RSpec
|
@@ -1,6 +1,6 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
require
|
3
|
+
require "benchmark-perf"
|
4
4
|
|
5
5
|
module RSpec
|
6
6
|
module Benchmark
|
@@ -13,7 +13,18 @@ module RSpec
|
|
13
13
|
@iterations = iterations
|
14
14
|
@time = options.fetch(:time) { 0.2 }
|
15
15
|
@warmup = options.fetch(:warmup) { 0.1 }
|
16
|
-
@
|
16
|
+
@format = options.fetch(:format) {
|
17
|
+
RSpec::Benchmark.configuration.format }
|
18
|
+
@bench = ::Benchmark::Perf
|
19
|
+
end
|
20
|
+
|
21
|
+
# Check if human format should be used
|
22
|
+
#
|
23
|
+
# @return [Boolean]
|
24
|
+
#
|
25
|
+
# @api private
|
26
|
+
def human_format?
|
27
|
+
@format == :human
|
17
28
|
end
|
18
29
|
|
19
30
|
# Indicates this matcher matches against a block
|
@@ -29,7 +40,7 @@ module RSpec
|
|
29
40
|
#
|
30
41
|
# @api private
|
31
42
|
def matches?(block)
|
32
|
-
@average, @stddev, = @bench.
|
43
|
+
@average, @stddev, = @bench.ips(time: @time, warmup: @warmup, &block)
|
33
44
|
@iterations <= (@average + 3 * @stddev)
|
34
45
|
end
|
35
46
|
|
@@ -70,11 +81,13 @@ module RSpec
|
|
70
81
|
end
|
71
82
|
|
72
83
|
def description
|
73
|
-
|
84
|
+
iters = human_format? ? Formatter.format_unit(@iterations) : @iterations
|
85
|
+
"perform at least #{iters} i/s"
|
74
86
|
end
|
75
87
|
|
76
88
|
def actual
|
77
|
-
|
89
|
+
avg = human_format? ? Formatter.format_unit(@average) : @average
|
90
|
+
"%s (± %d%%) i/s" % [avg, (@stddev / @average.to_f) * 100]
|
78
91
|
end
|
79
92
|
|
80
93
|
def positive_failure_reason
|
@@ -1,10 +1,10 @@
|
|
1
|
-
# frozen_string_literal
|
1
|
+
# frozen_string_literal: true
|
2
2
|
|
3
|
-
require_relative
|
4
|
-
require_relative
|
5
|
-
require_relative
|
6
|
-
require_relative
|
7
|
-
require_relative
|
3
|
+
require_relative "allocation_matcher"
|
4
|
+
require_relative "comparison_matcher"
|
5
|
+
require_relative "complexity_matcher"
|
6
|
+
require_relative "iteration_matcher"
|
7
|
+
require_relative "timing_matcher"
|
8
8
|
|
9
9
|
module RSpec
|
10
10
|
module Benchmark
|
@@ -35,7 +35,7 @@ module RSpec
|
|
35
35
|
#
|
36
36
|
# @api public
|
37
37
|
def perform_allocation(objects, **options)
|
38
|
-
AllocationMatcher::Matcher.new(objects, options)
|
38
|
+
AllocationMatcher::Matcher.new(objects, **options)
|
39
39
|
end
|
40
40
|
|
41
41
|
# Passes if code block performs at least iterations
|
@@ -48,7 +48,7 @@ module RSpec
|
|
48
48
|
#
|
49
49
|
# @api public
|
50
50
|
def perform_at_least(iterations, **options)
|
51
|
-
IterationMatcher::Matcher.new(iterations, options)
|
51
|
+
IterationMatcher::Matcher.new(iterations, **options)
|
52
52
|
end
|
53
53
|
|
54
54
|
# Passes if code block performs under threshold
|
@@ -62,7 +62,7 @@ module RSpec
|
|
62
62
|
#
|
63
63
|
# @api public
|
64
64
|
def perform_under(threshold, **options)
|
65
|
-
TimingMatcher::Matcher.new(threshold, options)
|
65
|
+
TimingMatcher::Matcher.new(threshold, **options)
|
66
66
|
end
|
67
67
|
|
68
68
|
# Passes if code block performs faster than sample block
|
@@ -75,7 +75,7 @@ module RSpec
|
|
75
75
|
#
|
76
76
|
# @api public
|
77
77
|
def perform_faster_than(**options, &sample)
|
78
|
-
ComparisonMatcher::Matcher.new(sample, :faster, options)
|
78
|
+
ComparisonMatcher::Matcher.new(sample, :faster, **options)
|
79
79
|
end
|
80
80
|
|
81
81
|
# Passes if code block performs slower than sample block
|
@@ -88,7 +88,7 @@ module RSpec
|
|
88
88
|
#
|
89
89
|
# @api public
|
90
90
|
def perform_slower_than(**options, &sample)
|
91
|
-
ComparisonMatcher::Matcher.new(sample, :slower, options)
|
91
|
+
ComparisonMatcher::Matcher.new(sample, :slower, **options)
|
92
92
|
end
|
93
93
|
|
94
94
|
# Pass if code block performs constant
|
@@ -100,7 +100,7 @@ module RSpec
|
|
100
100
|
#
|
101
101
|
# @api public
|
102
102
|
def perform_constant(**options)
|
103
|
-
ComplexityMatcher::Matcher.new(:constant, options)
|
103
|
+
ComplexityMatcher::Matcher.new(:constant, **options)
|
104
104
|
end
|
105
105
|
|
106
106
|
# Pass if code block performs logarithmic
|
@@ -113,7 +113,7 @@ module RSpec
|
|
113
113
|
#
|
114
114
|
# @api public
|
115
115
|
def perform_logarithmic(**options)
|
116
|
-
ComplexityMatcher::Matcher.new(:logarithmic, options)
|
116
|
+
ComplexityMatcher::Matcher.new(:logarithmic, **options)
|
117
117
|
end
|
118
118
|
alias perform_log perform_logarithmic
|
119
119
|
|
@@ -126,7 +126,7 @@ module RSpec
|
|
126
126
|
#
|
127
127
|
# @api public
|
128
128
|
def perform_linear(**options)
|
129
|
-
ComplexityMatcher::Matcher.new(:linear, options)
|
129
|
+
ComplexityMatcher::Matcher.new(:linear, **options)
|
130
130
|
end
|
131
131
|
|
132
132
|
# Pass if code block performs power
|
@@ -138,7 +138,7 @@ module RSpec
|
|
138
138
|
#
|
139
139
|
# @api public
|
140
140
|
def perform_power(**options)
|
141
|
-
ComplexityMatcher::Matcher.new(:power, options)
|
141
|
+
ComplexityMatcher::Matcher.new(:power, **options)
|
142
142
|
end
|
143
143
|
|
144
144
|
# Pass if code block performs exponential
|
@@ -150,7 +150,7 @@ module RSpec
|
|
150
150
|
#
|
151
151
|
# @api public
|
152
152
|
def perform_exponential(**options)
|
153
|
-
ComplexityMatcher::Matcher.new(:exponential, options)
|
153
|
+
ComplexityMatcher::Matcher.new(:exponential, **options)
|
154
154
|
end
|
155
155
|
alias perform_exp perform_exponential
|
156
156
|
|
@@ -1,8 +1,8 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
require
|
3
|
+
require "benchmark-perf"
|
4
4
|
|
5
|
-
require_relative
|
5
|
+
require_relative "formatter"
|
6
6
|
|
7
7
|
module RSpec
|
8
8
|
module Benchmark
|
@@ -18,13 +18,15 @@ module RSpec
|
|
18
18
|
def initialize(threshold, **options)
|
19
19
|
@threshold = threshold
|
20
20
|
@samples = options.fetch(:samples) {
|
21
|
-
RSpec::Benchmark.configuration.samples
|
21
|
+
RSpec::Benchmark.configuration.samples
|
22
|
+
}
|
22
23
|
@warmup = options.fetch(:warmup) { 1 }
|
23
24
|
@subprocess = options.fetch(:subprocess) {
|
24
|
-
RSpec::Benchmark.configuration.run_in_subprocess
|
25
|
+
RSpec::Benchmark.configuration.run_in_subprocess
|
26
|
+
}
|
25
27
|
@scale = threshold.to_s.split(/\./).last.size
|
26
28
|
@block = nil
|
27
|
-
@bench = ::Benchmark::Perf
|
29
|
+
@bench = ::Benchmark::Perf
|
28
30
|
end
|
29
31
|
|
30
32
|
# Indicates this matcher matches against a block
|
@@ -42,10 +44,8 @@ module RSpec
|
|
42
44
|
def matches?(block)
|
43
45
|
@block = block
|
44
46
|
return false unless block.is_a?(Proc)
|
45
|
-
@average, @stddev = @bench.
|
46
|
-
|
47
|
-
subprocess: @subprocess,
|
48
|
-
&block)
|
47
|
+
@average, @stddev = @bench.cpu(repeat: @samples, warmup: @warmup,
|
48
|
+
subprocess: @subprocess, &block)
|
49
49
|
@average <= @threshold
|
50
50
|
end
|
51
51
|
|
@@ -116,20 +116,20 @@ module RSpec
|
|
116
116
|
end
|
117
117
|
|
118
118
|
def description
|
119
|
-
"perform under #{format_time(@threshold)}"
|
119
|
+
"perform under #{Formatter.format_time(@threshold)}"
|
120
120
|
end
|
121
121
|
|
122
122
|
def actual
|
123
|
-
"#{format_time(@average)} (± #{format_time(@stddev)})"
|
123
|
+
"#{Formatter.format_time(@average)} (± #{Formatter.format_time(@stddev)})"
|
124
124
|
end
|
125
125
|
|
126
126
|
def positive_failure_reason
|
127
|
-
return
|
127
|
+
return "was not a block" unless @block.is_a?(Proc)
|
128
128
|
"performed above #{actual} "
|
129
129
|
end
|
130
130
|
|
131
131
|
def negative_failure_reason
|
132
|
-
return
|
132
|
+
return "was not a block" unless @block.is_a?(Proc)
|
133
133
|
"performed #{actual} under"
|
134
134
|
end
|
135
135
|
end # Matcher
|