Skip to content
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

YJIT: Handle splat+rest for args pass greater than required #7468

Merged
merged 1 commit into from Mar 7, 2023

Conversation

jimmyhmiller
Copy link
Contributor

For example:

def my_func(x, y, *rest)
    p [x, y, rest]
end

my_func(1, 2, 3, *[4, 5])

@matzbot matzbot requested a review from a team March 7, 2023 20:38
For example:

```ruby
def my_func(x, y, *rest)
    p [x, y, rest]
end

my_func(1, 2, 3, *[4, 5])
```
@jimmyhmiller
Copy link
Contributor Author

Here are the stats of railsbench and liquid-render before and after these changes

Big highlight liquid-render

ratio_in_yjit:                 88.3%
ratio_in_yjit:                 88.7%
Rails Bench Before
         ***YJIT: Printing YJIT statistics on exit***
method call exit reasons: 
                            block_arg:     65,022 (20.3%)
                          iseq_zsuper:     60,079 (18.7%)
              iseq_has_rest_and_block:     54,470 (17.0%)
                     iseq_arity_error:     30,685 ( 9.6%)
                  iseq_ruby2_keywords:     25,058 ( 7.8%)
                       iseq_has_no_kw:     17,298 ( 5.4%)
            args_splat_cfunc_var_args:     16,296 ( 5.1%)
                             kw_splat:     12,997 ( 4.1%)
    iseq_has_rest_and_splat_not_equal:     12,610 ( 3.9%)
                      iseq_has_kwrest:      7,320 ( 2.3%)
                    klass_megamorphic:      7,069 ( 2.2%)
             iseq_missing_optional_kw:      4,054 ( 1.3%)
                 iseq_has_rest_and_kw:      2,183 ( 0.7%)
               args_splat_cfunc_zuper:      2,002 ( 0.6%)
                        iseq_has_post:      1,988 ( 0.6%)
                cfunc_ruby_array_varg:      1,363 ( 0.4%)
                             keywords:        102 ( 0.0%)
      args_splat_cfunc_ruby2_keywords:         62 ( 0.0%)
                      args_splat_ivar:         50 ( 0.0%)
           iseq_has_rest_and_optional:         15 ( 0.0%)
                        zsuper_method:         14 ( 0.0%)
                          send_getter:         12 ( 0.0%)
                  args_splat_opt_call:          5 ( 0.0%)
          splatarray_length_not_equal:          2 ( 0.0%)
                      ivar_set_method:          2 ( 0.0%)
                    bmethod_block_arg:          2 ( 0.0%)
invokeblock exit reasons: 
      proc:      2,480 (93.1%)
    symbol:        183 ( 6.9%)
invokesuper exit reasons: 
    me_changed:      4,793 (68.5%)
         block:      2,201 (31.5%)
leave exit reasons: 
        interp_return:  1,757,043 (97.6%)
    start_pc_non_zero:     43,884 ( 2.4%)
         se_interrupt:         34 ( 0.0%)
getblockparamproxy exit reasons: 
    block_param_modified:          3 (100.0%)
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: 
            splat:      9,974 (99.8%)
    rhs_too_small:         23 ( 0.2%)
opt_getinlinecache exit reasons: 
    miss:         11 (100.0%)
invalidation reasons: 
       constant_ic_fill:      2,069 (58.1%)
          method_lookup:      1,152 (32.4%)
    constant_state_bump:        340 ( 9.5%)
