GitHub Sale: sign up for any paid plan this week and pay nothing until January 1, 2009!  [ hide ]

public
Description: Prettier Benchmarking for Ruby
Clone URL: git://github.com/wycats/benchwarmer.git
Initial commit with actual code ;)
wycats (author)
Sat May 03 15:29:34 -0700 2008
commit  3d36da3b0fa22f3a4183da7e4403f1850fb76f7a
tree    699623081e6bc7b4c221659a2fe500d5ef6b1cee
parent  2d92f8aa08bc21a00528387ba3e39dbb6085c53b
...
1
 
2
3
4
...
 
1
2
3
4
0
@@ -1,4 +1,4 @@
0
-Copyright (c) 2007 YOUR NAME
0
+Copyright (c) 2007 Yehuda Katz
0
 
0
 Permission is hereby granted, free of charge, to any person obtaining
0
 a copy of this software and associated documentation files (the
0
...
1
2
 
 
 
 
 
 
3
4
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
5
...
 
 
1
2
3
4
5
6
7
 
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
0
@@ -1,4 +1,96 @@
0
-templates
0
-=================
0
+# benchwarmer
0
+# ===========
0
+#
0
+# A gem that provides a nice DSL for a common type of benchmark.
0
+#
0
+# Specifically:
0
 
0
-A plugin for the Merb framework that provides ....
0
+ require "rubygems"
0
+ require "benchwarmer"
0
+
0
+ TIMES = 100_000
0
+
0
+ Benchmark.warmer(TIMES) do # [1]
0
+ columns :one, :two, :three # [2]
0
+ titles :one => "Option 1", :three => "Option 3" # [3]
0
+
0
+ group("Squeezing") do # [4]
0
+ report "with #squeeze" do # [5]
0
+ one { "abc//def//ghi//jkl".squeeze("/") } # [6]
0
+ two { "abc///def///ghi///jkl".squeeze("/") }
0
+ three { "abc////def////ghi////jkl".squeeze("/") }
0
+ end
0
+ report "with #gsub" do
0
+ one { "abc//def//ghi//jkl".gsub(/\/+/, "/") }
0
+ two { "abc///def///ghi///jkl".gsub(/\/+/, "/") }
0
+ three { "abc////def////ghi////jkl".gsub(/\/+/, "/") }
0
+ end
0
+ end
0
+
0
+ group("Spliting") do
0
+ report "with #split" do
0
+ one { "aaa/aaa/aaa.bbb.ccc.ddd".split(".") }
0
+ two { "aaa//aaa//aaa.bbb.ccc.ddd.eee".split(".") }
0
+ three { "aaa///aaa///aaa.bbb.ccc.ddd.eee.fff".split(".") }
0
+ end
0
+ report "with #match" do
0
+ one { "aaa/aaa/aaa.bbb.ccc.ddd".match(/\.([^\.]*)$/) }
0
+ two { "aaa//aaa//aaa.bbb.ccc.ddd.eee".match(/\.([^\.]*)$/) }
0
+ three { "aaa///aaa///aaa.bbb.ccc.ddd.eee.fff".match(/\.([^\.]*)$/) }
0
+ end
0
+ end
0
+ end
0
+
0
+ # [1] Specify the number of times you want to run each benchmark
0
+ # [2] Specify the column names. By default, they will be displayed as upcased
0
+ # versions of themselves.
0
+ # [3] Specify prettier titles via a Hash. You do *not* need to specify the
0
+ # same column in both columns and titles.
0
+ # [4] Specify a group of benchmarks you wish to run
0
+ # [5] Specify the name of the report you wish to run
0
+ # [6] Optionally, specify several different variants of the benchmark. This could
0
+ # be useful if you're testing a new alorithm, and wish to compare a bunch of
0
+ # benchmarks against each algorithms. In most cases, you will probably want to
0
+ # use the variant below, which does not require columns.
0
+
0
+ # Output:
0
+ # Running the benchmarks 100000 times each...
0
+ #
0
+ # Option 1 | TWO | Option 3 |
0
+ # -----------------------------------------------------
0
+ # Squeezing with #squeeze 0.15 | 0.15 | 0.14 |
0
+ # with #gsub 0.38 | 0.35 | 0.36 |
0
+ # -----------------------------------------------------
0
+ # Spliting with #split 0.43 | 0.51 | 0.61 |
0
+ # with #match 0.29 | 0.35 | 0.38 |
0
+ # -----------------------------------------------------
0
+
0
+ Benchmark.warmer(TIMES) do
0
+ group("Squeezing") do
0
+ report "with #squeeze" do
0
+ "abc//def//ghi//jkl".squeeze("/")
0
+ end
0
+ report "with #gsub" do
0
+ "abc//def//ghi//jkl".gsub(/\/+/, "/")
0
+ end
0
+ end
0
+
0
+ group("Spliting") do
0
+ report "with #split" do
0
+ "aaa/aaa/aaa.bbb.ccc.ddd".split(".")
0
+ end
0
+ report "with #match" do
0
+ "aaa/aaa/aaa.bbb.ccc.ddd".match(/\.([^\.]*)$/)
0
+ end
0
+ end
0
+ end
0
+
0
+ # Results |
0
+ # ---------------------------------
0
+ # Squeezing with #squeeze 0.15 |
0
+ # with #gsub 0.37 |
0
+ # ---------------------------------
0
+ # Spliting with #split 0.43 |
0
+ # with #match 0.29 |
0
+ # ---------------------------------
0
+
0
\ No newline at end of file
...
1
2
3
4
5
6
7
8
9
 
 
 
 
 
 
10
11
12
...
1
2
3
 
 
 
 
 
 
4
5
6
7
8
9
10
11
12
0
@@ -1,12 +1,12 @@
0
 require 'rubygems'
0
 require 'rake/gempackagetask'
0
 
0
-GEM = "new_gem"
0
-VERSION = "0.0.1"
0
-AUTHOR = "Your Name"
0
-EMAIL = "Your Email"
0
-HOMEPAGE = "http://example.com"
0
-SUMMARY = "A gem that provides..."
0
+GEM = "benchwarmer"
0
+VERSION = "0.5"
0
+AUTHOR = "Yehuda Katz"
0
+EMAIL = "wycats@gmail.com"
0
+HOMEPAGE = "http://yehudakatz.com"
0
+SUMMARY = "A gem that provides a prettier formatting and DSL for Ruby benchmarks"
0
 
0
 spec = Gem::Specification.new do |s|
0
   s.name = GEM
...
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
0
...
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
0
@@ -0,0 +1,130 @@
0
+require "benchmark"
0
+require File.join(File.expand_path(File.dirname(__FILE__)), "vendor", "dictionary")
0
+
0
+module Enumerable
0
+ def max_by(&blk)
0
+ self.sort_by(&blk).last
0
+ end
0
+end
0
+
0
+module Benchmark
0
+
0
+ def self.warmer(times, &blk)
0
+ Warmer.new(times).run(&blk)
0
+ end
0
+
0
+ class Warmer
0
+
0
+ attr_reader :times, :columns, :groups
0
+ def initialize(times)
0
+ @times = times
0
+ end
0
+
0
+ def line!
0
+ size = @name_max + @group_max + 1
0
+ @columns.each do |name, val|
0
+ size += (@columns[name].size <= 5 ? 5 : @columns[name].size) + 3
0
+ end
0
+ puts "-" * size
0
+ end
0
+
0
+ def blanks(size)
0
+ print " " * size
0
+ end
0
+
0
+ def run(&blk)
0
+ puts "Running the benchmarks #{@times} times each..."
0
+ puts
0
+
0
+ self.instance_eval(&blk)
0
+
0
+ unless @columns
0
+ @columns = Dictionary.new
0
+ @columns[:results] = "Results"
0
+ end
0
+
0
+ @name_max = @groups.keys.max_by {|x| x.size}.size
0
+ @group_max = @groups.values.map {|x| x.keys }.flatten.max_by {|x| x.size}.size
0
+
0
+ print " " * (@name_max + @group_max + 2)
0
+
0
+ puts @columns.map {|col,val| "%5s" % val }.join(" | ") + " |"
0
+
0
+ line!
0
+
0
+ @groups.each do |group_name,runs|
0
+ # Print the group's name, left-justified and filling up as much space as the max
0
+ # group name
0
+ print "%-#{@name_max + 1}s" % group_name
0
+
0
+ # Go through the registered runs
0
+ runs.each_with_index do |(name, procs), i|
0
+ blanks(@name_max + 1) if i > 0
0
+ # The name has to take up all the space of the group name, and then some
0
+ print "%#{@group_max}s" % name
0
+
0
+ # Actually run the benchmarks
0
+ procs.each_with_index do |proc, i|
0
+ head = @columns[@columns.order[i]]
0
+ bench = Benchmark.measure { @times.times(&proc)}
0
+ print (" %#{head.size >= 5 ? head.size : 5}.2f |" % bench.real)
0
+ end
0
+ puts
0
+ end
0
+
0
+ line!
0
+ end
0
+ end
0
+
0
+ def columns(*list)
0
+ @columns = list.inject(Dictionary.new) do |accum, col|
0
+ accum[col] = col.to_s.upcase
0
+ accum
0
+ end
0
+ end
0
+
0
+ def titles(titles)
0
+ @columns.merge!(titles)
0
+ end
0
+
0
+ def group(str, &blk)
0
+ @groups ||= Dictionary.new {|h,k| h[k] = Dictionary.new}
0
+ @current_group = str
0
+ self.instance_eval(&blk)
0
+ @current_group = nil
0
+ end
0
+
0
+ def report(str, &blk)
0
+ @groups ||= Dictionary.new
0
+ if !@columns || @columns.size == 1
0
+ @groups[@current_group || "default"][str] = [blk]
0
+ else
0
+ report = GroupReport.new(@columns.keys)
0
+ report.instance_eval(&blk)
0
+ @groups[@current_group || "default"][str] = report.runs
0
+ end
0
+ end
0
+
0
+ end
0
+
0
+ class GroupReport
0
+ self.instance_methods.each do |meth|
0
+ send(:undef_method, meth) unless meth =~ /^(__|instance_eval)/
0
+ end
0
+
0
+ attr_accessor :runs, :cols
0
+
0
+ def initialize(cols)
0
+ new_self = (class << self; self end)
0
+ cols.each do |col|
0
+ new_self.class_eval <<-RUBY
0
+ def #{col}(&blk)
0
+ @runs ||= []
0
+ @runs << blk
0
+ end
0
+ RUBY
0
+ end
0
+ end
0
+ end
0
+
0
+end
0
\ No newline at end of file

Comments

    No one has commented yet.