benchmark-ips 2.3.0 → 2.11.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.
@@ -0,0 +1,50 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'net/http'
4
+ require 'net/https'
5
+ require 'json'
6
+
7
+ module Benchmark
8
+ module IPS
9
+ class Share
10
+ DEFAULT_URL = "https://ips.fastruby.io"
11
+ def initialize(report, job)
12
+ @report = report
13
+ @job = job
14
+ end
15
+
16
+ def share
17
+ base = (ENV['SHARE_URL'] || DEFAULT_URL)
18
+ url = URI(File.join(base, "reports"))
19
+
20
+ req = Net::HTTP::Post.new(url)
21
+
22
+ data = {
23
+ "entries" => @report.data,
24
+ "options" => {
25
+ "compare" => @job.compare?
26
+ }
27
+ }
28
+
29
+ req.body = JSON.generate(data)
30
+
31
+ http = Net::HTTP.new(url.hostname, url.port)
32
+ if url.scheme == "https"
33
+ http.use_ssl = true
34
+ http.ssl_version = :TLSv1_2
35
+ end
36
+
37
+ res = http.start do |h|
38
+ h.request req
39
+ end
40
+
41
+ if Net::HTTPOK === res
42
+ data = JSON.parse res.body
43
+ puts "Shared at: #{File.join(base, data["id"])}"
44
+ else
45
+ puts "Error sharing report"
46
+ end
47
+ end
48
+ end
49
+ end
50
+ end
@@ -0,0 +1,58 @@
1
+ module Benchmark
2
+ module IPS
3
+ module Stats
4
+
5
+ class Bootstrap
6
+ include StatsMetric
7
+ attr_reader :data, :error, :samples
8
+
9
+ def initialize(samples, confidence)
10
+ dependencies
11
+ @iterations = 10_000
12
+ @confidence = (confidence / 100.0).to_s
13
+ @samples = samples
14
+ @data = Kalibera::Data.new({[0] => samples}, [1, samples.size])
15
+ interval = @data.bootstrap_confidence_interval(@iterations, @confidence)
16
+ @median = interval.median
17
+ @error = interval.error
18
+ end
19
+
20
+ # Average stat value
21
+ # @return [Float] central_tendency
22
+ def central_tendency
23
+ @median
24
+ end
25
+
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)
30
+ def slowdown(baseline)
31
+ low, slowdown, high = baseline.data.bootstrap_quotient(@data, @iterations, @confidence)
32
+ error = Timing.mean([slowdown - low, high - slowdown])
33
+ [slowdown, error]
34
+ end
35
+
36
+ def speedup(baseline)
37
+ baseline.slowdown(self)
38
+ end
39
+
40
+ def footer
41
+ "with #{(@confidence.to_f * 100).round(1)}% confidence"
42
+ end
43
+
44
+ def dependencies
45
+ require 'kalibera'
46
+ rescue LoadError
47
+ puts
48
+ puts "Can't load the kalibera gem - this is required to use the :bootstrap stats options."
49
+ puts "It's optional, so we don't formally depend on it and it isn't installed along with benchmark-ips."
50
+ puts "You probably want to do something like 'gem install kalibera' to fix this."
51
+ abort
52
+ end
53
+
54
+ end
55
+
56
+ end
57
+ end
58
+ end
@@ -0,0 +1,45 @@
1
+ module Benchmark
2
+ module IPS
3
+ module Stats
4
+
5
+ class SD
6
+ include StatsMetric
7
+ attr_reader :error, :samples
8
+
9
+ def initialize(samples)
10
+ @samples = samples
11
+ @mean = Timing.mean(samples)
12
+ @error = Timing.stddev(samples, @mean).round
13
+ end
14
+
15
+ # Average stat value
16
+ # @return [Float] central_tendency
17
+ def central_tendency
18
+ @mean
19
+ end
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)
25
+ def slowdown(baseline)
26
+ if baseline.central_tendency > central_tendency
27
+ [baseline.central_tendency.to_f / central_tendency, nil]
28
+ else
29
+ [central_tendency.to_f / baseline.central_tendency, nil]
30
+ end
31
+ end
32
+
33
+ def speedup(baseline)
34
+ baseline.slowdown(self)
35
+ end
36
+
37
+ def footer
38
+ nil
39
+ end
40
+
41
+ end
42
+
43
+ end
44
+ end
45
+ end
@@ -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
data/lib/benchmark/ips.rb CHANGED
@@ -1,7 +1,14 @@
1
1
  # encoding: utf-8
