benchmark_suite 0.8.0 → 1.0.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.
@@ -4,10 +4,7 @@ Manifest.txt
4
4
  README.txt
5
5
  Rakefile
6
6
  bin/benchmark
7
- lib/benchmark/compare.rb
8
- lib/benchmark/ips.rb
9
7
  lib/benchmark/suite-run.rb
10
8
  lib/benchmark/suite.rb
11
- lib/benchmark/timing.rb
12
9
  lib/benchmark_suite.rb
13
10
  test/test_benchmark_suite.rb
data/README.txt CHANGED
@@ -20,7 +20,7 @@ A set of enhancements to the standard library benchmark.rb
20
20
 
21
21
  require 'benchmark/ips'
22
22
 
23
- Benchmark.ips do
23
+ Benchmark.ips do |x|
24
24
  # Typical mode, runs the block as many times as it can
25
25
  x.report("addition") { 1 + 2 }
26
26
 
data/Rakefile CHANGED
@@ -12,6 +12,7 @@ require 'hoe'
12
12
 
13
13
  Hoe.spec 'benchmark_suite' do
14
14
  developer('Evan Phoenix', 'evan@fallingsnow.net')
15
+ dependency "benchmark-ips", "~> 1.0"
15
16
  end
16
17
 
17
18
  # vim: syntax=ruby
@@ -2,6 +2,8 @@ require 'benchmark'
2
2
 
3
3
  module Benchmark
4
4
  class Suite
5
+ @current = nil
6
+
5
7
  def self.current
6
8
  @current
7
9
  end
@@ -37,9 +39,10 @@ module Benchmark
37
39
  @reports = {}
38
40
  @order = []
39
41
  @quiet = false
42
+ @verbose = false
40
43
  end
41
44
 
42
- attr_reader :reports
45
+ attr_reader :reports, :report
43
46
 
44
47
  def quiet!
45
48
  @quiet = true
@@ -82,7 +85,7 @@ module Benchmark
82
85
  rescue Exception => e
83
86
  STDOUT.puts "\nError in #{file}:"
84
87
  if e.respond_to? :render
85
- e.render(STDERR)
88
+ e.render
86
89
  else
87
90
  STDOUT.puts e.backtrace
88
91
  end
@@ -1,3 +1,7 @@
1
+ require 'benchmark/suite'
2
+ require 'benchmark/ips'
3
+ require 'benchmark/helpers'
4
+
1
5
  class BenchmarkSuite
2
- VERSION = '0.8.0'
6
+ VERSION = '1.0.0'
3
7
  end
@@ -2,7 +2,19 @@ require "test/unit"
2
2
  require "benchmark_suite"
3
3
 
4
4
  class TestBenchmarkSuite < Test::Unit::TestCase
5
- def test_sanity
6
- flunk "write tests or I will kneecap you"
5
+ def test_ips
6
+ s = Benchmark::Suite.create do |s|
7
+ s.quiet!
8
+
9
+ Benchmark.ips(1,1) do |x|
10
+ x.report("sleep") { sleep(0.25) }
11
+ end
12
+ end
13
+
14
+ rep = s.report.first
15
+
16
+ assert_equal "sleep", rep.label
17
+ assert_equal 4, rep.iterations
18
+ assert_in_delta 4.0, rep.ips, 0.2
7
19
  end
8
20
  end
metadata CHANGED
@@ -1,13 +1,13 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: benchmark_suite
3
3
  version: !ruby/object:Gem::Version
4
- hash: 63
4
+ hash: 23
5
5
  prerelease:
6
6
  segments:
7
+ - 1
7
8
  - 0
8
- - 8
9
9
  - 0
10
- version: 0.8.0
10
+ version: 1.0.0
11
11
  platform: ruby
12
12
  authors:
13
13
  - Evan Phoenix
@@ -15,25 +15,53 @@ autorequire:
15
15
  bindir: bin
16
16
  cert_chain: []
17
17
 
18
- date: 2011-04-05 00:00:00 -07:00
19
- default_executable:
18
+ date: 2012-03-24 00:00:00 Z
20
19
  dependencies:
21
20
  - !ruby/object:Gem::Dependency
22
- name: hoe
21
+ name: benchmark-ips
23
22
  prerelease: false
24
23
  requirement: &id001 !ruby/object:Gem::Requirement
25
24
  none: false
26
25
  requirements:
27
- - - ">="
26
+ - - ~>
28
27
  - !ruby/object:Gem::Version
29
- hash: 41
28
+ hash: 15
30
29
  segments:
