benchmark-perf 0.4.0 → 0.5.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG.md +9 -0
- data/README.md +13 -1
- data/Rakefile +0 -3
- data/benchmark-perf.gemspec +3 -3
- data/lib/benchmark/perf.rb +4 -2
- data/lib/benchmark/perf/execution_time.rb +21 -14
- data/lib/benchmark/perf/version.rb +1 -1
- data/spec/spec_helper.rb +3 -3
- data/spec/unit/arithmetic_spec.rb +1 -1
- data/spec/unit/assertions_spec.rb +1 -1
- data/spec/unit/execution_time_spec.rb +33 -7
- data/tasks/console.rake +1 -1
- data/tasks/coverage.rake +1 -1
- data/tasks/spec.rake +1 -1
- metadata +10 -11
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 23be9b198b35a0cd2ba9fce98fe449cc11bf603d85361fd296fce4d25c4e6fcb
|
4
|
+
data.tar.gz: 4e88b12e133ad01323eca2dbae4aa1a36cfcc44390ef9883785fa9df14009618
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 8cc2086bbfcedfa67021a9cd6fdc9ea0a6b04bbedf1457cd8a1921d28dde118a328b95568a0d361313ae0c4f16f18187fc023f76e6f82b185cb28355859d941b
|
7
|
+
data.tar.gz: '0962f8911d08ec0be76097fc7bb7a225031ed943214c6be85dfebd909e606168463061013bd22cfc2e18c782861f6e3b5f12c51f935eec300e5923b63a8e0016'
|
data/CHANGELOG.md
CHANGED
@@ -1,5 +1,14 @@
|
|
1
1
|
# Change log
|
2
2
|
|
3
|
+
## [v0.5.0] - 2019-04-21
|
4
|
+
|
5
|
+
### Added
|
6
|
+
* Add :subprocess option To ExecutionTime#run for toggling forking behaviour
|
7
|
+
|
8
|
+
### Changed
|
9
|
+
* Remove ExecutiomTime#linear_range
|
10
|
+
* Change to relax development dependencies versions
|
11
|
+
|
3
12
|
## [v0.4.0] - 2018-09-30
|
4
13
|
|
5
14
|
### Changed
|
data/README.md
CHANGED
@@ -77,6 +77,14 @@ If you're interested in having debug output to see exact measurements for each i
|
|
77
77
|
Benchmark::Perf::ExecutionTime.run(io: $stdout) { ... }
|
78
78
|
```
|
79
79
|
|
80
|
+
By default all measurements are done in subprocess to isolate them from other process activities. This may have negative consequences, for example when your code uses database connections and transactions. To switch this behaviour off use `:subprocess` option.
|
81
|
+
|
82
|
+
```ruby
|
83
|
+
Benchmark::Perf::ExeuctionTime.run(subprocess: false) { ... }
|
84
|
+
```
|
85
|
+
|
86
|
+
Or use the environment variable `RUN_IN_SUBPROCESS` to toggle the behaviour.
|
87
|
+
|
80
88
|
### 2.2 Iterations
|
81
89
|
|
82
90
|
In order to check how many iterations per second a given code takes do:
|
@@ -105,6 +113,10 @@ Benchmark::Perf::Iteration.run(time: 3.5) { ... } # 3.5 seconds
|
|
105
113
|
4. Push to the branch (`git push origin my-new-feature`)
|
106
114
|
5. Create a new Pull Request
|
107
115
|
|
116
|
+
## Code of Conduct
|
117
|
+
|
118
|
+
Everyone interacting in the Strings project’s codebases, issue trackers, chat rooms and mailing lists is expected to follow the [code of conduct](https://github.com/piotrmurach/benchmark-perf/blob/master/CODE_OF_CONDUCT.md).
|
119
|
+
|
108
120
|
## Copyright
|
109
121
|
|
110
|
-
Copyright (c) 2016
|
122
|
+
Copyright (c) 2016 Piotr Murach. See LICENSE for further details.
|
data/Rakefile
CHANGED
data/benchmark-perf.gemspec
CHANGED
@@ -6,7 +6,7 @@ Gem::Specification.new do |spec|
|
|
6
6
|
spec.name = "benchmark-perf"
|
7
7
|
spec.version = Benchmark::Perf::VERSION
|
8
8
|
spec.authors = ["Piotr Murach"]
|
9
|
-
spec.email = [""]
|
9
|
+
spec.email = ["me@piotrmurach.com"]
|
10
10
|
spec.summary = %q{Execution time and iteration performance benchmarking}
|
11
11
|
spec.description = %q{Execution time and iteration performance benchmarking}
|
12
12
|
spec.homepage = ""
|
@@ -21,7 +21,7 @@ Gem::Specification.new do |spec|
|
|
21
21
|
|
22
22
|
spec.required_ruby_version = '>= 2.0.0'
|
23
23
|
|
24
|
-
spec.add_development_dependency 'bundler', '
|
24
|
+
spec.add_development_dependency 'bundler', '>= 1.16'
|
25
25
|
spec.add_development_dependency 'rspec', '~> 3.0'
|
26
|
-
spec.add_development_dependency 'rake'
|
26
|
+
spec.add_development_dependency 'rake'
|
27
27
|
end
|
data/lib/benchmark/perf.rb
CHANGED
@@ -18,6 +18,7 @@ module Benchmark
|
|
18
18
|
# @api public
|
19
19
|
def average(measurements)
|
20
20
|
return 0 if measurements.empty?
|
21
|
+
|
21
22
|
measurements.reduce(&:+).to_f / measurements.size
|
22
23
|
end
|
23
24
|
module_function :average
|
@@ -31,6 +32,7 @@ module Benchmark
|
|
31
32
|
# @api public
|
32
33
|
def variance(measurements)
|
33
34
|
return 0 if measurements.empty?
|
35
|
+
|
34
36
|
avg = average(measurements)
|
35
37
|
total = measurements.reduce(0) do |sum, x|
|
36
38
|
sum + (x - avg)**2
|
@@ -46,6 +48,7 @@ module Benchmark
|
|
46
48
|
# @api public
|
47
49
|
def std_dev(measurements)
|
48
50
|
return 0 if measurements.empty?
|
51
|
+
|
49
52
|
Math.sqrt(variance(measurements))
|
50
53
|
end
|
51
54
|
module_function :std_dev
|
@@ -81,14 +84,13 @@ module Benchmark
|
|
81
84
|
def time_now
|
82
85
|
Process.clock_gettime Process::CLOCK_MONOTONIC
|
83
86
|
end
|
84
|
-
module_function :time_now
|
85
87
|
else
|
86
88
|
# Object represeting current time
|
87
89
|
def time_now
|
88
90
|
Time.now
|
89
91
|
end
|
90
|
-
module_function :time_now
|
91
92
|
end
|
93
|
+
module_function :time_now
|
92
94
|
|
93
95
|
# Measure time elapsed with a monotonic clock
|
94
96
|
#
|
@@ -6,13 +6,13 @@ module Benchmark
|
|
6
6
|
#
|
7
7
|
# @api public
|
8
8
|
module ExecutionTime
|
9
|
-
#
|
9
|
+
# Check if measurements need to run in subprocess
|
10
10
|
#
|
11
|
-
# @api
|
12
|
-
def
|
13
|
-
|
11
|
+
# @api private
|
12
|
+
def run_in_subprocess?
|
13
|
+
ENV["RUN_IN_SUBPROCESS"] != 'false' && Process.respond_to?(:fork)
|
14
14
|
end
|
15
|
-
module_function :
|
15
|
+
module_function :run_in_subprocess?
|
16
16
|
|
17
17
|
# Isolate run in subprocess
|
18
18
|
#
|
@@ -23,10 +23,14 @@ module Benchmark
|
|
23
23
|
# the elapsed time of the measurement
|
24
24
|
#
|
25
25
|
# @api private
|
26
|
-
def run_in_subprocess(io: nil)
|
27
|
-
return yield unless Process.respond_to?(:fork)
|
26
|
+
def run_in_subprocess(subprocess: true, io: nil)
|
27
|
+
return yield unless subprocess && Process.respond_to?(:fork)
|
28
|
+
return yield unless run_in_subprocess?
|
28
29
|
|
29
30
|
reader, writer = IO.pipe
|
31
|
+
reader.binmode
|
32
|
+
writer.binmode
|
33
|
+
|
30
34
|
pid = Process.fork do
|
31
35
|
GC.start
|
32
36
|
GC.disable if ENV['BENCH_DISABLE_GC']
|
@@ -34,20 +38,21 @@ module Benchmark
|
|
34
38
|
begin
|
35
39
|
reader.close
|
36
40
|
time = yield
|
37
|
-
|
38
41
|
io.print "%9.6f" % data if io
|
39
42
|
Marshal.dump(time, writer)
|
40
43
|
rescue => error
|
41
44
|
Marshal.dump(error, writer)
|
42
45
|
ensure
|
43
46
|
GC.enable if ENV['BENCH_DISABLE_GC']
|
44
|
-
|
47
|
+
writer.close
|
48
|
+
exit # allow finalizers to run
|
45
49
|
end
|
46
50
|
end
|
47
51
|
|
48
52
|
writer.close unless writer.closed?
|
49
53
|
Process.waitpid(pid)
|
50
54
|
data = Marshal.load(reader)
|
55
|
+
reader.close
|
51
56
|
raise data if data.is_a?(Exception)
|
52
57
|
data
|
53
58
|
end
|
@@ -59,10 +64,11 @@ module Benchmark
|
|
59
64
|
# the warmup time
|
60
65
|
#
|
61
66
|
# @api private
|
62
|
-
def run_warmup(warmup: 1, &work)
|
67
|
+
def run_warmup(warmup: 1, io: nil, subprocess: true, &work)
|
63
68
|
GC.start
|
69
|
+
|
64
70
|
warmup.times do
|
65
|
-
run_in_subprocess do
|
71
|
+
run_in_subprocess(io: io, subprocess: subprocess) do
|
66
72
|
Perf.clock_time(&work)
|
67
73
|
end
|
68
74
|
end
|
@@ -81,14 +87,15 @@ module Benchmark
|
|
81
87
|
# average and standard deviation
|
82
88
|
#
|
83
89
|
# @api public
|
84
|
-
def run(repeat: 1, io: nil, warmup: 1, &work)
|
90
|
+
def run(repeat: 1, io: nil, warmup: 1, subprocess: true, &work)
|
85
91
|
check_greater(repeat, 0)
|
86
92
|
measurements = []
|
87
|
-
|
93
|
+
|
94
|
+
run_warmup(warmup: warmup, io: io, subprocess: subprocess, &work)
|
88
95
|
|
89
96
|
repeat.times do
|
90
97
|
GC.start
|
91
|
-
measurements << run_in_subprocess(io: io) do
|
98
|
+
measurements << run_in_subprocess(io: io, subprocess: subprocess) do
|
92
99
|
Perf.clock_time(&work)
|
93
100
|
end
|
94
101
|
end
|
data/spec/spec_helper.rb
CHANGED
@@ -1,6 +1,6 @@
|
|
1
|
-
#
|
1
|
+
# frozen_string_literal: true
|
2
2
|
|
3
|
-
if
|
3
|
+
if ENV['COVERAGE'] || ENV['TRAVIS']
|
4
4
|
require 'simplecov'
|
5
5
|
require 'coveralls'
|
6
6
|
|
@@ -15,7 +15,7 @@ if RUBY_VERSION > '1.9' and (ENV['COVERAGE'] || ENV['TRAVIS'])
|
|
15
15
|
end
|
16
16
|
end
|
17
17
|
|
18
|
-
require
|
18
|
+
require "benchmark-perf"
|
19
19
|
|
20
20
|
RSpec.configure do |config|
|
21
21
|
config.expect_with :rspec do |expectations|
|
@@ -1,37 +1,60 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
RSpec.describe Benchmark::Perf::ExecutionTime do
|
4
|
-
it "provides linear range" do
|
5
|
-
expect(described_class.linear_range(0, 3)).to eq([0,1,2,3])
|
6
|
-
end
|
7
|
-
|
8
4
|
it "provides default benchmark range" do
|
9
5
|
allow(described_class).to receive(:run_in_subprocess).and_return(0.1)
|
6
|
+
|
10
7
|
described_class.run(warmup: 0) { 'x' * 1024 }
|
8
|
+
|
11
9
|
expect(described_class).to have_received(:run_in_subprocess).once
|
12
10
|
end
|
13
11
|
|
14
12
|
it "accepts custom number of samples" do
|
15
13
|
allow(described_class).to receive(:run_in_subprocess).and_return(0.1)
|
14
|
+
|
16
15
|
described_class.run(repeat: 12, warmup: 0) { 'x' * 1024 }
|
16
|
+
|
17
17
|
expect(described_class).to have_received(:run_in_subprocess).exactly(12).times
|
18
18
|
end
|
19
19
|
|
20
|
-
it "
|
20
|
+
it "runs warmup cycles" do
|
21
21
|
allow(described_class).to receive(:run_in_subprocess).and_return(0.1)
|
22
|
+
|
22
23
|
described_class.run(repeat: 1, warmup: 1) { 'x' }
|
24
|
+
|
23
25
|
expect(described_class).to have_received(:run_in_subprocess).twice
|
24
26
|
end
|
25
27
|
|
28
|
+
it "doesn't run in subproces when option :run_in_subprocess is set to false",
|
29
|
+
if: ::Process.respond_to?(:fork) do
|
30
|
+
|
31
|
+
allow(::Process).to receive(:fork)
|
32
|
+
|
33
|
+
described_class.run(subprocess: false) { 'x' * 1024 }
|
34
|
+
|
35
|
+
expect(::Process).to_not have_received(:fork)
|
36
|
+
end
|
37
|
+
|
38
|
+
it "doesn't run in subprocess when RUN_IN_SUBPROCESS env var is set to false",
|
39
|
+
if: ::Process.respond_to?(:fork) do
|
40
|
+
|
41
|
+
allow(::Process).to receive(:fork)
|
42
|
+
allow(ENV).to receive(:[]).with("RUN_IN_SUBPROCESS").and_return('false')
|
43
|
+
|
44
|
+
described_class.run { 'x' * 1024 }
|
45
|
+
|
46
|
+
expect(::Process).to_not have_received(:fork)
|
47
|
+
end
|
48
|
+
|
26
49
|
it "doesn't accept range smaller than 1" do
|
27
50
|
expect {
|
28
51
|
described_class.run(repeat: 0) { 'x' }
|
29
|
-
}.to raise_error(ArgumentError,
|
30
|
-
'Repeat value: 0 needs to be greater than 0')
|
52
|
+
}.to raise_error(ArgumentError, 'Repeat value: 0 needs to be greater than 0')
|
31
53
|
end
|
32
54
|
|
33
55
|
it "provides measurements for 30 samples by default" do
|
34
56
|
sample = described_class.run { 'x' * 1024 }
|
57
|
+
|
35
58
|
expect(sample).to all(be < 0.01)
|
36
59
|
end
|
37
60
|
|
@@ -43,16 +66,19 @@ RSpec.describe Benchmark::Perf::ExecutionTime do
|
|
43
66
|
|
44
67
|
it "measures complex object" do
|
45
68
|
sample = described_class.run { {foo: Object.new, bar: :piotr} }
|
69
|
+
|
46
70
|
expect(sample).to all(be < 0.01)
|
47
71
|
end
|
48
72
|
|
49
73
|
it "executes code to warmup ruby vm" do
|
50
74
|
sample = described_class.run_warmup { 'x' * 1_000_000 }
|
75
|
+
|
51
76
|
expect(sample).to eq(1)
|
52
77
|
end
|
53
78
|
|
54
79
|
it "measures work performance for 10 samples" do
|
55
80
|
sample = described_class.run(repeat: 10) { 'x' * 1_000_000 }
|
81
|
+
|
56
82
|
expect(sample.size).to eq(2)
|
57
83
|
expect(sample).to all(be < 0.01)
|
58
84
|
end
|
data/tasks/console.rake
CHANGED
data/tasks/coverage.rake
CHANGED
data/tasks/spec.rake
CHANGED
metadata
CHANGED
@@ -1,27 +1,27 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: benchmark-perf
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.5.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Piotr Murach
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2019-04-21 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: bundler
|
15
15
|
requirement: !ruby/object:Gem::Requirement
|
16
16
|
requirements:
|
17
|
-
- - "
|
17
|
+
- - ">="
|
18
18
|
- !ruby/object:Gem::Version
|
19
19
|
version: '1.16'
|
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
26
|
version: '1.16'
|
27
27
|
- !ruby/object:Gem::Dependency
|
@@ -42,19 +42,19 @@ dependencies:
|
|
42
42
|
name: rake
|
43
43
|
requirement: !ruby/object:Gem::Requirement
|
44
44
|
requirements:
|
45
|
-
- - "
|
45
|
+
- - ">="
|
46
46
|
- !ruby/object:Gem::Version
|
47
|
-
version: '
|
47
|
+
version: '0'
|
48
48
|
type: :development
|
49
49
|
prerelease: false
|
50
50
|
version_requirements: !ruby/object:Gem::Requirement
|
51
51
|
requirements:
|
52
|
-
- - "
|
52
|
+
- - ">="
|
53
53
|
- !ruby/object:Gem::Version
|
54
|
-
version: '
|
54
|
+
version: '0'
|
55
55
|
description: Execution time and iteration performance benchmarking
|
56
56
|
email:
|
57
|
-
-
|
57
|
+
- me@piotrmurach.com
|
58
58
|
executables: []
|
59
59
|
extensions: []
|
60
60
|
extra_rdoc_files: []
|
@@ -96,8 +96,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
96
96
|
- !ruby/object:Gem::Version
|
97
97
|
version: '0'
|
98
98
|
requirements: []
|
99
|
-
|
100
|
-
rubygems_version: 2.7.3
|
99
|
+
rubygems_version: 3.0.3
|
101
100
|
signing_key:
|
102
101
|
specification_version: 4
|
103
102
|
summary: Execution time and iteration performance benchmarking
|