summaryrefslogtreecommitdiff
path: root/benchmark
diff options
context:
space:
mode:
authorJeremy Evans <code@jeremyevans.net>2023-03-23 14:39:31 -0700
committerJeremy Evans <code@jeremyevans.net>2023-04-25 08:06:16 -0700
commitf6254f77f7a7c4d1f11180b3b382680868bd9ee4 (patch)
treeabfd87315df6e5742fc71ee6ea9e1bd45fed5654 /benchmark
parent99c6d19e502b5fdadbd367ae4b6bb3fab850fddc (diff)
downloadruby-f6254f77f7a7c4d1f11180b3b382680868bd9ee4.tar.gz
Speed up calling iseq bmethods
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 ```
Diffstat (limited to 'benchmark')
-rw-r--r--benchmark/vm_call_bmethod.yml37
1 files changed, 37 insertions, 0 deletions
diff --git a/benchmark/vm_call_bmethod.yml b/benchmark/vm_call_bmethod.yml
new file mode 100644
index 0000000000..40136e5aa4
--- /dev/null
+++ b/benchmark/vm_call_bmethod.yml
@@ -0,0 +1,37 @@
+prelude: |
+ define_method(:a0){}
+ define_method(:a1){|a| a}
+ define_method(:s){|*a| a}
+ define_method(:b){|kw: 1| kw}
+
+ t0 = 0.times.to_a
+ t1 = 1.times.to_a
+ t10 = 10.times.to_a
+ t100 = 100.times.to_a
+ kw = {kw: 2}
+benchmark:
+ bmethod_simple_0: |
+ a0
+ bmethod_simple_1: |
+ a1(1)
+ bmethod_simple_0_splat: |
+ a0(*t0)
+ bmethod_simple_1_splat: |
+ a1(*t1)
+ bmethod_no_splat: |
+ s
+ bmethod_0_splat: |
+ s(*t0)
+ bmethod_1_splat: |
+ s(*t1)
+ bmethod_10_splat: |
+ s(*t10)
+ bmethod_100_splat: |
+ s(*t100)
+ bmethod_kw: |
+ b(kw: 1)
+ bmethod_no_kw: |
+ b
+ bmethod_kw_splat: |
+ b(**kw)
+loop_count: 6000000