31
- - 2
32
- - 9
33
30
  - 1
34
- version: 2.9.1
35
- type: :development
31
+ - 0
32
+ version: "1.0"
33
+ type: :runtime
36
34
  version_requirements: *id001
35
+ - !ruby/object:Gem::Dependency
36
+ name: rdoc
37
+ prerelease: false
38
+ requirement: &id002 !ruby/object:Gem::Requirement
39
+ none: false
40
+ requirements:
41
+ - - ~>
42
+ - !ruby/object:Gem::Version
43
+ hash: 19
44
+ segments:
45
+ - 3
46
+ - 10
47
+ version: "3.10"
48
+ type: :development
49
+ version_requirements: *id002
50
+ - !ruby/object:Gem::Dependency
51
+ name: hoe
52
+ prerelease: false
53
+ requirement: &id003 !ruby/object:Gem::Requirement
54
+ none: false
55
+ requirements:
56
+ - - ~>
57
+ - !ruby/object:Gem::Version
58
+ hash: 31
59
+ segments:
60
+ - 2
61
+ - 14
62
+ version: "2.14"
63
+ type: :development
64
+ version_requirements: *id003
37
65
  description: A set of enhancements to the standard library benchmark.rb
38
66
  email:
39
67
  - evan@fallingsnow.net
@@ -52,15 +80,11 @@ files:
52
80
  - README.txt
53
81
  - Rakefile
54
82
  - bin/benchmark
55
- - lib/benchmark/compare.rb
56
- - lib/benchmark/ips.rb
57
83
  - lib/benchmark/suite-run.rb
58
84
  - lib/benchmark/suite.rb
59
- - lib/benchmark/timing.rb
60
85
  - lib/benchmark_suite.rb
61
86
  - test/test_benchmark_suite.rb
62
87
  - .gemtest
63
- has_rdoc: true
64
88
  homepage: http://github.com/evanphx/benchmark_suite
65
89
  licenses: []
66
90
 
@@ -91,7 +115,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
91
115
  requirements: []
92
116
 
93
117
  rubyforge_project: benchmark_suite
94
- rubygems_version: 1.6.2
118
+ rubygems_version: 1.8.18
95
119
  signing_key:
96
120
  specification_version: 3
97
121
  summary: A set of enhancements to the standard library benchmark.rb