2
2
  require 'benchmark/timing'
3
3
  require 'benchmark/compare'
4
+ require 'benchmark/ips/stats/stats_metric'
5
+ require 'benchmark/ips/stats/sd'
6
+ require 'benchmark/ips/stats/bootstrap'
4
7
  require 'benchmark/ips/report'
8
+ require 'benchmark/ips/noop_suite'
9
+ require 'benchmark/ips/job/entry'
10
+ require 'benchmark/ips/job/stdout_report'
11
+ require 'benchmark/ips/job/noop_report'
5
12
  require 'benchmark/ips/job'
6
13
 
7
14
  # Performance benchmarking library
@@ -11,10 +18,10 @@ module Benchmark
11
18
  module IPS
12
19
 
13
20
  # Benchmark-ips Gem version.
14
- VERSION = "2.3.0"
21
+ VERSION = "2.11.0"
15
22
 
16
23
  # CODENAME of current version.
17
- CODENAME = "Monsoon BBQ"
24
+ CODENAME = "We Do This Once A Year"
18
25
 
19
26
  # Measure code in block, each code's benchmarked result will display in
20
27
  # iteration per second with standard deviation in given time.
@@ -28,47 +35,43 @@ module Benchmark
28
35
  time, warmup, quiet = args
29
36
  end
30
37
 
31
- suite = nil
32
-
33
38
  sync, $stdout.sync = $stdout.sync, true
34
39
 
35
- if defined? Benchmark::Suite and Suite.current
36
- suite = Benchmark::Suite.current
37
- end
38
-
39
- quiet ||= (suite && suite.quiet?)
40
-
41
- job = Job.new({:suite => suite,
42
- :quiet => quiet
43
- })
40
+ job = Job.new
44
41
 
45
42
  job_opts = {}
46
43
  job_opts[:time] = time unless time.nil?
47
44
  job_opts[:warmup] = warmup unless warmup.nil?
45
+ job_opts[:quiet] = quiet unless quiet.nil?
48
46
 
49
47
  job.config job_opts
50
48
 
51
49
  yield job
52
50
 
53
- $stdout.puts "Calculating -------------------------------------" unless quiet
54
-
55
- job.run_warmup
56
-
57
- $stdout.puts "-------------------------------------------------" unless quiet
51
+ job.load_held_results
58
52
 
59
53
  job.run
60
54
 
55
+ if job.run_single? && job.all_results_have_been_run?
56
+ job.clear_held_results
57
+ else
58
+ job.save_held_results
59
+ puts '', 'Pausing here -- run Ruby again to measure the next benchmark...' if job.run_single?
60
+ end
61
+
61
62
  $stdout.sync = sync
63
+ job.run_comparison
64
+ job.generate_json
62
65
 
63
- if job.compare?
64
- job.run_comparison
65
- end
66
+ report = job.full_report
66
67
 
67
- if job.json?
68
- job.generate_json
68
+ if ENV['SHARE'] || ENV['SHARE_URL']
69
+ require 'benchmark/ips/share'
70
+ share = Share.new report, job
71
+ share.share
69
72
  end
70
73
 
71
- return job.full_report
74
+ report
72
75
  end
73
76
 
74
77
  # Set options for running the benchmarks.
@@ -100,4 +103,68 @@ module Benchmark
100
103
  end
101
104
 
102
105
  extend Benchmark::IPS # make ips available as module-level method
