Skip to content

Commit

Permalink
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Improve inline caching benchmark.
Browse files Browse the repository at this point in the history
The inline caching benchmark as written before did not provide
accurate information on the slowdown of polymorphic inline caches.
As the morphism increased, the benchmark would perform more calls,
skewing results toward the benchmarks with less polymorphism but
not due to the cost of the polymorphic cache itself. It was also
reusing the same "call_on" method for all morphisms, which on a
newer version of benchmark/ips resulted in the lower-morphic runs
being poisoned by higher-morphic runs (since benchmark/ips now
pre-warms all benchmarks as a group, rather than immediately
before measurement).

My modification attempts to avoid this via the following strategy:

* Measure all morphisms from 1 to 10.
* Each morphism uses its own call_on method.
* Each morphism performs the same number of call_on invocations.
* The objects are rotated every five invocations, allowing the
  call_on call site to eventually see all types.
* Rotation is performed manually, to avoid multiple assignment
  overhead skewing results. It is assumed that most interesting
  implementations will have relatively inexpensive local variable
  retrieval and assignment costs (or at least inexpensive when
  compared to invocation, polymorphic caching, and method lookup).

The new benchmark should provide more accurate results, since the
non-cache work done in each benchmark is mostly the same and the
different morphisms can no longer poison each other's results. The
ideal results for a well-tuned implementation should be gradual
decline toward the higher morphisms, rather than a sudden drop-off
when inline caching is abandoned in favor of a lookup mechanism.
Various impls will have their own sweet spot where a polymorphic
cache becomes more expensive than doing the lookup each time.
headius committed May 17, 2013
1 parent e9d6f2a commit ed05eb8
Showing 1 changed file with 247 additions and 23 deletions.
270 changes: 247 additions & 23 deletions benchmark/tiers/0/bm_inline_cache.rb
Original file line number Diff line number Diff line change
@@ -12,7 +12,43 @@ class Class7; def called_method; end; end
class Class8; def called_method; end; end
class Class9; def called_method; end; end

def call_on(obj)
def call_on1(obj)
obj.called_method
end

def call_on2(obj)
obj.called_method
end

def call_on3(obj)
obj.called_method
end

def call_on4(obj)
obj.called_method
end

def call_on5(obj)
obj.called_method
end

def call_on6(obj)
obj.called_method
end

def call_on7(obj)
obj.called_method
end

def call_on8(obj)
obj.called_method
end

def call_on9(obj)
obj.called_method
end

def call_on10(obj)
obj.called_method
end

@@ -27,60 +63,248 @@ def call_on(obj)
object8 = Class8.new
object9 = Class9.new

# In order to keep the numbers as uniform as possible, we use the following strategy:
#
# * Each bench uses a different call_on to avoid poisoning each other
# * Each bench attempts five calls against the same object, to reduce loop skew
# * Polymorphic benchmarks rotate objects every five calls
# * Rotation is done manually to avoid multiple-assignment overhead

Benchmark.ips do |x|
x.report "monomorphic call site" do |times|
i = 0
obj0 = object0
while i < times
call_on(object0)
call_on1(obj0)
call_on1(obj0)
call_on1(obj0)
call_on1(obj0)
call_on1(obj0)
i += 1
end
end

x.report "bimorphic call site" do |times|
i = 0
obj0 = object0
obj1 = object1
while i < times
call_on(object0)
call_on(object1)
call_on2(obj0)
call_on2(obj0)
call_on2(obj0)
call_on2(obj0)
call_on2(obj0)
objx = obj0
obj0 = obj1
obj1 = objx
i += 1
end
end

x.report "polymorphic call site with 3 entrie" do |times|
i = 0
obj0 = object0
obj1 = object1
obj2 = object2
while i < times
call_on3(obj0)
call_on3(obj0)
call_on3(obj0)
call_on3(obj0)
call_on3(obj0)
objx = obj0
obj0 = obj1
obj1 = obj2
obj2 = objx
i += 1
end
end

