[ruby-core:75425] [Ruby trunk Feature#12364] Copy superclass serial number to singleton subclasses for better IMC hits

From: tenderlove@...
Date: 2016-05-10 00:33:11 UTC
List: ruby-core #75425
Issue #12364 has been reported by Aaron Patterson.

----------------------------------------
Feature #12364: Copy superclass serial number to singleton subclasses for better IMC hits
https://bugs.ruby-lang.org/issues/12364

* Author: Aaron Patterson
* Status: Open
* Priority: Normal
* Assignee: Koichi Sasada
----------------------------------------
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--------------------------------
0001-Copy-the-serial-number-from-the-super-class-to-the-s.patch (1.31 KB)


-- 
https://bugs.ruby-lang.org/

Unsubscribe: <mailto:ruby-core-request@ruby-lang.org?subject=unsubscribe>
<http://lists.ruby-lang.org/cgi-bin/mailman/options/ruby-core>

In This Thread

Prev Next