Project

General

Profile

Actions

Feature #12364

closed

Copy superclass serial number to singleton subclasses for better IMC hits

Added by tenderlovemaking (Aaron Patterson) almost 8 years ago. Updated over 7 years ago.

Status:
Closed
Target version:
-
[ruby-core:75425]

Description

Hi,

I've attached a patch that copies the serial number from the superclass to newly created singleton subclasses. For example:

class Foo
  def x; end
end

def bar(v)
  v.x
end

a = Foo.new
bar(a)
a.singleton_class
bar(a)

Today, the IMC for "v.x" would miss on the second call because calling "singleton_class" would mutate the class pointer for the "a" variable and that would result in the "a" variable having a different serial number than the previous call.

Merits of the patch

  1. It's pretty small
  2. It looks great in micro benchmarks ;)

Given this benchmark:

class C1
  def m; 1; end
end

o1 = C1.new
o2 = C1.new
o2.singleton_class

i = 0
while i<6_000_000 # benchmark loop 2
  o = (i % 2 == 0) ? o1 : o2
  o.m; o.m; o.m; o.m; o.m; o.m; o.m; o.m
  i += 1
end

Here is trunk Ruby:

[aaron@TC ruby (trunk)]$ time ./ruby benchmark/bm_vm2_poly_singleton.rb 

real	0m2.334s
user	0m2.308s
sys	0m0.015s

And with my patch applied:

[aaron@TC ruby (anon_ic)]$ time ./ruby benchmark/bm_vm2_poly_singleton.rb 

real	0m1.387s
user	0m1.360s
sys	0m0.014s

Demerits

  1. I like to use RubyVM.stat to see if any caches are being broken. This still mutates the global counter, so RubyVM.stat is slightly less helpful (though that data is internal)
  2. I don't think it's common to access the singleton class and not add methods, so Real World impact may not be very much.

I found that RSpec accesses the singleton class but does not add methods:

https://github.com/rspec/rspec-core/blob/4504b72a066fe618dd4ccf9425dee349e0f9c560/lib/rspec/core/example.rb#L441

And so does Event Machine:

https://github.com/eventmachine/eventmachine/blob/539ae89b1b810f35d2585e4ac239013ac606f60e/lib/em/connection.rb#L49

I haven't been able to check our applications at work yet, but I tried to take some statistics on an RSpec test. I wrote an RSpec test that generated many test cases:

https://gist.github.com/tenderlove/9ea76c0274812b477f32e4a542a97f82

Then I logged inline cache hits and misses using a tracepoint that I added: https://github.com/tenderlove/ruby/tree/IC_measure
I generated 1000 tests in RSpec, and I can see the cache miss rate drop from a 4.5% to 3%.

I tried timing the tests before and after the patch, but I could not prove any significant difference in overall time.

I think this patch is small enough that it's worth while to apply, but I don't think it's going to get us much closer to the 3x3 goal. ;-)


Files

Actions

Also available in: Atom PDF

Like0
Like0Like0