num_send:                 13,820,838
num_send_known_class:        493,256 ( 3.6%)
num_send_polymorphic:      1,804,191 (13.1%)
iseq_stack_too_large:              0
iseq_too_long:                     0
bindings_allocations:            193
bindings_set:                      0
compiled_iseq_count:           9,311
compiled_block_count:         55,762
compiled_branch_count:        90,216
block_next_count:             15,354
defer_count:                  17,289
defer_empty_count:             2,838
freed_iseq_count:              4,072
invalidation_count:            3,561
constant_state_bumps:              0
get_ivar_max_depth:           10,074
inline_code_size:         10,558,196
outlined_code_size:       10,556,104
freed_code_size:                   0
code_region_size:         21,118,976
yjit_alloc_size:          16,444,549
live_context_size:         1,498,308
live_context_count:           53,511
live_page_count:               1,289
freed_page_count:                  0
code_gc_count:                     0
num_gc_obj_refs:              47,495
object_shape_count:            2,452
side_exit_count:             433,561
total_exit_count:          2,190,604
total_insns_count:        89,627,660
vm_insns_count:            7,759,514
yjit_insns_count:         82,301,707
ratio_in_yjit:                 91.3%
avg_len_in_yjit:                37.4
Top-20 most frequent exit ops (100.0% of exits):
               invokesuper:    105,417 (24.3%)
                      send:     98,316 (22.7%)
    opt_send_without_block:     92,022 (21.2%)
      opt_getconstant_path:     53,911 (12.4%)
               invokeblock:     31,347 ( 7.2%)
                  opt_aref:     14,086 ( 3.2%)
                     throw:     10,655 ( 2.5%)
               expandarray:      9,997 ( 2.3%)
             setlocal_WC_0:      8,401 ( 1.9%)
                    opt_eq:      4,991 ( 1.2%)
        getblockparamproxy:      2,271 ( 0.5%)
          putspecialobject:        729 ( 0.2%)
               objtostring:        430 ( 0.1%)
                 opt_nil_p:        313 ( 0.1%)
             definesmethod:        237 ( 0.1%)
                checkmatch:        205 ( 0.0%)
                      once:        104 ( 0.0%)
                     leave:         35 ( 0.0%)
               opt_empty_p:         30 ( 0.0%)
             setblockparam:         25 ( 0.0%)
Rails Bench After
         ***YJIT: Printing YJIT statistics on exit***
method call exit reasons: 
                          block_arg:     65,019 (20.3%)
                        iseq_zsuper:     60,079 (18.7%)
            iseq_has_rest_and_block:     54,471 (17.0%)
                   iseq_arity_error:     30,685 ( 9.6%)
                iseq_ruby2_keywords:     25,058 ( 7.8%)
                     iseq_has_no_kw:     17,293 ( 5.4%)
          args_splat_cfunc_var_args:     16,296 ( 5.1%)
                           kw_splat:     12,997 ( 4.1%)
      iseq_has_rest_and_splat_fewer:     10,610 ( 3.3%)
                    iseq_has_kwrest:      7,319 ( 2.3%)
                  klass_megamorphic:      7,069 ( 2.2%)
           iseq_missing_optional_kw:      4,054 ( 1.3%)
               iseq_has_rest_and_kw:      2,182 ( 0.7%)
         iseq_has_rest_and_optional:      2,015 ( 0.6%)
             args_splat_cfunc_zuper:      2,002 ( 0.6%)
                      iseq_has_post:      1,988 ( 0.6%)
              cfunc_ruby_array_varg:      1,364 ( 0.4%)
                           keywords:        102 ( 0.0%)
    args_splat_cfunc_ruby2_keywords:         62 ( 0.0%)
                    args_splat_ivar:         50 ( 0.0%)
                      zsuper_method:         14 ( 0.0%)
                        send_getter:         12 ( 0.0%)
                args_splat_opt_call:          5 ( 0.0%)
        splatarray_length_not_equal:          2 ( 0.0%)
                    ivar_set_method:          2 ( 0.0%)
                  bmethod_block_arg:          2 ( 0.0%)
invokeblock exit reasons: 
      proc:      2,480 (93.1%)
    symbol:        183 ( 6.9%)
invokesuper exit reasons: 
    me_changed:      4,792 (68.5%)
         block:      2,201 (31.5%)
leave exit reasons: 
        interp_return:  1,756,957 (97.6%)
    start_pc_non_zero:     43,884 ( 2.4%)
         se_interrupt:         25 ( 0.0%)
getblockparamproxy exit reasons: 
    block_param_modified:          3 (100.0%)
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: 
            splat:      9,972 (99.8%)
    rhs_too_small:         23 ( 0.2%)
opt_getinlinecache exit reasons: 
    miss:         11 (100.0%)
invalidation reasons: 
       constant_ic_fill:      2,069 (58.1%)
          method_lookup:      1,152 (32.4%)
    constant_state_bump:        338 ( 9.5%)
