Skip to content
  • Jeremy Evans's avatar
    f6254f77
    Speed up calling iseq bmethods · f6254f77
    Jeremy Evans authored
    Currently, bmethod arguments are copied from the VM stack to the
    C stack in vm_call_bmethod, then copied from the C stack to the VM
    stack later in invoke_iseq_block_from_c.  This is inefficient.
    
    This adds vm_call_iseq_bmethod and vm_call_noniseq_bmethod.
    vm_call_iseq_bmethod is an optimized method that skips stack
    copies (though there is one copy to remove the receiver from
    the stack), and avoids calling vm_call_bmethod_body,
    rb_vm_invoke_bmethod, invoke_block_from_c_proc,
    invoke_iseq_block_from_c, and vm_yield_setup_args.
    
    Th vm_call_iseq_bmethod argument handling is similar to the
    way normal iseq methods are called, and allows for similar
    performance optimizations when using splats or keywords.
    However, even in the no argument case it's still significantly
    faster.
    
    A benchmark is added for bmethod calling.  In my environment,
    it improves bmethod calling performance by 38-59% for simple
    bmethod calls, and up to 180% for bmethod calls passing
    literal keywords on both sides.
    
    ```
    
    ./miniruby-iseq-bmethod:  18159792.6 i/s
              ./miniruby-m:  13174419.1 i/s - 1.38x  slower
    
                       bmethod_simple_1
    ./miniruby-iseq-bmethod:  15890745.4 i/s
              ./miniruby-m:  10008972.7 i/s - 1.59x  slower
    
                 bmethod_simple_0_splat
    ./miniruby-iseq-bmethod:  13142804.3 i/s
              ./miniruby-m:  11168595.2 i/s - 1.18x  slower
    
                 bmethod_simple_1_splat
    ./miniruby-iseq-bmethod:  12375791.0 i/s
              ./miniruby-m:   8491140.1 i/s - 1.46x  slower
    
                       bmethod_no_splat
    ./miniruby-iseq-bmethod:  10151258.8 i/s
              ./miniruby-m:   8716664.1 i/s - 1.16x  slower
    
                        bmethod_0_splat
    ./miniruby-iseq-bmethod:   8138802.5 i/s
              ./miniruby-m:   7515600.2 i/s - 1.08x  slower
    
                        bmethod_1_splat
    ./miniruby-iseq-bmethod:   8028372.7 i/s
              ./miniruby-m:   5947658.6 i/s - 1.35x  slower
    
                       bmethod_10_splat
    ./miniruby-iseq-bmethod:   6953514.1 i/s
              ./miniruby-m:   4840132.9 i/s - 1.44x  slower
    
                      bmethod_100_splat
    ./miniruby-iseq-bmethod:   5287288.4 i/s
              ./miniruby-m:   2243218.4 i/s - 2.36x  slower
    
                             bmethod_kw
    ./miniruby-iseq-bmethod:   8931358.2 i/s
              ./miniruby-m:   3185818.6 i/s - 2.80x  slower
    
                          bmethod_no_kw
    ./miniruby-iseq-bmethod:  12281287.4 i/s
              ./miniruby-m:  10041727.9 i/s - 1.22x  slower
    
                       bmethod_kw_splat
    ./miniruby-iseq-bmethod:   5618956.8 i/s
              ./miniruby-m:   3657549.5 i/s - 1.54x  slower
    ```
    f6254f77
    Speed up calling iseq bmethods
    Jeremy Evans authored
    Currently, bmethod arguments are copied from the VM stack to the
    C stack in vm_call_bmethod, then copied from the C stack to the VM
    stack later in invoke_iseq_block_from_c.  This is inefficient.
    
    This adds vm_call_iseq_bmethod and vm_call_noniseq_bmethod.
    vm_call_iseq_bmethod is an optimized method that skips stack
    copies (though there is one copy to remove the receiver from
    the stack), and avoids calling vm_call_bmethod_body,
    rb_vm_invoke_bmethod, invoke_block_from_c_proc,
    invoke_iseq_block_from_c, and vm_yield_setup_args.
    
    Th vm_call_iseq_bmethod argument handling is similar to the
    way normal iseq methods are called, and allows for similar
    performance optimizations when using splats or keywords.
    However, even in the no argument case it's still significantly
    faster.
    
    A benchmark is added for bmethod calling.  In my environment,
    it improves bmethod calling performance by 38-59% for simple
    bmethod calls, and up to 180% for bmethod calls passing
    literal keywords on both sides.
    
    ```
    
    ./miniruby-iseq-bmethod:  18159792.6 i/s
              ./miniruby-m:  13174419.1 i/s - 1.38x  slower
    
                       bmethod_simple_1
    ./miniruby-iseq-bmethod:  15890745.4 i/s
              ./miniruby-m:  10008972.7 i/s - 1.59x  slower
    
                 bmethod_simple_0_splat
    ./miniruby-iseq-bmethod:  13142804.3 i/s
              ./miniruby-m:  11168595.2 i/s - 1.18x  slower
    
                 bmethod_simple_1_splat
    ./miniruby-iseq-bmethod:  12375791.0 i/s
              ./miniruby-m:   8491140.1 i/s - 1.46x  slower
    
                       bmethod_no_splat
    ./miniruby-iseq-bmethod:  10151258.8 i/s
              ./miniruby-m:   8716664.1 i/s - 1.16x  slower
    
                        bmethod_0_splat
    ./miniruby-iseq-bmethod:   8138802.5 i/s
              ./miniruby-m:   7515600.2 i/s - 1.08x  slower
    
                        bmethod_1_splat
    ./miniruby-iseq-bmethod:   8028372.7 i/s
              ./miniruby-m:   5947658.6 i/s - 1.35x  slower
    
                       bmethod_10_splat
    ./miniruby-iseq-bmethod:   6953514.1 i/s
              ./miniruby-m:   4840132.9 i/s - 1.44x  slower
    
                      bmethod_100_splat
    ./miniruby-iseq-bmethod:   5287288.4 i/s
              ./miniruby-m:   2243218.4 i/s - 2.36x  slower
    
                             bmethod_kw
    ./miniruby-iseq-bmethod:   8931358.2 i/s
              ./miniruby-m:   3185818.6 i/s - 2.80x  slower
    
                          bmethod_no_kw
    ./miniruby-iseq-bmethod:  12281287.4 i/s
              ./miniruby-m:  10041727.9 i/s - 1.22x  slower
    
                       bmethod_kw_splat
    ./miniruby-iseq-bmethod:   5618956.8 i/s
              ./miniruby-m:   3657549.5 i/s - 1.54x  slower
    ```
Loading