motion-benchmark-ips 1.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 14cfdbe4568670fda3739ecd7a9837aa0b21a7c7
4
+ data.tar.gz: 550e6b910b78289a5b525450ed4ad0238e1b2e82
5
+ SHA512:
6
+ metadata.gz: 9acf976811223997ed734be9570a30e188b5282374fab9215d0028e12034106143464de40d3b1e144cc3bfb55b1f95f912a6d103d1f1181a776c77c118feca01
7
+ data.tar.gz: d00d71ba9fd3abdfaade152324a6b390099d5e5881be137ce8b856818d66f89edf64bcd10d90f19db13c6da9d14837aec4bda464c81a7e73d3f46857fd5128f6
@@ -0,0 +1,44 @@
1
+ # motion-benchmark-ips
2
+
3
+ Provides iteration per second benchmarking for RubyMotion.
4
+ The original is https://github.com/evanphx/benchmark-ips.
5
+
6
+ ## Installation
7
+
8
+ Add this line to your application's Gemfile:
9
+
10
+ gem 'motion-benchmark-ips'
11
+
12
+ And then execute:
13
+
14
+ $ bundle
15
+
16
+ Or install it yourself as:
17
+
18
+ $ gem install motion-benchmark-ips
19
+
20
+
21
+ ## LICENSE:
22
+
23
+ (The MIT License)
24
+
25
+ Copyright (c) 2014 Watson
26
+
27
+ Permission is hereby granted, free of charge, to any person obtaining
28
+ a copy of this software and associated documentation files (the
29
+ 'Software'), to deal in the Software without restriction, including
30
+ without limitation the rights to use, copy, modify, merge, publish,
31
+ distribute, sublicense, and/or sell copies of the Software, and to
32
+ permit persons to whom the Software is furnished to do so, subject to
33
+ the following conditions:
34
+
35
+ The above copyright notice and this permission notice shall be
36
+ included in all copies or substantial portions of the Software.
37
+
38
+ THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,
39
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
40
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
41
+ IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
42
+ CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
43
+ TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
44
+ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
@@ -0,0 +1,8 @@
1
+ unless defined?(Motion::Project::Config)
2
+ raise "This file must be required within a RubyMotion project Rakefile."
3
+ end
4
+
5
+ lib_dir_path = File.dirname(File.expand_path(__FILE__))
6
+ Motion::Project::App.setup do |app|
7
+ app.files.unshift(Dir.glob(File.join(lib_dir_path, "project/**/*.rb")))
8
+ end
@@ -0,0 +1,41 @@
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
@@ -0,0 +1,265 @@
1
+ # encoding: utf-8
2
+ # require 'benchmark/timing'
3
+ # require 'benchmark/compare'
4
+
5
+ module Benchmark
6
+
7
+ class IPSReport
8
+ VERSION = "1.1.0"
9
+
10
+ def initialize(label, us, iters, ips, ips_sd, cycles)
11
+ @label = label
12
+ @microseconds = us
13
+ @iterations = iters
14
+ @ips = ips
15
+ @ips_sd = ips_sd
16
+ @measurement_cycle = cycles
17
+ end
18
+
19
+ attr_reader :label, :microseconds, :iterations, :ips, :ips_sd, :measurement_cycle
20
+
21
+ def seconds
22
+ @microseconds.to_f / 1_000_000.0
23
+ end
24
+
25
+ def stddev_percentage
26
+ 100.0 * (@ips_sd.to_f / @ips.to_f)
27
+ end
28
+
29
+ alias_method :runtime, :seconds
30
+
31
+ def body
32
+ left = "%10.1f (±%.1f%%) i/s" % [ips, stddev_percentage]
33
+ left.ljust(20) + (" - %10d in %10.6fs" % [@iterations, runtime])
34
+ end
35
+
36
+ def header
37
+ @label.rjust(20)
38
+ end
39
+
40
+ def to_s
41
+ "#{header} #{body}"
42
+ end
43
+
44
+ def display
45
+ $stdout.puts to_s
46
+ end
47
+ end
48
+
49
+ class IPSJob
50
+ class Entry
51
+ def initialize(label, action)
52
+ @label = label
53
+
54
+ if action.kind_of? String
55
+ compile action
56
+ @action = self
57
+ @as_action = true
58
+ else
59
+ unless action.respond_to? :call
60
+ raise ArgumentError, "invalid action, must respond to #call"
61
+ end
62
+
63
+ @action = action
64
+
65
+ if action.respond_to? :arity and action.arity > 0
66
+ @call_loop = true
67
+ else
68
+ @call_loop = false
69
+ end
70
+
71
+ @as_action = false
72
+ end
73
+ end
74
+
75
+ attr_reader :label, :action
76
+
77
+ def as_action?
78
+ @as_action
79
+ end
80
+
81
+ def call_times(times)
82
+ return @action.call(times) if @call_loop
83
+
84
+ act = @action
85
+
86
+ i = 0
87
+ while i < times
88
+ act.call
89
+ i += 1
90
+ end
91
+ end
92
+
93
+ def compile(str)
94
+ m = (class << self; self; end)
95
+ code = <<-CODE
96
+ def call_times(__total);
97
+ __i = 0
98
+ while __i < __total
99
+ #{str};
100
+ __i += 1
101
+ end
102
+ end
103
+ CODE
104
+ m.class_eval code
105
+ end
106
+ end
107
+
108
+ def initialize
109
+ @list = []
110
+ @compare = false
111
+ end
112
+
113
+ attr_reader :compare
114
+
115
+ def compare!
116
+ @compare = true
117
+ end
118
+
119
+ #
120
+ # Registers the given label and block pair in the job list.
121
+ #
122
+ def item(label="", str=nil, &blk) # :yield:
123
+ if blk and str
124
+ raise ArgumentError, "specify a block and a str, but not both"
125
+ end
126
+
127
+ action = str || blk
128
+ raise ArgumentError, "no block or string" unless action
129
+
130
+ @list.push Entry.new(label, action)
131
+ self
132
+ end
133
+
134
+ alias_method :report, :item
135
+
136
+ # An array of 2-element arrays, consisting of label and block pairs.
137
+ attr_reader :list
138
+ end
139
+
140
+ def ips(time=5, warmup=2)
141
+ suite = nil
142
+
143
+ sync, $stdout.sync = $stdout.sync, true
144
+
145
+ if defined? Benchmark::Suite and Suite.current
146
+ suite = Benchmark::Suite.current
147
+ end
148
+
149
+ quiet = suite && !suite.quiet?
150
+
151
+ job = IPSJob.new
152
+ yield job
153
+
154
+ reports = []
155
+
156
+ timing = {}
157
+
158
+ $stdout.puts "Calculating -------------------------------------" unless quiet
159
+
160
+ job.list.each do |item|
161
+ suite.warming item.label, warmup if suite
162
+
163
+ Timing.clean_env
164
+
165
+ unless quiet
166
+ if item.label.size > 20
167
+ $stdout.print "#{item.label}\n#{' ' * 20}"
168
+ else
169
+ $stdout.print item.label.rjust(20)
170
+ end
171
+ end
172
+
173
+ before = Time.now
174
+ target = Time.now + warmup
175
+
176
+ warmup_iter = 0
177
+
178
+ while Time.now < target
179
+ item.call_times(1)
180
+ warmup_iter += 1
181
+ end
182
+
183
+ after = Time.now
184
+
185
+ warmup_time = (after.to_f - before.to_f) * 1_000_000.0
186
+
187
+ # calculate the time to run approx 100ms
188
+
189
+ cycles_per_100ms = ((100_000 / warmup_time) * warmup_iter).to_i
190
+ cycles_per_100ms = 1 if cycles_per_100ms <= 0
191
+
192
+ timing[item] = cycles_per_100ms
193
+
194
+ $stdout.printf "%10d i/100ms\n", cycles_per_100ms unless quiet
195
+
196
+ suite.warmup_stats warmup_time, cycles_per_100ms if suite
197
+ end
198
+
199
+ $stdout.puts "-------------------------------------------------" unless quiet
200
+
201
+ job.list.each do |item|
202
+ unless quiet
203
+ if item.label.size > 20
204
+ $stdout.print "#{item.label}\n#{' ' * 20}"
205
+ else
206
+ $stdout.print item.label.rjust(20)
207
+ end
208
+ end
209
+
210
+ Timing.clean_env
211
+
212
+ suite.running item.label, time if suite
213
+
214
+ iter = 0
215
+
216
+ target = Time.now + time
217
+
218
+ measurements = []
219
+
220
+ cycles_per_100ms = timing[item]
221
+
222
+ while Time.now < target
223
+ before = Time.now
224
+ item.call_times cycles_per_100ms
225
+ after = Time.now
226
+
227
+ # If for some reason the timing said this too no time (O_o)
228
+ # then ignore the iteration entirely and start another.
229
+ #
230
+ m = ((after.to_f - before.to_f) * 1_000_000.0)
231
+ next if m <= 0.0
232
+
233
+ iter += cycles_per_100ms
234
+
235
+ measurements << m
236
+ end
237
+
238
+ measured_us = measurements.inject(0) { |a,i| a + i }
239
+
240
+ all_ips = measurements.map { |i| cycles_per_100ms.to_f / (i.to_f / 1_000_000) }
241
+
242
+ avg_ips = Timing.mean(all_ips)
243
+ sd_ips = Timing.stddev(all_ips).round
244
+
245
+ rep = IPSReport.new(item.label, measured_us, iter, avg_ips, sd_ips, cycles_per_100ms)
246
+
247
+ $stdout.puts " #{rep.body}" unless quiet
248
+
249
+ suite.add_report rep, caller(1).first if suite
250
+
251
+ reports << rep
252
+ end
253
+
254
+ $stdout.sync = sync
255
+
256
+ if job.compare
257
+ Benchmark.compare(*reports)
258
+ end
259
+
260
+ return reports
261
+ end
262
+
263
+
264
+ module_function :ips
265
+ end
@@ -0,0 +1,40 @@
1
+ module Benchmark
2
+ module Timing
3
+ def self.mean(samples)
4
+ sum = samples.inject(0) { |acc, i| acc + i }
5
+ sum / samples.size
6
+ end
7
+
8
+ def self.variance(samples, m=nil)
9
+ m ||= mean(samples)
10
+
11
+ total = samples.inject(0) { |acc, i| acc + ((i - m) ** 2) }
12
+
13
+ total / samples.size
14
+ end
15
+
16
+ def self.stddev(samples, m=nil)
17
+ Math.sqrt variance(samples, m)
18
+ end
19
+
20
+ def self.resample_mean(samples, resample_times=100)
21
+ resamples = []
22
+
23
+ resample_times.times do
24
+ resample = samples.map { samples[rand(samples.size)] }
25
+ resamples << Timing.mean(resample)
26
+ end
27
+
28
+ resamples
29
+ end
30
+
31
+ def self.clean_env
32
+ # rbx
33
+ if GC.respond_to? :run
34
+ GC.run(true)
35
+ else
36
+ GC.start
37
+ end
38
+ end
39
+ end
40
+ end
metadata ADDED
@@ -0,0 +1,63 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: motion-benchmark-ips
3
+ version: !ruby/object:Gem::Version
4
+ version: '1.0'
5
+ platform: ruby
6
+ authors:
7
+ - Watson
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2014-01-24 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: rake
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - ">="
18
+ - !ruby/object:Gem::Version
19
+ version: '0'
20
+ type: :development
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - ">="
25
+ - !ruby/object:Gem::Version
26
+ version: '0'
27
+ description: Provides iteration per second benchmarking for RubyMotion
28
+ email:
29
+ - watson1978@gmail.com
30
+ executables: []
31
+ extensions: []
32
+ extra_rdoc_files: []
33
+ files:
34
+ - README.md
35
+ - lib/motion-benchmark-ips.rb
36
+ - lib/project/compare.rb
37
+ - lib/project/ips.rb
38
+ - lib/project/timing.rb
39
+ homepage: ''
40
+ licenses:
41
+ - MIT
42
+ metadata: {}
43
+ post_install_message:
44
+ rdoc_options: []
45
+ require_paths:
46
+ - lib
47
+ required_ruby_version: !ruby/object:Gem::Requirement
48
+ requirements:
49
+ - - ">="
50
+ - !ruby/object:Gem::Version
51
+ version: '0'
52
+ required_rubygems_version: !ruby/object:Gem::Requirement
53
+ requirements:
54
+ - - ">="
55
+ - !ruby/object:Gem::Version
56
+ version: '0'
57
+ requirements: []
58
+ rubyforge_project:
59
+ rubygems_version: 2.2.0
60
+ signing_key:
61
+ specification_version: 4
62
+ summary: Provides iteration per second benchmarking for RubyMotion
63
+ test_files: []