benchmark-ips 2.3.0 → 2.11.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -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