x.report "polymorphic call site with 4 entrie" do |times|
i = 0
obj0 = object0
obj1 = object1
obj2 = object2
obj3 = object3
while i < times
call_on(object0)
call_on(object1)
call_on(object2)
call_on4(obj0)
call_on4(obj0)
call_on4(obj0)
call_on4(obj0)
call_on4(obj0)
objx = obj0
obj0 = obj1
obj1 = obj2
obj2 = obj3
obj3 = objx
i += 1
end
end

x.report "polymorphic call site with 5 entrie" do |times|
i = 0
obj0 = object0
obj1 = object1
obj2 = object2
obj3 = object3
obj4 = object4
while i < times
call_on5(obj0)
call_on5(obj0)
call_on5(obj0)
call_on5(obj0)
call_on5(obj0)
objx = obj0
obj0 = obj1
obj1 = obj2
obj2 = obj3
obj3 = obj4
obj4 = objx
i += 1
end
end

x.report "polymorphic call site with 6 entrie" do |times|
i = 0
obj0 = object0
obj1 = object1
obj2 = object2
obj3 = object3
obj4 = object4
obj5 = object5
while i < times
call_on6(obj0)
call_on6(obj0)
call_on6(obj0)
call_on6(obj0)
call_on6(obj0)
objx = obj0
obj0 = obj1
obj1 = obj2
obj2 = obj3
obj3 = obj4
obj4 = obj5
obj5 = objx
i += 1
end
end

x.report "polymorphic call site with 7 entrie" do |times|
i = 0
obj0 = object0
obj1 = object1
obj2 = object2
obj3 = object3
obj4 = object4
obj5 = object5
obj6 = object6
while i < times
call_on7(obj0)
call_on7(obj0)
call_on7(obj0)
call_on7(obj0)
call_on7(obj0)
objx = obj0
obj0 = obj1
obj1 = obj2
obj2 = obj3
obj3 = obj4
obj4 = obj5
obj5 = obj6
obj6 = objx
i += 1
end
end

x.report "polymorphic call site with 8 entrie" do |times|
i = 0
obj0 = object0
obj1 = object1
obj2 = object2
obj3 = object3
obj4 = object4
obj5 = object5
obj6 = object6
obj7 = object7
while i < times
call_on8(obj0)
call_on8(obj0)
call_on8(obj0)
call_on8(obj0)
call_on8(obj0)
objx = obj0
obj0 = obj1
obj1 = obj2
obj2 = obj3
obj3 = obj4
obj4 = obj5
obj5 = obj6
obj6 = obj7
obj7 = objx
i += 1
end
end

x.report "polymorphic call site with 9 entrie" do |times|
i = 0
obj0 = object0
obj1 = object1
obj2 = object2
obj3 = object3
obj4 = object4
obj5 = object5
obj6 = object6
obj7 = object7
obj8 = object8
while i < times
call_on(object0)
call_on(object1)
call_on(object2)
call_on(object3)
call_on(object4)
call_on(object5)
call_on9(obj0)
call_on9(obj0)
call_on9(obj0)
call_on9(obj0)
call_on9(obj0)
objx = obj0
obj0 = obj1
obj1 = obj2
obj2 = obj3
obj3 = obj4
obj4 = obj5
obj5 = obj6
obj6 = obj7
obj7 = obj8
obj8 = objx
i += 1
end
end

x.report "megamorphic call site with 10 entrie" do |times|
i = 0
obj0 = object0
obj1 = object1
obj2 = object2
obj3 = object3
obj4 = object4
obj5 = object5
obj6 = object6
obj7 = object7
obj8 = object8
obj9 = object9
while i < times
call_on(object0)
call_on(object1)
call_on(object2)
call_on(object3)
call_on(object4)
call_on(object5)
call_on(object6)
call_on(object7)
call_on(object8)
call_on(object9)
call_on10(obj0)
call_on10(obj0)
call_on10(obj0)
call_on10(obj0)
call_on10(obj0)
objx = obj0
obj0 = obj1
obj1 = obj2
obj2 = obj3
obj3 = obj4
obj4 = obj5
obj5 = obj6
obj6 = obj7
obj7 = obj8
obj8 = obj9
obj9 = objx
i += 1
end
end

0 comments on commit ed05eb8

Please sign in to comment.