Skip to content

Instantly share code, notes, and snippets.

@hannestyden
Created January 3, 2013 07:33
Show Gist options
  • Save hannestyden/4441557 to your computer and use it in GitHub Desktop.
Save hannestyden/4441557 to your computer and use it in GitHub Desktop.
# How expensive is DCI in Ruby?
# http://news.ycombinator.com/item?id=4997498
RUBY_VERSION # => "1.9.3"
RUBY_PATCHLEVEL # => 362
RUBY_PLATFORM # => "x86_64-darwin12.2.0"
require 'benchmark'
require 'delegate'
require 'forwardable'
class C
def org; :org; end
def ovr; :org; end
end
class LazyDel < SimpleDelegator
def ldl; :ldl; end
def ovr; :ldl; end
end
class ForwDel
extend Forwardable
def initialize(base)
@base = base
end
delegate :org => :@base
def fwd; :fwd; end
def ovr; :fwd; end
end
class ExplDel
def initialize(base)
@base = base
end
def org
@base.org
end
def xdl; :xdl; end
def ovr; :xdl; end
end
module M
def ext; :ext; end
def ovr; :ext; end
end
N = 1_000_000
objects = Hash.new { |hash, key| hash[key] = [] }
COLS = 8
puts "create #{N} objects"
Benchmark.bm(COLS) do |bm|
bm.report("plain") do
N.times do
objects[:plain] << C.new
end
end
bm.report("lazy del") do
N.times do
objects[:lazy_del] << LazyDel.new(C.new)
end
end
bm.report("forw del") do
N.times do
objects[:forw_del] << ForwDel.new(C.new)
end
end
bm.report("expl del") do
N.times do
objects[:expl_del] << ExplDel.new(C.new)
end
end
bm.report("extend") do
N.times do
objects[:extend] << C.new.extend(M)
end
end
end
puts
puts "method call: delegate"
Benchmark.bm(COLS) do |bm|
objects.each do |key, value|
bm.report(key) { value.each { |o| o.org } }
end
end
puts
puts "method call: added"
Benchmark.bm(COLS) do |bm|
bm.report("plain") { objects[:plain].each { |o| o.org } }
bm.report("lazy del") { objects[:lazy_del].each { |o| o.ldl } }
bm.report("forw del") { objects[:forw_del].each { |o| o.fwd } }
bm.report("expl del") { objects[:expl_del].each { |o| o.xdl } }
bm.report("extend") { objects[:extend].each { |o| o.ext } }
end
puts
puts "method call: overloaded"
Benchmark.bm(COLS) do |bm|
objects.each do |key, value|
bm.report(key) { value.each { |o| o.ovr } }
end
end
# Conclusions
# - Creating objects will never be free.
# - Extending an object is **very** expensive.
# - Delegating using `SimpleDelegator` (`method_missing`) is expensive.
# - Delegating using explicit implementation is a bit cheaper than extending.
# - Adding and overloading methods by extending adds an overhead.
# >> create 1000000 objects
# >> user system total real
# >> plain 0.370000 0.040000 0.410000 ( 0.466573)
# >> lazy del 0.790000 0.060000 0.850000 ( 1.072003)
# >> forw del 0.560000 0.050000 0.610000 ( 0.915602)
# >> expl del 0.690000 0.060000 0.750000 ( 1.246730)
# >> extend 8.950000 0.390000 9.340000 ( 9.431121)
# >>
# >> method call: delegate
# >> user system total real
# >> plain 0.120000 0.000000 0.120000 ( 0.124878)
# >> lazy_del 0.760000 0.030000 0.790000 ( 0.800174)
# >> forw_del 0.420000 0.030000 0.450000 ( 0.454589)
# >> expl_del 0.200000 0.000000 0.200000 ( 0.200165)
# >> extend 0.300000 0.000000 0.300000 ( 0.324213)
# >>
# >> method call: added
# >> user system total real
# >> plain 0.130000 0.010000 0.140000 ( 0.134556)
# >> lazy del 0.130000 0.000000 0.130000 ( 0.134953)
# >> forw del 0.130000 0.000000 0.130000 ( 0.141292)
# >> expl del 0.130000 0.000000 0.130000 ( 0.128352)
# >> extend 0.260000 0.000000 0.260000 ( 0.259568)
# >>
# >> method call: overloaded
# >> user system total real
# >> plain 0.120000 0.000000 0.120000 ( 0.124404)
# >> lazy_del 0.130000 0.000000 0.130000 ( 0.126756)
# >> forw_del 0.120000 0.000000 0.120000 ( 0.126492)
# >> expl_del 0.130000 0.000000 0.130000 ( 0.127103)
# >> extend 0.270000 0.000000 0.270000 ( 0.272072)
@stigi
Copy link

stigi commented Jan 11, 2013

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment