benchmark-bigo 0.0.1

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.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 423aefb007643b70b3a3b6948ec4be73a699e39e
4
+ data.tar.gz: 58fb68d5bc09db75769948213ba3d7f493cdc433
5
+ SHA512:
6
+ metadata.gz: 5725e3a65ab19f74b6ebcb12a949247abf1d66cd22ebe8394da76e876ce1014a3628c1398e39daaab81597137f67976c88dcc564e07c4994c747bb47aaea311b
7
+ data.tar.gz: 674a6df9fa33fc2963906343d0f11dad96e4ab12345186743f6d5a3d0c3df40e82b9d318342e76917a2cdac3c7e1628add50bf296423cb1d6056c6346c5cecc3
data/.gemtest ADDED
File without changes
data/History.txt ADDED
@@ -0,0 +1,6 @@
1
+ === 0.0.1 / 2014-05-12
2
+
3
+ * 1 major enhancement
4
+
5
+ * Birthday!
6
+
data/Manifest.txt ADDED
@@ -0,0 +1,8 @@
1
+ History.txt
2
+ Manifest.txt
3
+ README.md
4
+ Rakefile
5
+ lib/benchmark/bigo.rb
6
+ lib/benchmark/bigo/report.rb
7
+ lib/benchmark/bigo/job.rb
8
+ lib/benchmark/bigo/chart.erb
data/README.md ADDED
@@ -0,0 +1,91 @@
1
+ [![Build Status](https://secure.travis-ci.org/davy/benchmark-bigo.png)](http://travis-ci.org/davy/benchmark-bigo)
2
+
3
+ # benchmark-bigo
4
+
5
+ * http://github.com/davy/benchmark-bigo
6
+
7
+ ## DESCRIPTION:
8
+
9
+ Benchmark objects to help calculate Big O behavior
10
+
11
+ ## SYNOPSIS:
12
+
13
+ ```ruby
14
+ require 'benchmark/bigo'
15
+
16
+ report = Benchmark.bigo do |x|
17
+
18
+
19
+ # increments is the total number of data points to collect
20
+ x.increments = 6
21
+
22
+ # generator should construct a test object of the given size
23
+ # example of an Array generator
24
+ x.generator {|size| (0...size).to_a.shuffle }
25
+
26
+ # specifies how the size of the object should grow
27
+ # options: linear, logarithmic
28
+ #
29
+ # specifies that arrays should grow linearly by 1000
30
+ x.linear 1000
31
+
32
+ # report takes a label and a block.
33
+ # block is passed in the generated object and the size of that object
34
+ x.report("#at") {|generated, size| generated.at rand(size) }
35
+ x.report("#index") {|generated, size| generated.index rand(size) }
36
+ x.report("#empty-index") {|generated, size| generated.index 'foo' }
37
+
38
+ # save results in JSON format
39
+ x.data! 'chart_array_simple.json'
40
+
41
+ # generate HTML chart using ChartKick
42
+ x.chart! 'chart_array_simple.html'
43
+
44
+ # for each report, create a comparison chart showing the report
45
+ # and scaled series for O(log n), O(n), O(n log n), and O(n squared)
46
+ x.compare!
47
+
48
+ end
49
+ ```
50
+
51
+ ## REQUIREMENTS:
52
+
53
+ * benchmark-ips (http://github.com/evanphx/benchmark-ips)
54
+
55
+ ## INSTALL:
56
+
57
+ $ gem install benchmark-bigo
58
+
59
+ ## DEVELOPERS:
60
+
61
+ After checking out the source, run:
62
+
63
+ $ rake newb
64
+
65
+ This task will install any missing dependencies, run the tests/specs,
66
+ and generate the RDoc.
67
+
68
+ ## LICENSE:
69
+
70
+ (The MIT License)
71
+
72
+ Copyright (c) 2014 Davy Stevenson
73
+
74
+ Permission is hereby granted, free of charge, to any person obtaining
75
+ a copy of this software and associated documentation files (the
76
+ 'Software'), to deal in the Software without restriction, including
77
+ without limitation the rights to use, copy, modify, merge, publish,
78
+ distribute, sublicense, and/or sell copies of the Software, and to
79
+ permit persons to whom the Software is furnished to do so, subject to
80
+ the following conditions:
81
+
82
+ The above copyright notice and this permission notice shall be
83
+ included in all copies or substantial portions of the Software.
84
+
85
+ THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,
86
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
87
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
88
+ IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
89
+ CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
90
+ TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
91
+ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/Rakefile ADDED
@@ -0,0 +1,20 @@
1
+ # -*- ruby -*-
2
+
3
+ require "rubygems"
4
+ require "hoe"
5
+
6
+ Hoe.plugin :minitest
7
+
8
+ Hoe.spec "benchmark-bigo" do
9
+
10
+ developer("Davy Stevenson", "davy.stevenson@gmail.com")
11
+
12
+ extra_deps << ["benchmark-ips", '~> 2.0']
13
+ extra_deps << ["chartkick", '~> 1.2', '>= 1.2.4']
14
+
15
+ self.readme_file = 'README.md'
16
+
17
+ license "MIT" # this should match the license in the README
18
+ end
19
+
20
+ # vim: syntax=ruby
@@ -0,0 +1,53 @@
1
+ # encoding: utf-8
2
+ require 'erb'
3
+ require 'chartkick'
4
+ require 'benchmark/ips'
5
+ require 'benchmark/bigo/report'
6
+ require 'benchmark/bigo/job'
7
+
8
+ module Benchmark
9
+
10
+ module BigO
11
+ VERSION = "0.0.1"
12
+
13
+ def bigo
14
+ suite = nil
15
+
16
+ sync, $stdout.sync = $stdout.sync, true
17
+
18
+ if defined? Benchmark::Suite and Suite.current
19
+ suite = Benchmark::Suite.current
20
+ end
21
+
22
+ quiet = suite && !suite.quiet?
23
+
24
+ job = Job.new({:suite => suite,
25
+ :quiet => quiet
26
+ })
27
+
28
+ yield job
29
+
30
+ $stdout.puts "Calculating -------------------------------------" unless quiet
31
+
32
+ job.run_warmup
33
+
34
+ $stdout.puts "-------------------------------------------------" unless quiet
35
+
36
+ job.run
37
+
38
+ if job.data?
39
+ job.generate_data
40
+ end
41
+
42
+ if job.chart?
43
+ job.generate_chart
44
+ end
45
+
46
+ $stdout.sync = sync
47
+
48
+ return job.full_report
49
+ end
50
+ end
51
+
52
+ extend Benchmark::BigO
53
+ end
@@ -0,0 +1,17 @@
1
+ <html>
2
+ <head>
3
+ <script src="http://code.jquery.com/jquery-2.1.1.min.js"></script>
4
+ <script src="http://www.google.com/jsapi"></script>
5
+ <script src="http://code.highcharts.com/highcharts.js"></script>
6
+ <script src="http://chartkick.com/chartkick.js"></script>
7
+ </head>
8
+ <body>
9
+
10
+ <% for chart in charts %>
11
+ <h1><%= chart[:name] %></h1>
12
+
13
+ <%= line_chart chart[:data], chart[:opts] %>
14
+ <% end %>
15
+ </body>
16
+ </html>
17
+
@@ -0,0 +1,204 @@
1
+ module Benchmark
2
+
3
+ module BigO
4
+ class Job < IPS::Job
5
+
6
+ class Entry < IPS::Job::Entry
7
+
8
+ def initialize label, action, generated, size
9
+ super label, action
10
+
11
+ if @as_action
12
+ raise "as_action not supported yet"
13
+ else
14
+ raise ArgumentError if action.arity != 2
15
+ @call_loop = false
16
+ end
17
+
18
+ # these objects can be very large, do not want
19
+ # them to be displayed as part of inspect
20
+ define_singleton_method(:generated) { generated }
21
+ define_singleton_method(:size) { size }
22
+ end
23
+
24
+ def call_times(times)
25
+ act = @action
26
+
27
+ i = 0
28
+ while i < times
29
+ act.call generated, size
30
+ i += 1
31
+ end
32
+ end
33
+
34
+ end
35
+
36
+ include Chartkick::Helper
37
+
38
+ # how many total increments are being measured
39
+ attr_accessor :increments
40
+
41
+ # whether to graph the results on a log scale
42
+ attr_accessor :logscale
43
+
44
+ # whether to generate a chart of the results
45
+ # if nil, do not generate chart
46
+ # else string is name of file to write chart out to
47
+ attr_reader :chart
48
+
49
+ def initialize opts={}
50
+ super
51
+
52
+ @full_report = Report.new
53
+ @generator = nil
54
+
55
+ # defaults
56
+ linear
57
+ @increments = 5
58
+ @logscale = false
59
+ @chart = nil
60
+ @data_file = nil
61
+ end
62
+
63
+ def config opts
64
+ super
65
+ @increments = opts[:increments] if opts[:increments]
66
+ @logscale = opts[:logscale] if opts[:logscale]
67
+ @full_report.logscale! if @logscale
68
+ end
69
+
70
+ def chart?
71
+ @chart
72
+ end
73
+
74
+ def chart! filename='chart.html'
75
+ @chart = filename
76
+ end
77
+
78
+ def data?
79
+ @data_file
80
+ end
81
+
82
+ def data! filename='data.json'
83
+ @data_file = filename
84
+ end
85
+
86
+ def logscale= val
87
+ @logscale = val
88
+ @full_report.logscale! if @logscale
89
+ end
90
+
91
+ def generator &blk
92
+ @generator = blk
93
+
94
+ raise ArgumentError, "no block" unless @generator
95
+ end
96
+
97
+
98
+ # use a generator that creates a randomized object
99
+ # represented by the symbol passed to the method
100
+ def generate sym
101
+
102
+ case sym
103
+
104
+ # generates an Array containing shuffled integer values from 0 to size
105
+ when :array
106
+ @generator = Proc.new{|size| (0...size).to_a.shuffle }
107
+
108
+ # when :string
109
+ # to do
110
+
111
+ else
112
+ raise "#{sym} is not a supported object type"
113
+ end
114
+ end
115
+
116
+ # custom incrementer
117
+ def incrementer &blk
118
+ @incrementer = blk
119
+ raise ArgumentError, "no block" unless @incrementer
120
+ end
121
+
122
+ # linear incrementer
123
+ def linear increments=100
124
+ @incrementer = Proc.new {|i| i * increments }
125
+ @logscale = false
126
+ end
127
+
128
+ # logarithmic incrementer
129
+ def logarithmic base=10
130
+ @incrementer = Proc.new {|i| base ** (i-1) }
131
+ @full_report.logscale!
132
+ @logscale = true
133
+ end
134
+
135
+ def sizes
136
+ (1..@increments).collect do |idx|
137
+ @incrementer.call(idx).to_i
138
+ end
139
+ end
140
+
141
+ def item label="", str=nil, &blk # :yield:
142
+ if blk and str
143
+ raise ArgumentError, "specify a block and a str, but not both"
144
+ end
145
+
146
+ action = str || blk
147
+ raise ArgumentError, "no block or string" unless action
148
+
149
+ for size in sizes
150
+ generated = @generator.call(size)
151
+
152
+ label_size = "#{label} #{size}"
153
+ @list.push Entry.new(label_size, action, generated, size)
154
+ end
155
+
156
+ self
157
+ end
158
+ alias_method :report, :item
159
+
160
+ def run_warmup
161
+ super
162
+
163
+ max_timing = @timing.values.max
164
+ @full_report.per_iterations = 10**Math.log10(max_timing).ceil
165
+ end
166
+
167
+ def generate_data
168
+ return if @data_file.nil?
169
+
170
+ all_data = @full_report.chart_data
171
+
172
+ File.open @data_file, 'w' do |f|
173
+ f.write JSON.pretty_generate(all_data)
174
+ end
175
+ end
176
+
177
+ def generate_chart
178
+ return if @chart.nil?
179
+
180
+ all_data = @full_report.chart_data
181
+
182
+ charts = []
183
+ charts << { name: 'Growth Chart', data: all_data, opts: @full_report.chart_opts(all_data) }
184
+
185
+ if compare?
186
+ all_sizes = sizes
187
+ for chart_data in all_data
188
+ comparison_data = @full_report.comparison_chart_data chart_data, all_sizes
189
+ charts << { name: chart_data[:name], data: comparison_data, opts: @full_report.chart_opts(chart_data) }
190
+ end
191
+ end
192
+
193
+ template_file = File.join File.dirname(__FILE__), 'chart.erb'
194
+ template = ERB.new(File.read(template_file))
195
+
196
+ File.open @chart, 'w' do |f|
197
+ f.write template.result(binding)
198
+ end
199
+
200
+ end
201
+
202
+ end
203
+ end
204
+ end
@@ -0,0 +1,130 @@
1
+ module Benchmark
2
+
3
+ module BigO
4
+ class Report
5
+
6
+ attr_accessor :per_iterations
7
+ attr_reader :entries
8
+
9
+ def initialize
10
+ @per_iterations = 0
11
+ @entries = {}
12
+ @logscale = false
13
+ end
14
+
15
+ def logscale?
16
+ @logscale
17
+ end
18
+
19
+ def logscale!
20
+ @logscale = true
21
+ end
22
+
23
+ def add_entry label, microseconds, iters, ips, ips_sd, measurement_cycle
24
+ group_label = label.split(' ').first
25
+
26
+ @entries[group_label] ||= []
27
+ @entries[group_label] << Benchmark::IPS::Report::Entry.new(label, microseconds, iters, ips, ips_sd, measurement_cycle)
28
+ @entries[group_label].last
29
+ end
30
+
31
+ def scaled_iterations
32
+ (@per_iterations.to_f * 50 )
33
+ end
34
+
35
+ def chart_hash group_label
36
+ @entries[group_label].collect do |report|
37
+ size = report.label.split(' ').last.to_i
38
+ seconds_per_scaled_iters = scaled_iterations / report.ips.to_f
39
+
40
+ {label: size,
41
+ seconds_per_scaled_iters: seconds_per_scaled_iters,
42
+ ips: report.ips
43
+ }
44
+ end
45
+ end
46
+
47
+ def chart_for group_label
48
+ chart_hash = chart_hash group_label
49
+ Hash[chart_hash.collect{|h| [h[:label], h[:seconds_per_scaled_iters]]}]
50
+ end
51
+
52
+ def chart_data
53
+ @entries.keys.map do |k|
54
+ data = chart_for k
55
+ {name: k, data: data }
56
+ end
57
+ end
58
+
59
+ def chart_opts chart_data
60
+
61
+ axis_type = logscale? ? 'logarithmic' : 'linear'
62
+
63
+ if chart_data.is_a? Array
64
+ min = chart_data.collect{|d| d[:data].values.min}.min
65
+ max = chart_data.collect{|d| d[:data].values.max}.max
66
+
67
+ elsif chart_data.is_a? Hash
68
+ min = chart_data[:data].values.min
69
+ max = chart_data[:data].values.max
70
+ end
71
+
72
+ orange = "#f0662d"
73
+ purple = "#8062a6"
74
+ light_green = "#7bc545"
75
+ med_blue = "#0883b2"
76
+ yellow = "#ffaa00"
77
+
78
+ {
79
+ discrete: true,
80
+ width: "800px",
81
+ height: "500px",
82
+ min: (min * 0.8).floor,
83
+ max: (max * 1.2).ceil,
84
+ library: {
85
+ colors: [orange, purple, light_green, med_blue, yellow],
86
+ xAxis: {type: axis_type, title: {text: "Size"}},
87
+ yAxis: {type: axis_type, title: {text: "Seconds per #{scaled_iterations.to_i} Iterations"}}
88
+ }
89
+ }
90
+ end
91
+
92
+ def comparison_chart_data chart_data, sizes
93
+ sample_size = sizes.first
94
+
95
+ # can't take log of 1,
96
+ # so it can't be used as the sample
97
+ if sample_size == 1
98
+ sample_size = sizes[1]
99
+ end
100
+
101
+ sample = chart_data[:data][sample_size]
102
+
103
+ logn_sample = sample/Math.log10(sample_size)
104
+ n_sample = sample/sample_size
105
+ nlogn_sample = sample/(sample_size * Math.log10(sample_size))
106
+ n2_sample = sample/(sample_size * sample_size)
107
+
108
+ logn_data = {}
109
+ n_data = {}
110
+ nlogn_data = {}
111
+ n2_data = {}
112
+
113
+ sizes.each do |n|
114
+ logn_data[n] = Math.log10(n) * logn_sample
115
+ n_data[n] = n * n_sample
116
+ nlogn_data[n] = n * Math.log10(n) * nlogn_sample
117
+ n2_data[n] = n * n * n2_sample
118
+ end
119
+
120
+ comparison_data = []
121
+ comparison_data << chart_data
122
+ comparison_data << {name: 'log n', data: logn_data}
123
+ comparison_data << {name: 'n', data: n_data}
124
+ comparison_data << {name: 'n log n', data: nlogn_data}
125
+ comparison_data << {name: 'n_sq', data: n2_data}
126
+ comparison_data
127
+ end
128
+ end
129
+ end
130
+ end
@@ -0,0 +1,8 @@
1
+ require "minitest/autorun"
2
+ require "benchmark/bigo"
3
+
4
+ class TestBenchmark::TestBigo < MiniTest::Test
5
+ def test_sanity
6
+ # flunk "write tests or I will kneecap you"
7
+ end
8
+ end
metadata ADDED
@@ -0,0 +1,136 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: benchmark-bigo
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.1
5
+ platform: ruby
6
+ authors:
7
+ - Davy Stevenson
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2014-08-08 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: benchmark-ips
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - ~>
18
+ - !ruby/object:Gem::Version
19
+ version: '2.0'
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - ~>
25
+ - !ruby/object:Gem::Version
26
+ version: '2.0'
27
+ - !ruby/object:Gem::Dependency
28
+ name: chartkick
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - ~>
32
+ - !ruby/object:Gem::Version
33
+ version: '1.2'
34
+ - - '>='
35
+ - !ruby/object:Gem::Version
36
+ version: 1.2.4
37
+ type: :runtime
38
+ prerelease: false
39
+ version_requirements: !ruby/object:Gem::Requirement
40
+ requirements:
41
+ - - ~>
42
+ - !ruby/object:Gem::Version
43
+ version: '1.2'
44
+ - - '>='
45
+ - !ruby/object:Gem::Version
46
+ version: 1.2.4
47
+ - !ruby/object:Gem::Dependency
48
+ name: minitest
49
+ requirement: !ruby/object:Gem::Requirement
50
+ requirements:
51
+ - - ~>
52
+ - !ruby/object:Gem::Version
53
+ version: '5.3'
54
+ type: :development
55
+ prerelease: false
56
+ version_requirements: !ruby/object:Gem::Requirement
57
+ requirements:
58
+ - - ~>
59
+ - !ruby/object:Gem::Version
60
+ version: '5.3'
61
+ - !ruby/object:Gem::Dependency
62
+ name: rdoc
63
+ requirement: !ruby/object:Gem::Requirement
64
+ requirements:
65
+ - - ~>
66
+ - !ruby/object:Gem::Version
67
+ version: '4.0'
68
+ type: :development
69
+ prerelease: false
70
+ version_requirements: !ruby/object:Gem::Requirement
71
+ requirements:
72
+ - - ~>
73
+ - !ruby/object:Gem::Version
74
+ version: '4.0'
75
+ - !ruby/object:Gem::Dependency
76
+ name: hoe
77
+ requirement: !ruby/object:Gem::Requirement
78
+ requirements:
79
+ - - ~>
80
+ - !ruby/object:Gem::Version
81
+ version: '3.12'
82
+ type: :development
83
+ prerelease: false
84
+ version_requirements: !ruby/object:Gem::Requirement
85
+ requirements:
86
+ - - ~>
87
+ - !ruby/object:Gem::Version
88
+ version: '3.12'
89
+ description: Benchmark objects to help calculate Big O behavior
90
+ email:
91
+ - davy.stevenson@gmail.com
92
+ executables: []
93
+ extensions: []
94
+ extra_rdoc_files:
95
+ - History.txt
96
+ - Manifest.txt
97
+ - README.md
98
+ files:
99
+ - History.txt
100
+ - Manifest.txt
101
+ - README.md
102
+ - Rakefile
103
+ - lib/benchmark/bigo.rb
104
+ - lib/benchmark/bigo/report.rb
105
+ - lib/benchmark/bigo/job.rb
106
+ - lib/benchmark/bigo/chart.erb
107
+ - test/benchmark/test_bigo.rb
108
+ - .gemtest
109
+ homepage: http://github.com/davy/benchmark-bigo
110
+ licenses:
111
+ - MIT
112
+ metadata: {}
113
+ post_install_message:
114
+ rdoc_options:
115
+ - --main
116
+ - README.md
117
+ require_paths:
118
+ - lib
119
+ required_ruby_version: !ruby/object:Gem::Requirement
120
+ requirements:
121
+ - - '>='
122
+ - !ruby/object:Gem::Version
123
+ version: '0'
124
+ required_rubygems_version: !ruby/object:Gem::Requirement
125
+ requirements:
126
+ - - '>='
127
+ - !ruby/object:Gem::Version
128
+ version: '0'
129
+ requirements: []
130
+ rubyforge_project:
131
+ rubygems_version: 2.0.3
132
+ signing_key:
133
+ specification_version: 4
134
+ summary: Benchmark objects to help calculate Big O behavior
135
+ test_files:
136
+ - test/benchmark/test_bigo.rb