New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Implement splat for cfuncs. Split exit exit cases to better capture where we are exiting #6929
Conversation
8eb27f3
to
a6ea33b
Compare
Can we please make sure that before this is committed, it works with the changes in #6816 (or if it won't be affected by the change, that it handles the same issue)? That won't be committed before 3.2, but hopefully it will be committed later this month or next month. |
@jeremyevans This PR doesn't deal with cfuncs that take varargs. But once I get there, I'll make sure it is compatible. Thanks for the heads up |
Yay for additional tracking of which func types can't handle splats! |
Will take a look at this failure in CI this afternoon |
367c9ec
to
fde1926
Compare
I looked into the original failure and wasn't able to recreate it. I can't think of a way of causing the failure given the code I have. Now I'm just getting http errors all the time. So CI is passing for real running things, but github actions is having issues. (I ran the test that failed in a loop for hours) |
I take it back. The error came back. Will keep trying to track it down :( |
Ugh, I just noticed that we have missed a The PR uses # YJIT splat ruby2_keywords edge case
# ISEQ call
def foo(args)
wrap(*args)
rescue ArgumentError => e
e.message
end
def wrap(a)
[a]
end
# C call
def bar(args)
Array(*args)
rescue ArgumentError => e
e.message
end
p bar([Hash.ruby2_keywords_hash({})])
p bar([Hash.ruby2_keywords_hash({})])
p foo([Hash.ruby2_keywords_hash({})])
p foo([Hash.ruby2_keywords_hash({})])
__END__
$ ./miniruby --yjit-call-threshold=1 test.rb
[]
[]
[{}]
[{}]
$ ./miniruby test.rb
"wrong number of arguments (given 0, expected 1)"
"wrong number of arguments (given 0, expected 1)"
"wrong number of arguments (given 0, expected 1)"
"wrong number of arguments (given 0, expected 1)" |
There is a second way to do ruby2keywords?? Okay. I'll go look into that. |
Once I get that issue dealt with, I will clean up this PR and rebase |
It's not really a second way since def empty_ruby2_keywords_hash = mark_hash(dummy: 0)
ruby2_keywords def mark_hash(*args) = extract(*args)
ruby2_keywords def extract(*args) = args.last.clear
|
@XrXr Got some clean up todo. But I think I got the ruby2keywords stuff working. Took me longer than I hoped because of register allocation. Which means it is not as efficient as it should be. But quick benchmarks don't show a big impact. Mind checking it out and seeing if I missed anything? |
The new guard looks good |
Fixing the conflict and rebasing. Other than that, all good for review. |
5384a42
to
56c8ed8
Compare
I'm again scared by the complexity of our method call handling, but I don't see anything wrong with your changes. Would like Alan or Kokubun to take a final look at it if possible. @jimmyhmiller can you include stats/perf from railsbench/liquid before and after? |
@maximecb Rails Bench Beforeruby 3.3.0dev (2023-01-17T13:01:19Z upstream/master df6b72b8ff) +YJIT dev [arm64-darwin22]
Command: bundle check 2> /dev/null || bundle install
The Gemfile's dependencies are satisfied
Command: bin/rails db:migrate db:seed
Using 100 posts in the database
***YJIT: Printing YJIT statistics on exit***
method call exit reasons:
iseq_has_rest 107985 (31.0%)
iseq_zsuper 46081 (13.2%)
args_splat_non_iseq 36983 (10.6%)
block_arg 34048 ( 9.8%)
iseq_arity_error 28708 ( 8.2%)
iseq_ruby2_keywords 24994 ( 7.2%)
iseq_has_no_kw 15971 ( 4.6%)
iseq_splat_with_opt 15448 ( 4.4%)
args_splat_cfunc 13934 ( 4.0%)
kw_splat 12995 ( 3.7%)
iseq_missing_optional_kw 4054 ( 1.2%)
iseq_has_kwrest 3294 ( 0.9%)
iseq_has_post 1987 ( 0.6%)
refined_method 890 ( 0.3%)
cfunc_ruby_array_varg 649 ( 0.2%)
keywords 102 ( 0.0%)
send_getter 12 ( 0.0%)
zsuper_method 9 ( 0.0%)
bmethod_block_arg 2 ( 0.0%)
ivar_set_method 2 ( 0.0%)
invokeblock exit reasons:
ifunc 5798 (56.3%)
proc 2341 (22.7%)
iseq_arg0_splat 2000 (19.4%)
iseq_tag_changed 100 ( 1.0%)
symbol 68 ( 0.7%)
invokesuper exit reasons:
block 4844 (98.2%)
me_changed 87 ( 1.8%)
leave exit reasons:
interp_return 1846823 (97.7%)
start_pc_non_zero 43887 ( 2.3%)
se_interrupt 30 ( 0.0%)
getblockparamproxy exit reasons:
block_param_modified 3 (100.0%)
getinstancevariable exit reasons:
megamorphic 13685 (100.0%)
setinstancevariable exit reasons:
(all relevant counters are zero)
opt_aref exit reasons:
(all relevant counters are zero)
expandarray exit reasons:
splat 9973 (99.8%)
rhs_too_small 22 ( 0.2%)
opt_getinlinecache exit reasons:
miss 11 (100.0%)
invalidation reasons:
constant_ic_fill 2001 (59.2%)
method_lookup 1044 (30.9%)
constant_state_bump 335 ( 9.9%)
bindings_allocations: 178
bindings_set: 0
compiled_iseq_count: 9278
compiled_block_count: 51901
compiled_branch_count: 82206
block_next_count: 15149
defer_count: 16322
freed_iseq_count: 4048
invalidation_count: 3380
constant_state_bumps: 0
inline_code_size: 8844176
outlined_code_size: 8843368
freed_code_size: 0
code_region_size: 17743872
yjit_alloc_size: 99750214
live_page_count: 1083
freed_page_count: 0
code_gc_count: 0
num_gc_obj_refs: 41292
object_shape_count: 2396
side_exit_count: 522732
total_exit_count: 2369555
total_insns_count: 89870478
vm_insns_count: 8733450
yjit_insns_count: 81659760
ratio_in_yjit: 90.3%
avg_len_in_yjit: 34.2
Top-20 most frequent exit ops (100.0% of exits):
opt_send_without_block: 155291 (29.7%)
invokesuper: 117050 (22.4%)
send: 104055 (19.9%)
opt_getconstant_path: 53734 (10.3%)
invokeblock: 36991 (7.1%)
opt_aref: 14087 (2.7%)
throw: 10587 (2.0%)
expandarray: 9995 (1.9%)
setlocal_WC_0: 8358 (1.6%)
opt_eq: 5008 (1.0%)
getinstancevariable: 3485 (0.7%)
getblockparamproxy: 2271 (0.4%)
objtostring: 448 (0.1%)
putspecialobject: 386 (0.1%)
opt_nil_p: 327 (0.1%)
definesmethod: 240 (0.0%)
checkmatch: 204 (0.0%)
once: 104 (0.0%)
opt_empty_p: 31 (0.0%)
leave: 31 (0.0%) Rails Bench Afterruby 3.3.0dev (2023-01-18T05:41:09Z yjit-cfunc-splat 01941cfb9c) +YJIT dev [arm64-darwin22]
Command: bundle check 2> /dev/null || bundle install
The Gemfile's dependencies are satisfied
Command: bin/rails db:migrate db:seed
Using 100 posts in the database
***YJIT: Printing YJIT statistics on exit***
method call exit reasons:
iseq_has_rest 107987 (31.0%)
block_arg 64598 (18.6%)
iseq_zsuper 46081 (13.2%)
iseq_arity_error 28708 ( 8.2%)
iseq_ruby2_keywords 24995 ( 7.2%)
args_splat_cfunc_var_args 16250 ( 4.7%)
iseq_has_no_kw 15971 ( 4.6%)
iseq_splat_with_opt 15448 ( 4.4%)
kw_splat 12994 ( 3.7%)
iseq_has_kwrest 5294 ( 1.5%)
iseq_missing_optional_kw 4054 ( 1.2%)
args_splat_cfunc_zuper 2002 ( 0.6%)
iseq_has_post 1987 ( 0.6%)
refined_method 891 ( 0.3%)
cfunc_ruby_array_varg 649 ( 0.2%)
keywords 102 ( 0.0%)
args_splat_cfunc_ruby2_keywords 62 ( 0.0%)
args_splat_ivar 49 ( 0.0%)
send_getter 12 ( 0.0%)
zsuper_method 9 ( 0.0%)
args_splat_optimized 5 ( 0.0%)
ivar_set_method 2 ( 0.0%)
bmethod_block_arg 2 ( 0.0%)
invokeblock exit reasons:
ifunc 5798 (56.3%)
proc 2341 (22.7%)
iseq_arg0_splat 2000 (19.4%)
iseq_tag_changed 100 ( 1.0%)
symbol 68 ( 0.7%)
invokesuper exit reasons:
block 4844 (98.2%)
me_changed 87 ( 1.8%)
leave exit reasons:
interp_return 1846785 (97.7%)
start_pc_non_zero 43885 ( 2.3%)
se_interrupt 17 ( 0.0%)
getblockparamproxy exit reasons:
block_param_modified 3 (100.0%)
getinstancevariable exit reasons:
megamorphic 13685 (100.0%)
setinstancevariable exit reasons:
(all relevant counters are zero)
opt_aref exit reasons:
(all relevant counters are zero)
expandarray exit reasons:
splat 9974 (99.8%)
rhs_too_small 22 ( 0.2%)
opt_getinlinecache exit reasons:
miss 11 (100.0%)
invalidation reasons:
constant_ic_fill 2001 (59.1%)
method_lookup 1046 (30.9%)
constant_state_bump 339 (10.0%)
bindings_allocations: 178
bindings_set: 0
compiled_iseq_count: 9278
compiled_block_count: 51918
compiled_branch_count: 82232
block_next_count: 15151
defer_count: 16331
freed_iseq_count: 4048
invalidation_count: 3386
constant_state_bumps: 0
inline_code_size: 8847540
outlined_code_size: 8844964
freed_code_size: 0
code_region_size: 17743872
yjit_alloc_size: 99765374
live_page_count: 1083
freed_page_count: 0
code_gc_count: 0
num_gc_obj_refs: 41311
object_shape_count: 2396
side_exit_count: 522713
total_exit_count: 2369498
total_insns_count: 89860430
vm_insns_count: 8733116
yjit_insns_count: 81650027
ratio_in_yjit: 90.3%
avg_len_in_yjit: 34.2
Top-20 most frequent exit ops (100.0% of exits):
opt_send_without_block: 155292 (29.7%)
invokesuper: 117052 (22.4%)
send: 104049 (19.9%)
opt_getconstant_path: 53733 (10.3%)
invokeblock: 36991 (7.1%)
opt_aref: 14087 (2.7%)
throw: 10587 (2.0%)
expandarray: 9996 (1.9%)
setlocal_WC_0: 8358 (1.6%)
opt_eq: 5008 (1.0%)
getinstancevariable: 3485 (0.7%)
getblockparamproxy: 2271 (0.4%)
objtostring: 448 (0.1%)
putspecialobject: 384 (0.1%)
opt_nil_p: 327 (0.1%)
definesmethod: 240 (0.0%)
checkmatch: 204 (0.0%)
once: 104 (0.0%)
opt_empty_p: 31 (0.0%)
setblockparam: 25 (0.0%) Liquid Render Beforeruby 3.3.0dev (2023-01-17T13:01:19Z upstream/master df6b72b8ff) +YJIT dev [arm64-darwin22]
***YJIT: Printing YJIT statistics on exit***
method call exit reasons:
iseq_has_rest 41227 (66.1%)
args_splat_non_iseq 18989 (30.4%)
block_arg 1320 ( 2.1%)
zsuper_method 792 ( 1.3%)
iseq_missing_optional_kw 39 ( 0.1%)
cfunc_ruby_array_varg 39 ( 0.1%)
ivar_set_method 1 ( 0.0%)
invokeblock exit reasons:
proc 89 (95.7%)
iseq_tag_changed 4 ( 4.3%)
invokesuper exit reasons:
block 5 (100.0%)
leave exit reasons:
interp_return 287893 (100.0%)
start_pc_non_zero 105 ( 0.0%)
se_interrupt 17 ( 0.0%)
getblockparamproxy exit reasons:
(all relevant counters are zero)
getinstancevariable exit reasons:
megamorphic 8 (100.0%)
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:
constant_ic_fill 149 (85.1%)
constant_state_bump 17 ( 9.7%)
method_lookup 9 ( 5.1%)
bindings_allocations: 77
bindings_set: 0
compiled_iseq_count: 694
compiled_block_count: 5878
compiled_branch_count: 9764
block_next_count: 2015
defer_count: 1982
freed_iseq_count: 181
invalidation_count: 175
constant_state_bumps: 0
inline_code_size: 922204
outlined_code_size: 919664
freed_code_size: 0
code_region_size: 1851392
yjit_alloc_size: 12321441
live_page_count: 113
freed_page_count: 0
code_gc_count: 0
num_gc_obj_refs: 3885
object_shape_count: 538
side_exit_count: 84920
total_exit_count: 372813
total_insns_count: 19297282
vm_insns_count: 2599567
yjit_insns_count: 16782635
ratio_in_yjit: 86.5%
avg_len_in_yjit: 44.8
Top-15 most frequent exit ops (100.0% of exits):
opt_send_without_block: 61360 (72.3%)
throw: 21516 (25.3%)
send: 1321 (1.6%)
opt_getconstant_path: 369 (0.4%)
invokesuper: 125 (0.1%)
invokeblock: 93 (0.1%)
opt_eq: 87 (0.1%)
leave: 17 (0.0%)
putspecialobject: 12 (0.0%)
once: 12 (0.0%)
opt_ltlt: 3 (0.0%)
opt_div: 2 (0.0%)
opt_aref: 1 (0.0%)
opt_aset: 1 (0.0%)
opt_empty_p: 1 (0.0%)
Liquid Render Afterruby 3.3.0dev (2023-01-18T05:41:09Z yjit-cfunc-splat 01941cfb9c) +YJIT dev [arm64-darwin22]
***YJIT: Printing YJIT statistics on exit***
method call exit reasons:
iseq_has_rest 41228 (66.1%)
args_splat_optimized 18975 (30.4%)
block_arg 1320 ( 2.1%)
zsuper_method 792 ( 1.3%)
cfunc_ruby_array_varg 39 ( 0.1%)
iseq_missing_optional_kw 39 ( 0.1%)
args_splat_cfunc_var_args 11 ( 0.0%)
ivar_set_method 1 ( 0.0%)
invokeblock exit reasons:
proc 89 (95.7%)
iseq_tag_changed 4 ( 4.3%)
invokesuper exit reasons:
block 5 (100.0%)
leave exit reasons:
interp_return 287908 (100.0%)
start_pc_non_zero 105 ( 0.0%)
se_interrupt 10 ( 0.0%)
getblockparamproxy exit reasons:
(all relevant counters are zero)
getinstancevariable exit reasons:
megamorphic 8 (100.0%)
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:
constant_ic_fill 149 (85.1%)
constant_state_bump 17 ( 9.7%)
method_lookup 9 ( 5.1%)
bindings_allocations: 77
bindings_set: 0
compiled_iseq_count: 694
compiled_block_count: 5872
compiled_branch_count: 9750
block_next_count: 2013
defer_count: 1980
freed_iseq_count: 181
invalidation_count: 175
constant_state_bumps: 0
inline_code_size: 920960
outlined_code_size: 918844
freed_code_size: 0
code_region_size: 1851392
yjit_alloc_size: 12308283
live_page_count: 113
freed_page_count: 0
code_gc_count: 0
num_gc_obj_refs: 3880
object_shape_count: 538
side_exit_count: 84903
total_exit_count: 372811
total_insns_count: 19297262
vm_insns_count: 2599586
yjit_insns_count: 16782579
ratio_in_yjit: 86.5%
avg_len_in_yjit: 44.8
Top-14 most frequent exit ops (100.0% of exits):
opt_send_without_block: 61350 (72.3%)
throw: 21516 (25.3%)
send: 1320 (1.6%)
opt_getconstant_path: 369 (0.4%)
invokesuper: 125 (0.1%)
invokeblock: 93 (0.1%)
opt_eq: 87 (0.1%)
putspecialobject: 12 (0.0%)
once: 12 (0.0%)
leave: 10 (0.0%)
opt_ltlt: 5 (0.0%)
opt_aref: 2 (0.0%)
opt_neq: 1 (0.0%)
opt_div: 1 (0.0%) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looks pretty good. Just a few nitpicks.
By the way, can you line wrap at 72 in your commit message? Not sure how to configure VSCode to do that. Maybe @k0kubun knows. Also, we like prefixing YJIT commit titles with YJIT:
. I also like to golf commit titles under 60, but you don't have to do that.
051cdd2
to
47c77a4
Compare
@XrXr Fixed the commit message. |
This also implements a new check for ruby2keywords as the last argument of a splat. This does mean that we generate more code, but in actual benchmarks where we gained speed from this (binarytrees) I don't see any significant slow down. I did have to struggle here with the register allocator to find code that didn't allocate too many registers. It's a bit hard when everything is implicit. But I think I got to the minimal amount of copying and stuff given our current allocation strategy.
(Putting out draft PR but would rather hold off on this until after 3.2 release)