ruby-changes:66350
From: Alan <ko1@a...>
Date: Sat, 29 May 2021 01:34:32 +0900 (JST)
Subject: [ruby-changes:66350] 5ada23ac12 (master): compile.c: Emit send for === calls in when statements
https://git.ruby-lang.org/ruby.git/commit/?id=5ada23ac12 From 5ada23ac1265a1da5d7ef82e1c71f14c40dddc26 Mon Sep 17 00:00:00 2001 From: Alan Wu <XrXr@u...> Date: Wed, 26 May 2021 11:50:37 -0400 Subject: compile.c: Emit send for === calls in when statements The checkmatch instruction with VM_CHECKMATCH_TYPE_CASE calls === without a call cache. Emit a send instruction to make the call instead. It includes a call cache. The call cache improves throughput of using when statements to check the class of a given object. This is useful for say, JSON serialization. Use of a regular send instead of checkmatch also avoids taking the VM lock every time, which is good for multi-ractor workloads. Calculating ------------------------------------- master post vm_case_classes 11.013M 16.172M i/s - 6.000M times in 0.544795s 0.371009s vm_case_lit 2.296 2.263 i/s - 1.000 times in 0.435606s 0.441826s vm_case 74.098M 64.338M i/s - 6.000M times in 0.080974s 0.093257s Comparison: vm_case_classes post: 16172114.4 i/s master: 11013316.9 i/s - 1.47x slower vm_case_lit master: 2.3 i/s post: 2.3 i/s - 1.01x slower vm_case master: 74097858.6 i/s post: 64338333.9 i/s - 1.15x slower The vm_case benchmark is a bit slower post patch, possibily due to the larger instruction sequence. The benchmark dispatches using opt_case_dispatch so was not running checkmatch and does not make the === call post patch. --- benchmark/vm_case_classes.yml | 9 +++++++++ compile.c | 6 +++--- test/ruby/test_jit.rb | 2 +- 3 files changed, 13 insertions(+), 4 deletions(-) create mode 100644 benchmark/vm_case_classes.yml diff --git a/benchmark/vm_case_classes.yml b/benchmark/vm_case_classes.yml new file mode 100644 index 0000000..cacc4f0 --- /dev/null +++ b/benchmark/vm_case_classes.yml @@ -0,0 +1,9 @@ https://github.com/ruby/ruby/blob/trunk/benchmark/vm_case_classes.yml#L1 +benchmark: + vm_case_classes: | + case :foo + when Hash + raise + when Array + raise + end +loop_count: 6000000 diff --git a/compile.c b/compile.c index e8d5d05..b03e815 100644 --- a/compile.c +++ b/compile.c @@ -4572,8 +4572,6 @@ when_vals(rb_iseq_t *iseq, LINK_ANCHOR *const cond_seq, const NODE *vals, https://github.com/ruby/ruby/blob/trunk/compile.c#L4572 rb_hash_aset(literals, lit, (VALUE)(l1) | 1); } - ADD_INSN(cond_seq, val, dup); /* dup target */ - if (nd_type(val) == NODE_STR) { debugp_param("nd_lit", val->nd_lit); lit = rb_fstring(val->nd_lit); @@ -4584,7 +4582,9 @@ when_vals(rb_iseq_t *iseq, LINK_ANCHOR *const cond_seq, const NODE *vals, https://github.com/ruby/ruby/blob/trunk/compile.c#L4582 if (!COMPILE(cond_seq, "when cond", val)) return -1; } - ADD_INSN1(cond_seq, vals, checkmatch, INT2FIX(VM_CHECKMATCH_TYPE_CASE)); + // Emit patern === target + ADD_INSN1(cond_seq, vals, topn, INT2FIX(1)); + ADD_CALL(cond_seq, vals, idEqq, INT2FIX(1)); ADD_INSNL(cond_seq, val, branchif, l1); vals = vals->nd_next; } diff --git a/test/ruby/test_jit.rb b/test/ruby/test_jit.rb index 55922b2..5b79f8c 100644 --- a/test/ruby/test_jit.rb +++ b/test/ruby/test_jit.rb @@ -497,7 +497,7 @@ class TestJIT < Test::Unit::TestCase https://github.com/ruby/ruby/blob/trunk/test/ruby/test_jit.rb#L497 end def test_compile_insn_checkmatch_opt_case_dispatch - assert_compile_once("#{<<~"begin;"}\n#{<<~"end;"}", result_inspect: '"world"', insns: %i[checkmatch opt_case_dispatch]) + assert_compile_once("#{<<~"begin;"}\n#{<<~"end;"}", result_inspect: '"world"', insns: %i[opt_case_dispatch]) begin; case 'hello' when 'hello' -- cgit v1.1 -- ML: ruby-changes@q... Info: http://www.atdot.net/~ko1/quickml/