106
+
107
+ ##
108
+ # :singleton-method: ips
109
+ #
110
+ # require 'benchmark/ips'
111
+ #
112
+ # Benchmark.ips do |x|
113
+ # # Configure the number of seconds used during
114
+ # # the warmup phase (default 2) and calculation phase (default 5)
115
+ # x.config(:time => 5, :warmup => 2)
116
+ #
117
+ # # These parameters can also be configured this way
118
+ # x.time = 5
119
+ # x.warmup = 2
120
+ #
121
+ # # Typical mode, runs the block as many times as it can
122
+ # x.report("addition") { 1 + 2 }
123
+ #
124
+ # # To reduce overhead, the number of iterations is passed in
125
+ # # and the block must run the code the specific number of times.
126
+ # # Used for when the workload is very small and any overhead
127
+ # # introduces incorrectable errors.
128
+ # x.report("addition2") do |times|
129
+ # i = 0
130
+ # while i < times
131
+ # 1 + 2
132
+ # i += 1
133
+ # end
134
+ # end
135
+ #
136
+ # # To reduce overhead even more, grafts the code given into
137
+ # # the loop that performs the iterations internally to reduce
138
+ # # overhead. Typically not needed, use the |times| form instead.
139
+ # x.report("addition3", "1 + 2")
140
+ #
141
+ # # Really long labels should be formatted correctly
142
+ # x.report("addition-test-long-label") { 1 + 2 }
143
+ #
144
+ # # Compare the iterations per second of the various reports!
145
+ # x.compare!
146
+ # end
147
+ #
148
+ # This will generate the following report:
149
+ #
150
+ # Calculating -------------------------------------
151
+ # addition 71.254k i/100ms
152
+ # addition2 68.658k i/100ms
153
+ # addition3 83.079k i/100ms
154
+ # addition-test-long-label
155
+ # 70.129k i/100ms
156
+ # -------------------------------------------------
157
+ # addition 4.955M (± 8.7%) i/s - 24.155M
158
+ # addition2 24.011M (± 9.5%) i/s - 114.246M
159
+ # addition3 23.958M (±10.1%) i/s - 115.064M
160
+ # addition-test-long-label
161
+ # 5.014M (± 9.1%) i/s - 24.545M
162
+ #
163
+ # Comparison:
164
+ # addition2: 24011974.8 i/s
165
+ # addition3: 23958619.8 i/s - 1.00x slower
166
+ # addition-test-long-label: 5014756.0 i/s - 4.79x slower
167
+ # addition: 4955278.9 i/s - 4.85x slower
168
+ #
169
+ # See also Benchmark::IPS
103
170
  end
@@ -1,12 +1,14 @@
1
1
  module Benchmark
2
2
  # Perform caclulations on Timing results.
3
3
  module Timing
4
+ # Microseconds per second.
5
+ MICROSECONDS_PER_SECOND = 1_000_000
4
6
 
5
7
  # Calculate (arithmetic) mean of given samples.
6
8
  # @param [Array] samples Samples to calculate mean.
7
9
  # @return [Float] Mean of given samples.
8
10
  def self.mean(samples)
9
- sum = samples.inject(0) { |acc, i| acc + i }
11
+ sum = samples.inject(:+)
10
12
  sum / samples.size
11
13
  end
12
14
 
@@ -29,21 +31,7 @@ module Benchmark
29
31
  Math.sqrt variance(samples, m)
30
32
  end
31
33
 
32
- # Resample mean of given samples.
33
- # @param [Integer] resample_times Resample times, defaults to 100.
34
- # @return [Array] Resampled samples.
35
- def self.resample_mean(samples, resample_times=100)
36
- resamples = []
37
-
38
- resample_times.times do
39
- resample = samples.map { samples[rand(samples.size)] }
40
- resamples << Timing.mean(resample)
41
- end
42
-
43
- resamples
44
- end
45
-
46
- # Recycle unsed objects by starting Garbage Collector.
34
+ # Recycle used objects by starting Garbage Collector.
47
35
  def self.clean_env
48
36
  # rbx
49
37
  if GC.respond_to? :run
@@ -52,5 +40,40 @@ module Benchmark
52
40
  GC.start
53
41
  end
54
42
  end
43
+
44
+ # Use a monotonic clock if available, otherwise use Time
45
+ begin
46
+ Process.clock_gettime Process::CLOCK_MONOTONIC, :float_microsecond
47
+
48
+ # Get an object that represents now and can be converted to microseconds
49
+ def self.now
50
+ Process.clock_gettime Process::CLOCK_MONOTONIC, :float_microsecond
51
+ end
52
+
53
+ # Add one second to the time represenetation
54
+ def self.add_second(t, s)
55
+ t + (s * MICROSECONDS_PER_SECOND)
56
+ end
57
+
58
+ # Return the number of microseconds between the 2 moments
59
+ def self.time_us(before, after)
60
+ after - before
61
+ end
62
+ rescue NameError
63
+ # Get an object that represents now and can be converted to microseconds
64
+ def self.now
65
+ Time.now
66
+ end
67
+
68
+ # Add one second to the time represenetation
69
+ def self.add_second(t, s)
70
+ t + s
71
+ end
72
+
73
+ # Return the number of microseconds between the 2 moments
74
+ def self.time_us(before, after)
75
+ (after.to_f - before.to_f) * MICROSECONDS_PER_SECOND
76
+ end
77
+ end
55
78
  end
56
79
  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.3.0
4
+ version: 2.11.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Evan Phoenix
8
- autorequire:
8
+ autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2015-07-20 00:00:00.000000000 Z
11
+ date: 2015-01-12 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: minitest
@@ -16,14 +16,14 @@ dependencies:
16
16
  requirements:
