-
-
Save JangoSteve/379771 to your computer and use it in GitHub Desktop.
| # Created by Steve Schwartz [1] (for Alfa Jango [2]) with the help of David Leal [3] | |
| # [1] http://github.com/jangosteve | |
| # [2] http://www.alfajango.com | |
| # [3] http://github.com/david | |
| # The latest version of this script may be found at http://gist.github.com/371710 | |
| require 'benchmark' | |
| class OptionsHashBenchmarker | |
| # assume an options hash of options => {:this => {:that => 'other'}} | |
| # and we want to do some operation if options[:this][:that] is defined and true | |
| VALID_OPTIONS = {:this => {:that => 'other'}} | |
| OTHER_OPTIONS = {:nothing => 'stuff'} | |
| def self.rescue_method(options={}) | |
| begin | |
| if options[:this][:that] | |
| #p "rescue_method doing stuff" | |
| end | |
| rescue | |
| ensure | |
| #p "rescue_method doing more stuff" | |
| end | |
| end | |
| def self.chained_tries(options={}) | |
| if options.try(:[], :this).try(:[], :that) | |
| #p "chained_tries doing stuff" | |
| end | |
| #p "chained_tries doing more stuff" | |
| end | |
| def self.chained_if(options={}) | |
| if options && options[:this] && options[:this][:that] | |
| #p "chained_if doing stuff" | |
| end | |
| #p "chained_if doing more stuff" | |
| end | |
| def self.hash_extension(options={}) | |
| if options.deep_fetch(:this, :that) | |
| #p "hash_extension doing stuff" | |
| end | |
| #p "hash_extension doing other stuff" | |
| end | |
| def self.nil_extension(options={}) | |
| if options[:this][:that] | |
| #p "nil_extension doing stuff" | |
| end | |
| #p "nil_extension doing more stuff" | |
| end | |
| def self.test_normal | |
| Hash.class_eval do | |
| def deep_fetch(*keys) | |
| keys.inject(self) { |h, k| if h then h[k] else return h end } | |
| end | |
| end | |
| n=1000000 | |
| Benchmark.bm do |x| | |
| x.report("rescue_method (valid):") { n.times do ; rescue_method(VALID_OPTIONS); end } | |
| x.report("chained_tries (valid):") { n.times do ; chained_tries(VALID_OPTIONS); end } | |
| x.report("chained_if (valid):") { n.times do ; chained_if(VALID_OPTIONS); end } | |
| x.report("hash_extension (valid):") { n.times do ; hash_extension(VALID_OPTIONS); end } | |
| x.report("rescue_method (other):") { n.times do ; rescue_method(OTHER_OPTIONS); end } | |
| x.report("chained_tries (other):") { n.times do ; chained_tries(OTHER_OPTIONS); end } | |
| x.report("chained_if (other):") { n.times do ; chained_if(OTHER_OPTIONS); end } | |
| x.report("hash_extension (other):") { n.times do ; hash_extension(OTHER_OPTIONS); end } | |
| x.report("rescue_method (none):") { n.times do ; rescue_method; end } | |
| x.report("chained_tries (none):") { n.times do ; chained_tries; end } | |
| x.report("chained_if (none):") { n.times do ; chained_if; end } | |
| x.report("hash_extension (none):") { n.times do ; hash_extension; end } | |
| end | |
| end | |
| # nil_extension must be put into its own method, so that NilClass doesn't get extended for the rescue_method (which would then never call the rescue block since it would no longer generate an exception) | |
| def self.test_nil_extension | |
| NilClass.class_eval do | |
| def [](key) | |
| nil | |
| end | |
| end | |
| n=1000000 | |
| Benchmark.bm do |x| | |
| x.report("nil_extension (valid):") { n.times do ; nil_extension(VALID_OPTIONS); end } | |
| x.report("nil_extension (other):") { n.times do ; nil_extension(OTHER_OPTIONS); end } | |
| x.report("nil_extension (none):") { n.times do ; nil_extension; end } | |
| end | |
| end | |
| end |
Generates the following results running Ruby 1.8:
user system total real
rescue_method (valid): 0.690000 0.010000 0.700000 ( 0.706048)
chained_tries (valid): 0.810000 0.010000 0.820000 ( 0.821056)
chained_if (valid): 0.790000 0.000000 0.790000 ( 0.803357)
nil_extension (valid): 0.610000 0.000000 0.610000 ( 0.624397)
rescue_method (other): 37.190000 1.410000 38.600000 ( 39.176910)
chained_tries (other): 1.220000 0.010000 1.230000 ( 1.232347)
chained_if (other): 0.640000 0.000000 0.640000 ( 0.649805)
nil_extension (other): 0.850000 0.010000 0.860000 ( 0.860668)
rescue_method (none): 37.700000 1.400000 39.100000 ( 39.871890)
chained_tries (none): 2.010000 0.010000 2.020000 ( 2.048758)
chained_if (none): 1.490000 0.010000 1.500000 ( 1.504774)
nil_extension (none): 1.580000 0.000000 1.580000 ( 1.611356)
Run again on Ruby 1.8, this time with new Hash#deep_find extension:
user system total real
rescue_method (valid): 0.700000 0.010000 0.710000 ( 0.708726)
chained_tries (valid): 0.800000 0.000000 0.800000 ( 0.823636)
chained_if (valid): 0.800000 0.010000 0.810000 ( 0.844903)
nil_extension (valid): 0.600000 0.000000 0.600000 ( 0.611619)
hash_extension (valid): 3.060000 0.020000 3.080000 ( 3.153540)
rescue_method (other): 37.810000 1.420000 39.230000 ( 40.710294)
chained_tries (other): 1.230000 0.010000 1.240000 ( 1.268215)
chained_if (other): 0.650000 0.000000 0.650000 ( 0.680624)
nil_extension (other): 0.840000 0.000000 0.840000 ( 0.863451)
hash_extension (other): 3.500000 0.020000 3.520000 ( 3.548087)
rescue_method (none): 38.070000 1.410000 39.480000 ( 40.272977)
chained_tries (none): 2.080000 0.010000 2.090000 ( 2.120892)
chained_if (none): 1.410000 0.010000 1.420000 ( 1.417036)
nil_extension (none): 1.610000 0.010000 1.620000 ( 1.637559)
hash_extension (none): 4.310000 0.010000 4.320000 ( 4.503614)
Must run OptionsHashBenchmarker.test_normal before running test_nil_extension, so that it can run the begin/rescue method without having NilClass extended and actually generate an exception.