bnchmrkr 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: b9f1258f5d0cea36bb610c16d36641e2969a8e28
4
+ data.tar.gz: 3bbc474bdb09cead4a2cd915bf6d4b6ebc1c87a2
5
+ SHA512:
6
+ metadata.gz: d5ce962a867982f82026b0a2f4b0ad24f472dee6582e0dd330b5f360e1b2c5b3f1492f48f7bc87b80ce187efa73e1a49c983ab968dfab2848e43cad3461db1f8
7
+ data.tar.gz: 1db49c32999165c48192499d8d33d43f5e3d298af9adbc33b05cf95b4138ed69b0ae6b859169d40fde6d4412d0f10aae137cd8e5cf01a3164f6e4c6a5b43564f
data/Gemfile ADDED
@@ -0,0 +1,10 @@
1
+ ruby '2.0.0'
2
+
3
+ source 'https://rubygems.org'
4
+
5
+ group :development do
6
+ gem 'jeweler', '~> 0'
7
+ gem 'test-unit', '~> 3.0.0', '>= 3.0.0'
8
+ end
9
+
10
+
data/Gemfile.lock ADDED
@@ -0,0 +1,20 @@
1
+ GEM
2
+ remote: https://rubygems.org/
3
+ specs:
4
+ jeweler (0.11.1)
5
+ rubyforge
6
+ schacon-git (>= 1.1.1)
7
+ json_pure (1.8.3)
8
+ power_assert (0.2.7)
9
+ rubyforge (2.0.4)
10
+ json_pure (>= 1.1.7)
11
+ schacon-git (1.2.2)
12
+ test-unit (3.0.9)
13
+ power_assert
14
+
15
+ PLATFORMS
16
+ ruby
17
+
18
+ DEPENDENCIES
19
+ jeweler (~> 0)
20
+ test-unit (~> 3.0.0, >= 3.0.0)
data/README.md ADDED
@@ -0,0 +1,61 @@
1
+ # bnchmrkr
2
+
3
+ i hate the name too, [but..](https://github.com/chorankates/bnchmrkr/issues/1)
4
+
5
+ Bnchmrkr (Benchmarker) is a tool to help benchmark different method implementations.
6
+
7
+
8
+ # examples
9
+
10
+ ```rb
11
+ tester = Bnchmrlr.new({
12
+ :count_to_1k => lambda { 1.upto(1000).each { |i| i } },
13
+ :count_to_5k => lambda { 1.upto(5000).each { |i| i } },
14
+ :count_to_10k => lambda { 1.upto(10000).each { |i| i } },
15
+ :count_to_50k => lambda { 1.upto(50000).each { |i| i } },
16
+ :count_to_100k => lambda { 1.upto(100000).each { |i| i } },
17
+ }, 1000)
18
+
19
+ tester.benchmark!
20
+
21
+ puts tester
22
+ ```
23
+
24
+ ```
25
+ $ ruby examples/ls_vs_stat.rb
26
+ fastest by type(ls) => 0.005704
27
+ fastest overall => {:name=>:ls, :measure=>0.005704}
28
+ slowest by type(stat) => 0.076243
29
+ slowest_overall => {:name=>:stat, :measure=>0.076243}
30
+ is_faster?(:ls, :stat) => true
31
+ is_slower?(:ls, :stat) => false
32
+ ls:
33
+ fastest => 0.005704
34
+ mean => 0.008375
35
+ median => 0.006715
36
+ slowest => 0.024187
37
+ total => 0.083754
38
+ stat:
39
+ fastest => 0.061403
40
+ mean => 0.069956
41
+ median => 0.073952
42
+ slowest => 0.076243
43
+ total => 0.699563
44
+ overall:
45
+ fastest => ls [0.005704]
46
+ slowest => stat [0.076243]
47
+ ```
48
+
49
+ # instance methods
50
+ ```
51
+ benchmark!
52
+ count
53
+ faster_by
54
+ fastest_by_type
55
+ fastest_overall
56
+ is_faster?
57
+ is_slower?
58
+ results
59
+ slowest_by_type
60
+ slowest_overall
61
+ ```
data/Rakefile ADDED
@@ -0,0 +1,40 @@
1
+ require 'jeweler'
2
+ require 'rake/testtask'
3
+
4
+ $LOAD_PATH << File.join([File.dirname(__FILE__), 'lib'])
5
+ $LOAD_PATH << File.dirname(__FILE__)
6
+ require 'bnchmrkr'
7
+
8
+ Jeweler::Tasks.new do |gem|
9
+ gem.name = 'bnchmrkr'
10
+ gem.summary = 'compare execution time'
11
+ gem.description = 'given a hash of lambdas, runs and compares the amount of time each implementation takes'
12
+ gem.email = 'conor.code@gmail.com'
13
+ gem.homepage = 'http://github.com/chorankates/bnchmrkr'
14
+ gem.authors = ['Conor Horan-Kates']
15
+ gem.licenses = 'MIT'
16
+
17
+ end
18
+ Jeweler::RubygemsDotOrgTasks.new
19
+
20
+ namespace :test do
21
+ Rake::TestTask.new do |t|
22
+ t.name = 'unit'
23
+ t.libs << 'lib'
24
+ t.test_files = FileList['test/unit/**/test_*.rb']
25
+ t.verbose = true
26
+ end
27
+
28
+ end
29
+
30
+ desc 'run all tests'
31
+ task :test => ['test:unit'] do
32
+ end
33
+
34
+ desc 'run all examples'
35
+ task :examples do
36
+ Dir.glob('examples/*.rb').each do |file|
37
+ sh "time ruby #{file}"
38
+ puts
39
+ end
40
+ end
data/VERSION ADDED
@@ -0,0 +1 @@
1
+ 0.0.1
@@ -0,0 +1,15 @@
1
+ #!/usr/bin/ruby
2
+ # contrived.rb - methods that intentionally take differing amounts of time
3
+ require_relative File.expand_path(sprintf('%s/../lib/bnchmrkr', File.dirname(__FILE__)))
4
+
5
+ tester = Bnchmrkr.new({
6
+ :count_to_1k => lambda { 1.upto(1000).each { |i| i } },
7
+ :count_to_5k => lambda { 1.upto(5000).each { |i| i } },
8
+ :count_to_10k => lambda { 1.upto(10000).each { |i| i } },
9
+ :count_to_50k => lambda { 1.upto(50000).each { |i| i } },
10
+ :count_to_100k => lambda { 1.upto(100000).each { |i| i } },
11
+ }, 1000)
12
+
13
+ tester.benchmark!
14
+
15
+ puts tester
@@ -0,0 +1,63 @@
1
+ #!/usr/bin/ruby
2
+ # fibonacci.rb - comparing recursive vs. iterative functions
3
+
4
+ require_relative File.expand_path(sprintf('%s/../lib/bnchmrkr', File.dirname(__FILE__)))
5
+
6
+ require 'test-unit'
7
+
8
+ def recursive(n)
9
+ if n <= 1
10
+ return n
11
+ end
12
+
13
+ ( recursive(n - 1) + recursive(n - 2) )
14
+ end
15
+
16
+ def iterative(target)
17
+
18
+ if target <= 1
19
+ return target
20
+ end
21
+
22
+ hash = {
23
+ 0 => 0,
24
+ 1 => 1,
25
+ }
26
+
27
+ 2.upto(target).each do |e|
28
+ hash[e] = (hash[e - 1] + hash[e - 2])
29
+ end
30
+
31
+ hash[target]
32
+ end
33
+
34
+ class TestFibonacci < Test::Unit::TestCase
35
+
36
+ def test_fibonacci_equality
37
+
38
+ 1.upto(25).each do |i|
39
+ recursive_result = recursive(i)
40
+ iterative_result = iterative(i)
41
+ assert_equal(recursive_result, iterative_result)
42
+ end
43
+
44
+ end
45
+
46
+ def test_fibonacci_speed
47
+
48
+ tester = Bnchmrkr.new({
49
+ :iterative => lambda { iterative(30) },
50
+ :recursive => lambda { recursive(30) },
51
+ }, 25)
52
+
53
+ tester.benchmark!
54
+ puts tester
55
+
56
+ assert_true(tester.is_faster?(:iterative, :recursive))
57
+ assert_true(tester.is_slower?(:recursive, :iterative))
58
+ assert_equal(:iterative, tester.fastest_overall[:name])
59
+ assert_equal(:recursive, tester.slowest_overall[:name])
60
+
61
+ end
62
+
63
+ end
@@ -0,0 +1,90 @@
1
+ #
2
+ # line by line vs. .read and then split
3
+
4
+ require_relative File.expand_path(sprintf('%s/../lib/bnchmrkr', File.dirname(__FILE__)))
5
+
6
+ class ReadAndSplit
7
+ attr_reader :file
8
+
9
+ def initialize(file)
10
+ @file = file
11
+ end
12
+
13
+ def read!
14
+ contents = File.read(@file).split("\n")
15
+ end
16
+ end
17
+
18
+ class ReadAndIterate
19
+ attr_reader :file
20
+
21
+ def initialize(file)
22
+ @file = file
23
+ end
24
+
25
+ def read!
26
+ contents = Array.new
27
+ f = File.new(file)
28
+ f.each_line do |line|
29
+ contents << line
30
+ end
31
+ end
32
+
33
+ end
34
+
35
+ def generate_ras_variances(files)
36
+ hash = Hash.new
37
+ name = :split
38
+ files.each do |file|
39
+ local_name = sprintf('%s_%s', name.to_s, File.basename(file)).to_sym
40
+ hash[local_name] = lambda {
41
+ brl = ReadAndSplit.new(file)
42
+ brl.read!
43
+ }
44
+ end
45
+ hash
46
+ end
47
+
48
+ def generate_rai_variances(files)
49
+ hash = Hash.new
50
+ name = :iterate
51
+ files.each do |file|
52
+ local_name = sprintf('%s_%s', name.to_s, File.basename(file)).to_sym
53
+ hash[local_name] = lambda {
54
+ rai = ReadAndIterate.new(file)
55
+ rai.read!
56
+ }
57
+ end
58
+ hash
59
+ end
60
+
61
+
62
+ files = [
63
+ File.expand_path(sprintf('%s/../resources/li-100kw.txt', File.dirname(__FILE__))),
64
+ File.expand_path(sprintf('%s/../resources/li-500kw.txt', File.dirname(__FILE__))),
65
+ File.expand_path(sprintf('%s/../resources/li-1Mw.txt', File.dirname(__FILE__))),
66
+ ]
67
+
68
+ tester = Bnchmrkr.new({
69
+ :split => lambda {
70
+ brl = ReadAndSplit.new(files.first)
71
+ brl.read!
72
+ },
73
+ :iterate => lambda {
74
+ rai = ReadAndIterate.new(files.first)
75
+ rai.read!
76
+ }
77
+ }, 500)
78
+
79
+ tester.benchmark!
80
+ puts tester
81
+
82
+ tester2 = Bnchmrkr.new(
83
+ generate_rai_variances(files).merge(
84
+ generate_ras_variances(files)),
85
+ 100)
86
+
87
+ tester2.benchmark!
88
+ puts tester2
89
+
90
+
@@ -0,0 +1,29 @@
1
+ #!/usr/bin/ruby
2
+ # ls_vs_stat.rb - comparing `ls <dir>/*` to `stat <dir>/*`
3
+
4
+ require_relative File.expand_path(sprintf('%s/../lib/bnchmrkr', File.dirname(__FILE__)))
5
+
6
+ dir = File.dirname(__FILE__)
7
+ dir = sprintf('%s/*', ENV['HOME'])
8
+
9
+ tester = Bnchmrkr.new({
10
+ :ls => lambda { `ls #{dir}` },
11
+ :stat => lambda { `stat #{dir}` },
12
+ },
13
+ 10,
14
+ )
15
+
16
+ tester.benchmark!
17
+
18
+ {
19
+ 'fastest by type(ls)' => tester.fastest_by_type(:ls),
20
+ 'fastest overall' => tester.fastest_overall,
21
+ 'slowest by type(stat)' => tester.slowest_by_type(:stat),
22
+ 'slowest_overall' => tester.slowest_overall,
23
+ 'is_faster?(:ls, :stat)' => tester.is_faster?(:ls, :stat),
24
+ 'is_slower?(:ls, :stat)' => tester.is_slower?(:ls, :stat),
25
+ }.each_pair do |name, result|
26
+ puts sprintf(' %#15s => %s%s', name, result, "\n")
27
+ end
28
+
29
+ puts tester
data/lib/bnchmrkr.rb ADDED
@@ -0,0 +1,187 @@
1
+ #!/usr/bin/ruby
2
+
3
+ require 'benchmark'
4
+
5
+ class Bnchmrkr
6
+
7
+ attr_reader :count, :results
8
+
9
+ def initialize(lambdas, count = 100)
10
+
11
+ @count = count
12
+ @results = Hash.new
13
+ @lambdas = lambdas
14
+
15
+ @fastest = { :name => :unknown, :measure => 2 ** 10 } # TODO really need to find a better max int
16
+ @slowest = { :name => :unknown, :measure => 0 }
17
+
18
+ @cache = Hash.new
19
+
20
+ @lambdas.each_pair do |name, l|
21
+ unless name.class.eql?(Symbol) and l.class.eql?(Proc)
22
+ raise ArgumentError.new(sprintf('expecting[Symbol,Proc], got[%s,%s]', name.class, l.class))
23
+ end
24
+ end
25
+
26
+ raise ArgumentError.new(sprintf('expecting[Fixnum], got[%s]', count.class)) unless count.class.eql?(Fixnum)
27
+
28
+ end
29
+
30
+ # return list of named lambdas known
31
+ def types
32
+ @lambdas.keys
33
+ end
34
+
35
+ # 10 lines to actually do the work..
36
+ def benchmark!
37
+ @lambdas.each_pair do |name, l|
38
+ 1.upto(@count).each do |round|
39
+ measure = Benchmark.measure {
40
+ l.call
41
+ }
42
+ add_measure(name, measure)
43
+ end
44
+ end
45
+
46
+ end
47
+
48
+ ## :specific => fastest, slowest, mean, median, total per lambda
49
+ ## :overall => fastest, slowest for all
50
+ def inspect
51
+ { :overall => calculate_overall, :specific => calculate_per_lambda }
52
+ end
53
+
54
+ # overly intricate output formatting of overall and specific results
55
+ def to_s
56
+ string = String.new
57
+ inspection = self.inspect
58
+ return string unless inspection.nil? or inspection.has_key?(:overall)
59
+ longest_key = 15 # TODO determine this dynamically
60
+
61
+ inspection[:specific].keys.each do |i|
62
+ string << sprintf('%s:%s', i, "\n")
63
+ inspection[:specific][i].keys.sort.each do |k|
64
+ string << sprintf(" %#{longest_key}s => %s%s", k, inspection[:specific][i][k], "\n")
65
+ end
66
+ end
67
+
68
+ string << sprintf('overall:%s', "\n")
69
+ inspection[:overall].each_pair do |type, measure|
70
+ string << sprintf(" %#{longest_key}s => %s [%s]%s", type, measure[:name], measure[:measure], "\n")
71
+ end
72
+
73
+ string
74
+ end
75
+
76
+ # +type+ name of a lambda that is known
77
+ # find and return the fastest execution per lambda of +type+
78
+ def fastest_by_type(type)
79
+ results = @results
80
+ measures = Array.new
81
+
82
+ return nil unless results.has_key?(type)
83
+ results[type].collect { |r| measures << r.real}
84
+
85
+ measures.sort.first
86
+ end
87
+
88
+ # find and return the fastest overall execution (regardless of lambda type)
89
+ def fastest_overall
90
+ calculate_overall
91
+ @fastest
92
+ end
93
+
94
+ # +type+ name of a lambda that is known
95
+ # find and return the slowest execution per lambda of +type+
96
+ def slowest_by_type(type)
97
+ results = @results
98
+ measures = Array.new
99
+
100
+ return nil unless results.has_key?(type)
101
+ results[type].collect { |r| measures << r.real }
102
+
103
+ measures.sort.last
104
+ end
105
+
106
+ # find and return the slowest overall execution (regardless of lambda type)
107
+ def slowest_overall
108
+ calculate_overall
109
+ @slowest
110
+ end
111
+
112
+ # +a+ {:name => name, :measure => measure}
113
+ # +b+ {:name => name, :measure => measure}
114
+ # +mode+ :fastest, :slowest, :mean, :median, :total
115
+ # return boolean if a is faster than b, false if invalid
116
+ def is_faster?(a, b, mode = :total)
117
+ result = calculate_per_lambda
118
+ return false unless result.has_key?(a[:name]) and result.has_key?(b[:name])
119
+ result[a[:name]][mode] < result[b[:name]][mode]
120
+ end
121
+
122
+ # +a+ {:name => name, :measure => measure}
123
+ # +b+ {:name => name, :measure => measure}
124
+ # +mode+ :fastest, :slowest, :mean, :median, :total
125
+ # return boolean if a is faster than b, false if invalid
126
+ def is_slower?(a, b, mode = :total)
127
+ ! is_faster?(a, b, mode)
128
+ end
129
+
130
+ # +a+ {:name => name, :measure => measure}
131
+ # +b+ {:name => name, :measure => measure}
132
+ # return Float representing difference in measure, or false, if b is slower than a
133
+ def faster_by(a, b, percent = true)
134
+ return false if b[:measure] < a[:measure]
135
+
136
+ faster = (b[:measure] - a[:measure]) / b[:measure]
137
+ percent ? sprintf('%4f%', faster * 100) : faster
138
+ end
139
+
140
+ private
141
+
142
+ def add_measure(name, measure)
143
+ self.results[name] = Array.new unless self.results.has_key?(name)
144
+ self.results[name] << measure
145
+ end
146
+
147
+ # from existing results, generate some statistics per lambda type
148
+ def calculate_per_lambda
149
+ hash = Hash.new
150
+
151
+ # TODO come up with way to not recompute unless contents have changed
152
+
153
+ @results.each_pair do |name, measures|
154
+ sorted = measures.sort { |a,b| a.real <=> b.real }
155
+
156
+ hash[name] = Hash.new
157
+
158
+ total = 0
159
+ measures.collect {|m| total += m.real }
160
+
161
+ # TODO do we want to determine the mode?
162
+ hash[name][:fastest] = sorted.first.real
163
+ hash[name][:slowest] = sorted.last.real
164
+ hash[name][:mean] = sprintf('%5f', total / sorted.size)
165
+ hash[name][:median] = sorted[(sorted.size / 2)].real
166
+ hash[name][:total] = sprintf('%5f', total)
167
+ end
168
+
169
+ hash
170
+ end
171
+
172
+ # update fastest/slowest, return in a named Hash
173
+ def calculate_overall
174
+ calculate_per_lambda.each_pair do |name,results|
175
+ if results[:fastest] < @fastest[:measure]
176
+ @fastest = { :name => name, :measure => results[:fastest] }
177
+ end
178
+
179
+ if results[:slowest] > @slowest[:measure]
180
+ @slowest = { :name => name, :measure => results[:slowest] }
181
+ end
182
+ end
183
+
184
+ { :fastest => @fastest, :slowest => @slowest }
185
+ end
186
+
187
+ end