17
17
  - - "~>"
18
18
  - !ruby/object:Gem::Version
19
- version: '5.6'
19
+ version: '5.4'
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.6'
26
+ version: '5.4'
27
27
  - !ruby/object:Gem::Dependency
28
28
  name: rdoc
29
29
  requirement: !ruby/object:Gem::Requirement
@@ -38,47 +38,41 @@ dependencies:
38
38
  - - "~>"
39
39
  - !ruby/object:Gem::Version
40
40
  version: '4.0'
41
- - !ruby/object:Gem::Dependency
42
- name: hoe
43
- requirement: !ruby/object:Gem::Requirement
44
- requirements:
45
- - - "~>"
46
- - !ruby/object:Gem::Version
47
- version: '3.13'
48
- type: :development
49
- prerelease: false
50
- version_requirements: !ruby/object:Gem::Requirement
51
- requirements:
52
- - - "~>"
53
- - !ruby/object:Gem::Version
54
- version: '3.13'
55
41
  description: A iterations per second enhancement to Benchmark.
56
42
  email:
57
43
  - evan@phx.io
58
44
  executables: []
59
45
  extensions: []
60
46
  extra_rdoc_files:
61
- - History.txt
62
- - Manifest.txt
47
+ - History.md
48
+ - LICENSE
63
49
  - README.md
64
50
  files:
65
- - ".autotest"
66
- - ".gemtest"
67
- - History.txt
68
- - Manifest.txt
51
+ - History.md
52
+ - LICENSE
69
53
  - README.md
70
- - Rakefile
54
+ - examples/advanced.rb
55
+ - examples/hold.rb
56
+ - examples/save.rb
57
+ - examples/simple.rb
71
58
  - lib/benchmark/compare.rb
72
59
  - lib/benchmark/ips.rb
73
60
  - lib/benchmark/ips/job.rb
61
+ - lib/benchmark/ips/job/entry.rb
62
+ - lib/benchmark/ips/job/noop_report.rb
63
+ - lib/benchmark/ips/job/stdout_report.rb
64
+ - lib/benchmark/ips/noop_suite.rb
74
65
  - lib/benchmark/ips/report.rb
66
+ - lib/benchmark/ips/share.rb
67
+ - lib/benchmark/ips/stats/bootstrap.rb
68
+ - lib/benchmark/ips/stats/sd.rb
69
+ - lib/benchmark/ips/stats/stats_metric.rb
75
70
  - lib/benchmark/timing.rb
76
- - test/test_benchmark_ips.rb
77
71
  homepage: https://github.com/evanphx/benchmark-ips
78
72
  licenses:
79
73
  - MIT
80
74
  metadata: {}
81
- post_install_message:
75
+ post_install_message:
82
76
  rdoc_options:
83
77
  - "--main"
84
78
  - README.md
@@ -95,9 +89,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
95
89
  - !ruby/object:Gem::Version
96
90
  version: '0'
97
91
  requirements: []
98
- rubyforge_project:
99
- rubygems_version: 2.2.2
100
- signing_key:
92
+ rubygems_version: 3.3.20
93
+ signing_key:
101
94
  specification_version: 4
102
95
  summary: A iterations per second enhancement to Benchmark.
103
96
  test_files: []