@@ -1,41 +0,0 @@
1
- module Benchmark
2
- def compare(*reports)
3
- return if reports.size < 2
4
-
5
- iter = false
6
- sorted = reports.sort do |a,b|
7
- if a.respond_to? :ips
8
- iter = true
9
- b.ips <=> a.ips
10
- else
11
- a.runtime <=> b.runtime
12
- end
13
- end
14
-
15
- best = sorted.shift
16
-
17
- STDOUT.puts "\nComparison:"
18
-
19
- if iter
20
- STDOUT.printf "%20s: %10.1f i/s\n", best.label, best.ips
21
- else
22
- STDOUT.puts "#{best.rjust(20)}: #{best.runtime}s"
23
- end
24
-
25
- sorted.each do |report|
26
- name = report.label
27
-
28
- if iter
29
- x = (best.ips.to_f / report.ips.to_f)
30
- STDOUT.printf "%20s: %10.1f i/s - %.2fx slower\n", name, report.ips, x
31
- else
32
- x = "%.2f" % (report.ips.to_f / best.ips.to_f)
33
- STDOUT.puts "#{name.rjust(20)}: #{report.runtime}s - #{x}x slower"
34
- end
35
- end
36
-
37
- STDOUT.puts
38
- end
39
-
40
- module_function :compare
41
- end
@@ -1,243 +0,0 @@
1
- # encoding: utf-8
2
- require 'benchmark/timing'
3
- require 'benchmark/compare'
4
-
5
- module Benchmark
6
-
7
- class IPSReport
8
- def initialize(label, us, iters, ips, ips_sd, cycles)
9
- @label = label
10
- @microseconds = us
11
- @iterations = iters
12
- @ips = ips
13
- @ips_sd = ips_sd
14
- @measurement_cycle = cycles
15
- end
16
-
17
- attr_reader :label, :microseconds, :iterations, :ips, :ips_sd, :measurement_cycle
18
-
19
- def seconds
20
- @microseconds.to_f / 1_000_000.0
21
- end
22
-
23
- def stddev_percentage
24
- 100.0 * (@ips_sd.to_f / @ips.to_f)
25
- end
26
-
27
- alias_method :runtime, :seconds
28
-
29
- def body
30
- left = "%10.1f (±%.1f%%) i/s" % [ips, stddev_percentage]
31
- left.ljust(20) + (" - %10d in %10.6fs (cycle=%d)" %
32
- [@iterations, runtime, @measurement_cycle])
33
- end
34
-
35
- def header
36
- @label.rjust(20)
37
- end
38
-
39
- def to_s
40
- "#{header} #{body}"
41
- end
42
-
43
- def display
44
- STDOUT.puts to_s
45
- end
46
- end
47
-
48
- class IPSJob
49
- class Entry
50
- def initialize(label, action)
51
- @label = label
52
-
53
- if action.kind_of? String
54
- compile action
55
- @action = self
56
- @as_action = true
57
- else
58
- unless action.respond_to? :call
59
- raise ArgumentError, "invalid action, must respond to #call"
60
- end
61
-
62
- @action = action
63
-
64
- if action.respond_to? :arity and action.arity > 0
65
- @call_loop = true
66
- else
67
- @call_loop = false
68
- end
69
-
70
- @as_action = false
71
- end
72
- end
73
-
74
- attr_reader :label, :action
75
-
76
- def as_action?
77
- @as_action
78
- end
79
-
80
- def call_times(times)
81
- return @action.call(times) if @call_loop
82
-
83
- act = @action
84
-
85
- i = 0
86
- while i < times
87
- act.call
88
- i += 1
89
- end
90
- end
91
-
92
- def compile(str)
93
- m = (class << self; self; end)
94
- code = <<-CODE
95
- def call_times(__total);
96
- __i = 0
97
- while __i < __total
98
- #{str};
99
- __i += 1
100
- end
101
- end
102
- CODE
103
- m.class_eval code
104
- end
105
- end
106
-
107
- def initialize
108
- @list = []
109
- @compare = false
110
- end
111
-
112
- attr_reader :compare
113
-
114
- def compare!
115
- @compare = true
116
- end
117
-
118
- #
119
- # Registers the given label and block pair in the job list.
120
- #
121
- def item(label="", str=nil, &blk) # :yield:
122
- if blk and str
123
- raise ArgmentError, "specify a block and a str, but not both"
124
- end
125
-
126
- action = str || blk
127
- raise ArgmentError, "no block or string" unless action
128
-
129
- @list.push Entry.new(label, action)
130
- self
131
- end
132
-
133
- alias_method :report, :item
134
-
135
- # An array of 2-element arrays, consisting of label and block pairs.
136
- attr_reader :list
137
- end
138
-
139
- def ips(time=5, warmup=2)
140
- suite = nil
141
-
142
- sync, STDOUT.sync = STDOUT.sync, true
143
-
144
- if defined? Benchmark::Suite and Suite.current
145
- suite = Benchmark::Suite.current
146
- end
147
-
148
- job = IPSJob.new
149
- yield job
150
-
151
- start = Timing::TimeVal.new
152
- cur = Timing::TimeVal.new
153
-
154
- before = Timing::TimeVal.new
155
- after = Timing::TimeVal.new
156
-
157
- reports = []
158
-
159
- job.list.each do |item|
160
- suite.warming item.label, warmup if suite
161
-
162
- Timing.clean_env
163
-
164
- if !suite or !suite.quiet?
165
- if item.label.size > 20
166
- STDOUT.print "#{item.label}\n#{' ' * 20}"
167
- else
168
- STDOUT.print item.label.rjust(20)
169
- end
170
- end
171
-
172
- before.update!
173
- start.update!
174
- cur.update!
175
-
176
- warmup_iter = 0
177
-
178
- until start.elapsed?(cur, warmup)
179
- item.call_times(1)
180
- warmup_iter += 1
181
- cur.update!
182
- end
183
-
184
- after.update!
185
-
186
- warmup_time = before.diff(after)
187
-
188
- # calculate the time to run approx 100ms
189
-
190
- cycles_per_100ms = ((100_000 / warmup_time.to_f) * warmup_iter).to_i
191
- cycles_per_100ms = 1 if cycles_per_100ms <= 0
192
-
193
- suite.warmup_stats warmup_time, cycles_per_100ms if suite
194
-
195
- Timing.clean_env
196
-
197
- suite.running item.label, time if suite
198
-
199
- iter = 0
200
- start.update!
201
- cur.update!
202
-
203
- measurements = []
204
-
205
- until start.elapsed?(cur, time)
206
- before.update!
207
- item.call_times cycles_per_100ms
208
- after.update!
209
-
210
- iter += cycles_per_100ms
211
- cur.update!
212
-
213
- measurements << before.diff(after)
214
- end
215
-
216
- measured_us = measurements.inject(0) { |a,i| a + i }
217
-
218
- seconds = measured_us.to_f / 1_000_000.0
219
-
220
- all_ips = measurements.map { |i| cycles_per_100ms.to_f / (i.to_f / 1_000_000) }
221
-
222
- avg_ips = Timing.mean(all_ips)
223
- sd_ips = Timing.stddev(all_ips).round
224
-
225
- rep = IPSReport.new(item.label, measured_us, iter, avg_ips, sd_ips, cycles_per_100ms)
226
-
227
- STDOUT.puts " #{rep.body}" if !suite or !suite.quiet?
228
-
229
- suite.add_report rep, caller(1).first if suite
230
-
231
- STDOUT.sync = sync
232
-
233
- reports << rep
234
- end
235
-
236
- if job.compare
237
- Benchmark.compare *reports
238
- end
239
- end
240
-
241
-
242
- module_function :ips
243
- end
@@ -1,137 +0,0 @@
1
- if !defined?(RUBY_ENGINE) or RUBY_ENGINE != "rbx"
2
- require 'rubygems'
3
- end
4
-
5
- require 'ffi'
6
-
7
- module Benchmark
8
- module Timing
9
- extend FFI::Library
10
-
11
- ffi_lib FFI::Library::LIBC
12
-
13
- attach_function :gettimeofday, [:pointer, :pointer], :int
14
-
15
- class TimeVal < FFI::Struct
16
- layout :tv_sec, :time_t, :tv_usec, :suseconds_t
17
-
18
- def sec
19
- self[:tv_sec]
20
- end
21
-
22
- def usec
23
- self[:tv_usec]
24
- end
25
-
26
- def update!
27
- Timing.gettimeofday to_ptr, nil
28
- end
29
-
30
- def to_time
31
- Time.at sec, usec
32
- end
33
-
34
- def <(tv)
35
- return true if sec < tv.sec
36
- return true if usec < tv.usec
37
- return false
38
- end
39
-
40
- def ==(tv)
41
- if sec == tv.sec and usec == tv.usec
42
- return true
43
- end
44
- return false
45
- end
46
-
47
- def diff(tv)
48
- if tv.sec == sec
49
- return tv.usec - usec
50
- end
51
-
52
- sec_diff = tv.sec - sec
53
-
54
- usec_diff = tv.usec - usec
55
- if usec_diff < 0
56
- sec_diff -= 1
57
- usec_diff += 1_000_000
58
- end
59
-
60
- (sec_diff * 1_000_000) + usec_diff
61
- end
62
-
63
- def >(tv)
64
- tv < self
65
- end
66
-
67
- def elapsed?(tv, second)
68
- target = sec + second
69
- cur_tv = tv.sec
70
-
71
- return true if target < cur_tv
72
- return true if target == cur_tv and usec < tv.usec
73
-
74
- return false
75
- end
76
-
77
- end
78
-
79
- def self.resolution
80
- samples = []
81
-
82
- t1 = TimeVal.new
83
- t2 = TimeVal.new
84
-
85
- 30.times do
86
- t1.update!
87
-
88
- while true
89
- t2.update!
90
- break if t2 != t1
91
- end
92
-
93
- samples << t1.diff(t2)
94
- end
95
-
96
- sum = samples.inject(0) { |acc, i| acc + i }
97
- sum / 30
98
- end
99
-
100
- def self.mean(samples)
101
- sum = samples.inject(0) { |acc, i| acc + i }
102
- sum / samples.size
103
- end
104
-
105
- def self.variance(samples, m=nil)
106
- m ||= mean(samples)
107
-
108
- total = samples.inject(0) { |acc, i| acc + ((i - m) ** 2) }
109
-
110
- total / samples.size
111
- end
112
-
113
- def self.stddev(samples, m=nil)
114
- Math.sqrt variance(samples, m)
115
- end
116
-
117
- def self.resample_mean(samples, resample_times=100)
118
- resamples = []
119
-
120
- resample_times.times do
121
- resample = samples.map { samples[rand(samples.size)] }
122
- resamples << Timing.mean(resample)
123
- end
124
-
125
- resamples
126
- end
127
-
128
- def self.clean_env
129
- # rbx
130
- if GC.respond_to? :run
131
- GC.run(true)
132
- else
133
- GC.start
134
- end
135
- end
136
- end
137
- end