diff options
author | eileencodes <[email protected]> | 2023-02-17 15:04:51 -0500 |
---|---|---|
committer | Aaron Patterson <[email protected]> | 2023-02-21 13:59:54 -0800 |
commit | ae9e1aee59b0db1e61aa0473556165f9fd719cde (patch) | |
tree | 4055be3b3cdcc6ac141fbab85c0c80622f1d3642 | |
parent | 9f8056a7dd13168a7d1f81380435a6a2e21c44d3 (diff) |
Call rb_ivar_set instead of exiting for many ivars
Previously, when we have a lot of ivars defined, we would exit via
`jit_chain_guard` for megamorphic ivars. Now if we have more than the
max depth of ivars we can call `rb_ivar_set` instead of exiting.
Using the following script:
```ruby
class A
def initialize
@a = 1
end
def a
@a
end
end
N = 30
N.times do |i|
eval <<-eorb
class A#{i} < A
def initialize
@a#{i} = 1
super
end
end
eorb
end
klasses = N.times.map { Object.const_get(:"A#{_1}") }
1000.times do
klasses.each do |k|
k.new.a
end
end
```
Exits before this change show exits for `setinstancevariable`:
```
***YJIT: Printing YJIT statistics on exit***
method call exit reasons:
klass_megamorphic: 24,975 (100.0%)
invokeblock exit reasons:
(all relevant counters are zero)
invokesuper exit reasons:
(all relevant counters are zero)
leave exit reasons:
interp_return: 26,948 (100.0%)
se_interrupt: 1 ( 0.0%)
getblockparamproxy exit reasons:
(all relevant counters are zero)
getinstancevariable exit reasons:
megamorphic: 13,986 (100.0%)
setinstancevariable exit reasons:
megamorphic: 19,980 (100.0%)
opt_aref exit reasons:
(all relevant counters are zero)
expandarray exit reasons:
(all relevant counters are zero)
opt_getinlinecache exit reasons:
(all relevant counters are zero)
invalidation reasons:
(all relevant counters are zero)
num_send: 155,823
num_send_known_class: 0 ( 0.0%)
num_send_polymorphic: 119,880 (76.9%)
bindings_allocations: 0
bindings_set: 0
compiled_iseq_count: 36
compiled_block_count: 158
compiled_branch_count: 240
block_next_count: 10
defer_count: 70
freed_iseq_count: 0
invalidation_count: 0
constant_state_bumps: 0
inline_code_size: 29,216
outlined_code_size: 27,948
freed_code_size: 0
code_region_size: 65,536
live_context_size: 8,322
live_context_count: 219
live_page_count: 4
freed_page_count: 0
code_gc_count: 0
num_gc_obj_refs: 130
object_shape_count: 295
side_exit_count: 58,942
total_exit_count: 85,890
yjit_insns_count: 1,023,581
avg_len_in_yjit: 11.2
Top-4 most frequent exit ops (100.0% of exits):
opt_send_without_block: 24,975 (42.4%)
setinstancevariable: 19,980 (33.9%)
getinstancevariable: 13,986 (23.7%)
leave: 1 ( 0.0%)
```
Exits after this change show we have no exits for `setinstancevariable`.
```
***YJIT: Printing YJIT statistics on exit***
method call exit reasons:
klass_megamorphic: 24,975 (100.0%)
invokeblock exit reasons:
(all relevant counters are zero)
invokesuper exit reasons:
(all relevant counters are zero)
leave exit reasons:
interp_return: 60,912 (100.0%)
se_interrupt: 3 ( 0.0%)
getblockparamproxy exit reasons:
(all relevant counters are zero)
getinstancevariable exit reasons:
(all relevant counters are zero)
setinstancevariable exit reasons:
(all relevant counters are zero)
opt_aref exit reasons:
(all relevant counters are zero)
expandarray exit reasons:
(all relevant counters are zero)
opt_getinlinecache exit reasons:
(all relevant counters are zero)
invalidation reasons:
(all relevant counters are zero)
num_send: 155,823
num_send_known_class: 0 ( 0.0%)
num_send_polymorphic: 119,880 (76.9%)
bindings_allocations: 0
bindings_set: 0
compiled_iseq_count: 36
compiled_block_count: 179
compiled_branch_count: 240
block_next_count: 11
defer_count: 70
freed_iseq_count: 0
invalidation_count: 0
constant_state_bumps: 0
inline_code_size: 31,032
outlined_code_size: 29,708
freed_code_size: 0
code_region_size: 65,536
live_context_size: 8,360
live_context_count: 220
live_page_count: 4
freed_page_count: 0
code_gc_count: 0
num_gc_obj_refs: 130
object_shape_count: 295
side_exit_count: 24,978
total_exit_count: 85,890
yjit_insns_count: 1,076,966
avg_len_in_yjit: 12.2
Top-2 most frequent exit ops (100.0% of exits):
opt_send_without_block: 24,975 (100.0%)
leave: 3 ( 0.0%)
```
Co-authored-by: Aaron Patterson <[email protected]>
Notes
Notes:
Merged: https://github.com/ruby/ruby/pull/7335
-rw-r--r-- | yjit/src/codegen.rs | 2 |
1 files changed, 1 insertions, 1 deletions
diff --git a/yjit/src/codegen.rs b/yjit/src/codegen.rs index 636a28ad4c..564a39d42c 100644 --- a/yjit/src/codegen.rs +++ b/yjit/src/codegen.rs @@ -2182,7 +2182,7 @@ fn gen_setinstancevariable( // If the receiver isn't a T_OBJECT, or uses a custom allocator, // then just write out the IV write as a function call. // too-complex shapes can't use index access, so we use rb_ivar_get for them too. - if !receiver_t_object || uses_custom_allocator || comptime_receiver.shape_too_complex() { + if !receiver_t_object || uses_custom_allocator || comptime_receiver.shape_too_complex() || (ctx.get_chain_depth() as i32) >= SET_IVAR_MAX_DEPTH { asm.comment("call rb_vm_setinstancevariable()"); let ic = jit.get_arg(1).as_u64(); // type IVC |