data/.autotest DELETED
@@ -1,23 +0,0 @@
1
- # -*- ruby -*-
2
-
3
- require 'autotest/restart'
4
-
5
- # Autotest.add_hook :initialize do |at|
6
- # at.extra_files << "../some/external/dependency.rb"
7
- #
8
- # at.libs << ":../some/external"
9
- #
10
- # at.add_exception 'vendor'
11
- #
12
- # at.add_mapping(/dependency.rb/) do |f, _|
13
- # at.files_matching(/test_.*rb$/)
14
- # end
15
- #
16
- # %w(TestA TestB).each do |klass|
17
- # at.extra_class_map[klass] = "test/test_misc.rb"
18
- # end
19
- # end
20
-
21
- # Autotest.add_hook :run_command do |at|
22
- # system "rake build"
23
- # end
data/.gemtest DELETED
File without changes
data/History.txt DELETED
@@ -1,87 +0,0 @@
1
- === 2.3.0 / 2015-07-20
2
-
3
- * 2 minor features:
4
- * Support keyword arguments
5
- * Allow any datatype for labels (use #to_s conversion)
6
-
7
- * 1 doc/test changes:
8
- * Newer Travis for 1.8.7, ree, and 2.2.2
9
-
10
- * 3 PRs merged:
11
- * Merge pull request #41 from kbrock/kwargs-support
12
- * Merge pull request #42 from kbrock/newer_travis
13
- * Merge pull request #43 from kbrock/non_to_s_labels
14
-
15
- === 2.2.0 / 2015-05-09
16
-
17
- * 1 minor features:
18
- * Fix quiet mode
19
- * Allow passing a custom suite via config
20
- * Silent a job if a suite was passed and is quiet
21
- * Export report to json file.
22
- * Accept symbol as report's argument.
23
-
24
- * 2 doc fixes:
25
- * Squish duplicate `to` in README
26
- * Update copyright to 2015. [ci skip]
27
-
28
- * 9 PRs merged:
29
- * Merge pull request #37 from splattael/patch-1
30
- * Merge pull request #36 from kirs/quiet-mode
31
- * Merge pull request #35 from JuanitoFatas/doc/suite
32
- * Merge pull request #34 from splattael/config-suite
33
- * Merge pull request #33 from splattael/suite-quiet
34
- * Merge pull request #32 from O-I/remove-gemfile-lock
35
- * Merge pull request #31 from JuanitoFatas/doc/bump-copyright-year
36
- * Merge pull request #29 from JuanitoFatas/feature/json-export
37
- * Merge pull request #26 from JuanitoFatas/feature/takes-symbol-as-report-parameter
38
-
39
- === 2.1.1 / 2015-01-12
40
-
41
- * 1 minor fix:
42
- * Don't send label through printf so that % work directly
43
-
44
- * 1 documenation changes:
45
- * Use HEREDOC and wrap at 80 chars for example result description
46
-
47
- * 1 usage fix:
48
- * Add gemspec for use via bundler git
49
-
50
- * 1 PR merged:
51
- * Merge pull request #24 from zzak/simple-format-result-description
52
-
53
- === 2.1.0 / 2014-11-10
54
-
55
- * Documentation changes:
56
- * Many documentation fixes by Juanito Fatas!
57
- * Minor readme fix by Will Leinweber
58
-
59
- * 2 minor features:
60
- * Displaying the total runtime for a job is suppressed unless interesting
61
- * Formatting of large values improved (human vs raw mode)
62
- * Contributed by Charles Oliver Nutter
63
-
64
- === 2.0.0 / 2014-06-18
65
-
66
- * The 'Davy Stevenson' release!
67
- * Codename: Springtime Hummingbird Dance
68
-
69
- * Big API refactoring so the internal bits are easier to use
70
- * Bump to 2.0 because return types changed to make the API better
71
-
72
- * Contributors added:
73
- * Davy Stevenson
74
- * Juanito Fatas
75
- * Benoit Daloze
76
- * Matias
77
- * Tony Arcieri
78
- * Vipul A M
79
- * Zachary Scott
80
- * schneems (Richard Schneeman)
81
-
82
- === 1.0.0 / 2012-03-23
83
-
84
- * 1 major enhancement
85
-
86
- * Birthday!
87
-
data/Manifest.txt DELETED
@@ -1,11 +0,0 @@
1
- .autotest
2
- History.txt
3
- Manifest.txt
4
- README.md
5
- Rakefile
6
- lib/benchmark/compare.rb
7
- lib/benchmark/ips.rb
8
- lib/benchmark/ips/report.rb
9
- lib/benchmark/ips/job.rb
10
- lib/benchmark/timing.rb
11
- test/test_benchmark_ips.rb
data/Rakefile DELETED
@@ -1,26 +0,0 @@
1
- # -*- ruby -*-
2
-
3
- require 'rubygems'
4
- require 'hoe'
5
-
6
- Hoe.plugin :minitest
7
- Hoe.plugin :git
8
-
9
- hoe = Hoe.spec 'benchmark-ips' do
10
- developer('Evan Phoenix', 'evan@phx.io')
11
-
12
- self.readme_file = 'README.md'
13
-
14
- license "MIT"
15
- end
16
-
17
- file "#{hoe.spec.name}.gemspec" => ['Rakefile', "lib/benchmark/ips.rb"] do |t|
18
- puts "Generating #{t.name}"
19
- File.open(t.name, 'wb') { |f| f.write hoe.spec.to_ruby }
20
- end
21
-
22
- desc "Generate or update the standalone gemspec file for the project"
23
- task :gemspec => ["#{hoe.spec.name}.gemspec"]
24
-
25
-
26
- # vim: syntax=ruby