Feature #12364
closedCopy superclass serial number to singleton subclasses for better IMC hits
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¶
- It's pretty small
- 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¶
- 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)
- 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:
And so does Event Machine:
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
Updated by ko1 (Koichi Sasada) about 8 years ago
I don't have any objection about this change because it is not big change.
Did you measure not micro-benchmarks?
Updated by Anonymous almost 8 years ago
- Status changed from Open to Closed
Applied in changeset r56144.
Copy the serial number from the super class to the singleton class
This helps hit inline method caches more frequently. Before this
commit:
[aaron@TC ruby (trunk)]$ time ./ruby -v benchmark/bm_vm2_poly_singleton.rb
ruby 2.4.0dev (2016-09-12 trunk 56141) [x86_64-darwin15]
real 0m3.679s
user 0m3.632s
sys 0m0.022s
After this commit:
[aaron@TC ruby (trunk)]$ time ./ruby -v benchmark/bm_vm2_poly_singleton.rb
ruby 2.4.0dev (2016-09-12 trunk 56141) [x86_64-darwin15]
last_commit=Copy the serial number from the super class to the singleton class
real 0m2.246s
user 0m2.203s
sys 0m0.020s
[Feature #12364]
[ruby-core:75425]