num_send:                 13,820,666
num_send_known_class:        493,251 ( 3.6%)
num_send_polymorphic:      1,804,196 (13.1%)
iseq_stack_too_large:              0
iseq_too_long:                     0
bindings_allocations:            193
bindings_set:                      0
compiled_iseq_count:           9,311
compiled_block_count:         55,747
compiled_branch_count:        90,182
block_next_count:             15,351
defer_count:                  17,280
defer_empty_count:             2,837
freed_iseq_count:              4,072
invalidation_count:            3,559
constant_state_bumps:              0
get_ivar_max_depth:           10,074
inline_code_size:         10,554,684
outlined_code_size:       10,553,724
freed_code_size:                   0
code_region_size:         21,118,976
yjit_alloc_size:          16,439,713
live_context_size:         1,497,328
live_context_count:           53,476
live_page_count:               1,289
freed_page_count:                  0
code_gc_count:                     0
num_gc_obj_refs:              47,471
object_shape_count:            2,452
side_exit_count:             433,670
total_exit_count:          2,190,627
total_insns_count:        89,627,535
vm_insns_count:            7,760,630
yjit_insns_count:         82,300,575
ratio_in_yjit:                 91.3%
avg_len_in_yjit:                37.4
Top-20 most frequent exit ops (100.0% of exits):
               invokesuper:    105,416 (24.3%)
                      send:     98,312 (22.7%)
    opt_send_without_block:     92,030 (21.2%)
      opt_getconstant_path:     54,025 (12.5%)
               invokeblock:     31,347 ( 7.2%)
                  opt_aref:     14,087 ( 3.2%)
                     throw:     10,655 ( 2.5%)
               expandarray:      9,995 ( 2.3%)
             setlocal_WC_0:      8,401 ( 1.9%)
                    opt_eq:      4,991 ( 1.2%)
        getblockparamproxy:      2,271 ( 0.5%)
          putspecialobject:        729 ( 0.2%)
               objtostring:        430 ( 0.1%)
                 opt_nil_p:        313 ( 0.1%)
             definesmethod:        237 ( 0.1%)
                checkmatch:        205 ( 0.0%)
                      once:        104 ( 0.0%)
               opt_empty_p:         30 ( 0.0%)
                     leave:         26 ( 0.0%)
             setblockparam:         25 ( 0.0%)
Liquid Render Before
         ***YJIT: Printing YJIT statistics on exit***
method call exit reasons: 
    iseq_has_rest_and_splat_not_equal:     19,698 (89.1%)
                            block_arg:      1,476 ( 6.7%)
                        zsuper_method:        832 ( 3.8%)
                    klass_megamorphic:         33 ( 0.1%)
                cfunc_ruby_array_varg:         33 ( 0.1%)
                 iseq_has_rest_and_kw:         14 ( 0.1%)
                          send_getter:         12 ( 0.1%)
             iseq_missing_optional_kw:          9 ( 0.0%)
            args_splat_cfunc_var_args:          8 ( 0.0%)
                             kw_splat:          3 ( 0.0%)
                      ivar_set_method:          1 ( 0.0%)
              iseq_has_rest_and_block:          1 ( 0.0%)
invokeblock exit reasons: 
      proc:        351 (81.2%)
    symbol:         81 (18.8%)
invokesuper exit reasons: 
    block:         83 (100.0%)
