Skip to content

Commit

Permalink
Reworked call site, inline cache mechanism.
Browse files Browse the repository at this point in the history
A CallSite is an abstraction of the point of call & return for another
procedure. An InlineCache is an abstraction of a particular instance of an
executable at a CallSite.

In a 'statically typed' (or early bound) language, the executable at the call
site is known 'statically', via textual analysis of the program text. In a
'dynamically-typed' (or late bound) language, the particular executable is not
known until the program is executed. Consequently, in a late-bound language, a
call site must permit dynamic reconfiguration based on the program's
execution.

This dynamic reconfiguration requires prediction: when this kind of object is
seen, we predict we will see it again. The cost of finding the executable in
the first place can then be reduced by caching the previous result of looking
up the executable. When we see this kind of object, we can retrieve the
executable from the cache at less cost than looking it up.

If our predictions are correct, and the mechanism of creating and retrieving
items from the cache is actually less than searching for the item, we can
execute the program more efficiently. However, predictions can be wrong. If
they are wrong, the cache mechanism can become pure overhead, work done that
produces no value. In this case, the caching mechanism will make the program
*less* efficient rather than more efficient.

The number of cached items is typically limited because as the number grows,
the cost of retrieving items typically grows. Ideally, the first cached item
would always be the desired one. When that is not true, some (hopefully less
costly than lookup) search mechanism is required. Contiguous structures that
permit linear probing and are CPU cache-efficient usually perform very well.
If the number of entries grows, the algorithm needs to change from on O(n)
complexity to something closer to O(1), or the extra work of the caching
mechanism will be a cost increase instead of a cost reduction.

To account for our predictions being wrong, we need to be able to update,
replace, or even discard previous predictions. In same cases, we may need to
disable the caching mechanism completely. This latter case is true when the
types of objects seen at a call site vary widely.

This change also adds some new metrics for understanding how a program is
performing from the perspective of the call sites and inline caches. The next
mechanism to add is diagnostics to see the operation of individual caches
instead of the aggregate values that the metrics provide.

Another improvement that is needed is to cache `#method_missing`,
`#respond_to?` and `#send` call sites.
  • Loading branch information
brixen committed Apr 23, 2016
1 parent 54bed47 commit 3b0777d
Show file tree
Hide file tree
Showing 66 changed files with 1,084 additions and 2,023 deletions.
28 changes: 20 additions & 8 deletions core/call_site.rb
@@ -1,23 +1,35 @@
module Rubinius
class CallSite
attr_reader :name
attr_reader :executable

def hits
0
end
attr_reader :cache

def ip
Rubinius.primitive :call_site_ip
raise PrimitiveFailure, "CallSite#ip primitive failed"
end

def location
"#{@executable.file}:#{@executable.line_from_ip(ip)}"
def depth
Rubinius.primitive :call_site_depth
raise PrimitiveFailure, "CallSite#depth primitive failed"
end

def invokes
Rubinius.primitive :call_site_invokes
raise PrimitiveFailure, "CallSite#invokes primitive failed"
end

def hits
Rubinius.primitive :call_site_hits
raise PrimitiveFailure, "CallSite#hits primitive failed"
end

def misses
Rubinius.primitive :call_site_misses
raise PrimitiveFailure, "CallSite#misses primitive failed"
end

def inspect
"#<#{self.class.name}:0x#{self.object_id.to_s(16)} #{location}##{@name}(#{hits})>"
"#<#{self.class.name}:0x#{self.object_id.to_s(16)} name=#{@name} ip=#{ip} depth=#{depth} invokes=#{invokes} hits=#{hits} misses=#{misses}>"
end
end
end
2 changes: 0 additions & 2 deletions core/load_order.txt
Expand Up @@ -77,7 +77,6 @@ metrics.rb
mirror.rb
missing_method.rb
module.rb
mono_inline_cache.rb
mutex.rb
native_method.rb
nil.rb
Expand All @@ -88,7 +87,6 @@ options.rb
pack.rb
pointer.rb
pointer_accessors.rb
poly_inline_cache.rb
proc.rb
proc_mirror.rb
process.rb
Expand Down
25 changes: 0 additions & 25 deletions core/mono_inline_cache.rb

This file was deleted.

52 changes: 0 additions & 52 deletions core/poly_inline_cache.rb

This file was deleted.

10 changes: 10 additions & 0 deletions library/rubinius/configuration.rb
Expand Up @@ -168,6 +168,16 @@
c.vm_variable "profiler.threshold", 1000000,
"The minimum number of nanoseconds a profiler node must have to be reported"

c.section "machine" do |s|
s.section "call_site" do |cs|
cs.vm_variable "cache", true,
"Cache executables at call sites"

cs.vm_variable "limit", 3,
"Maximum number of caches at call sites"
end
end

c.section "system" do |s|
s.vm_variable "tmp", "$TMPDIR",
"Default temp/fallback directory for the process"
Expand Down

0 comments on commit 3b0777d

Please sign in to comment.