bnchmrkr 0.0.1

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