leave exit reasons: 
        interp_return:    275,906 (100.0%)
    start_pc_non_zero:        111 ( 0.0%)
         se_interrupt:         13 ( 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: 
    rhs_too_small:         10 (100.0%)
opt_getinlinecache exit reasons: 
    (all relevant counters are zero)
invalidation reasons: 
       constant_ic_fill:        582 (81.3%)
    constant_state_bump:         91 (12.7%)
          method_lookup:         43 ( 6.0%)
num_send:                  3,025,112
num_send_known_class:        135,862 ( 4.5%)
num_send_polymorphic:        584,831 (19.3%)
iseq_stack_too_large:              1
iseq_too_long:                     0
bindings_allocations:            154
bindings_set:                      0
compiled_iseq_count:           1,681
compiled_block_count:         11,980
compiled_branch_count:        19,837
block_next_count:              4,228
defer_count:                   3,905
defer_empty_count:               769
freed_iseq_count:                558
invalidation_count:              716
constant_state_bumps:              0
get_ivar_max_depth:               10
inline_code_size:          2,052,356
outlined_code_size:        2,050,980
freed_code_size:                   0
code_region_size:          4,112,384
yjit_alloc_size:           5,513,749
live_context_size:           516,012
live_context_count:           18,429
live_page_count:                 251
freed_page_count:                  0
code_gc_count:                     0
num_gc_obj_refs:               7,993
object_shape_count:              766
side_exit_count:              42,763
total_exit_count:            318,669
total_insns_count:        20,340,563
vm_insns_count:            2,377,711
yjit_insns_count:         18,005,615
ratio_in_yjit:                 88.3%
avg_len_in_yjit:                56.4
Top-16 most frequent exit ops (100.0% of exits):
    opt_send_without_block:     20,620 (48.2%)
                     throw:     19,107 (44.7%)
                      send:      1,498 ( 3.5%)
      opt_getconstant_path:        752 ( 1.8%)
               invokeblock:        432 ( 1.0%)
                    opt_eq:         90 ( 0.2%)
                      once:         86 ( 0.2%)
               invokesuper:         84 ( 0.2%)
          putspecialobject:         36 ( 0.1%)
                     leave:         13 ( 0.0%)
             setlocal_WC_0:         12 ( 0.0%)
               expandarray:         10 ( 0.0%)
                  opt_aref:         10 ( 0.0%)
        getblockparamproxy:          9 ( 0.0%)
                checkmatch:          2 ( 0.0%)
                  opt_ltlt:          2 ( 0.0%)
Liquid Render After
         ***YJIT: Printing YJIT statistics on exit***
method call exit reasons: 
                    block_arg:      1,476 (60.9%)
                zsuper_method:        832 (34.4%)
            klass_megamorphic:         33 ( 1.4%)
        cfunc_ruby_array_varg:         33 ( 1.4%)
         iseq_has_rest_and_kw:         14 ( 0.6%)
                  send_getter:         12 ( 0.5%)
     iseq_missing_optional_kw:          9 ( 0.4%)
    args_splat_cfunc_var_args:          8 ( 0.3%)
                     kw_splat:          3 ( 0.1%)
      iseq_has_rest_and_block:          1 ( 0.0%)
              ivar_set_method:          1 ( 0.0%)
invokeblock exit reasons: 
      proc:        351 (81.2%)
    symbol:         81 (18.8%)
invokesuper exit reasons: 
    block:         83 (100.0%)
leave exit reasons: 
        interp_return:    275,919 (100.0%)
    start_pc_non_zero:        112 ( 0.0%)
         se_interrupt:         14 ( 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: 
    rhs_too_small:         10 (100.0%)
opt_getinlinecache exit reasons: 
    (all relevant counters are zero)
invalidation reasons: 
       constant_ic_fill:        582 (81.1%)
    constant_state_bump:         93 (13.0%)
          method_lookup:         43 ( 6.0%)
num_send:                  3,025,030
num_send_known_class:        135,860 ( 4.5%)
num_send_polymorphic:        584,801 (19.3%)
iseq_stack_too_large:              1
iseq_too_long:                     0
bindings_allocations:            154
bindings_set:                      0
compiled_iseq_count:           1,681
compiled_block_count:         11,994
compiled_branch_count:        19,861
block_next_count:              4,231
defer_count:                   3,911
defer_empty_count:               770
freed_iseq_count:                558
invalidation_count:              718
constant_state_bumps:              0
get_ivar_max_depth:               10
inline_code_size:          2,010,324
outlined_code_size:        2,008,956
freed_code_size:                   0
code_region_size:          4,030,464
yjit_alloc_size:           5,519,593
live_context_size:           516,684
live_context_count:           18,453
live_page_count:                 246
freed_page_count:                  0
code_gc_count:                     0
num_gc_obj_refs:               8,012
object_shape_count:              766
side_exit_count:              23,066
total_exit_count:            298,985
total_insns_count:        20,340,467
vm_insns_count:            2,299,936
yjit_insns_count:         18,063,597
ratio_in_yjit:                 88.7%
avg_len_in_yjit:                60.3
Top-16 most frequent exit ops (100.0% of exits):
                     throw:     19,107 (82.8%)
                      send:      1,498 ( 6.5%)
    opt_send_without_block:        920 ( 4.0%)
      opt_getconstant_path:        752 ( 3.3%)
               invokeblock:        432 ( 1.9%)
                    opt_eq:         90 ( 0.4%)
                      once:         87 ( 0.4%)
               invokesuper:         84 ( 0.4%)
          putspecialobject:         36 ( 0.2%)
                     leave:         14 ( 0.1%)
             setlocal_WC_0:         12 ( 0.1%)
                  opt_aref:         11 ( 0.0%)
               expandarray:         10 ( 0.0%)
        getblockparamproxy:          9 ( 0.0%)
                checkmatch:          2 ( 0.0%)
                  opt_ltlt:          2 ( 0.0%)

@maximecb maximecb merged commit 56df6d5 into ruby:master Mar 7, 2023
95 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
2 participants