Project

General

Profile

Feature #11769

optimize case / when for `nil`

Added by tenderlovemaking (Aaron Patterson) almost 4 years ago. Updated almost 4 years ago.

Status:
Closed
Priority:
Normal
Target version:
-
[ruby-core:71818]

Description

Hi,

I've noticed that when there are certain values in a case / when statement it gets optimized to a hash lookup. For example, code like this:

def foo socket
  case str = socket.read_nonblock(10, exception: false)
  when :wait_readable
    # do something
  else
    str
  end
end

puts RubyVM::InstructionSequence.of(method(:foo)).disasm

The above code will use opt_case_dispatch instruction with a hash. However, if I use nil in the case statement like this:

def foo socket
  case str = socket.read_nonblock(10, exception: false)
  when :wait_readable
    # do something
  when nil
    # got an EOF
  else
    str
  end
end

puts RubyVM::InstructionSequence.of(method(:foo)).disasm

Then the optimization is lost.

I've attached a patch that adds nil to the optimized case such that the above code will use opt_case_dispatch. My patch defines === on nil, then adds nil to the list of "optimizable literals".


Files

0001-optimize-case-when-for-nil.patch (3.4 KB) 0001-optimize-case-when-for-nil.patch tenderlovemaking (Aaron Patterson), 12/03/2015 09:42 PM

Associated revisions

Revision 4ebab10b
Added by normal almost 4 years ago

compile optimized case dispatch for nil/true/false

nil/true/false are special literals just like floats, integers,
literal strings, and symbols. Optimize when statements with
them by using a jump table, too.

target 0: a (ruby 2.3.0dev (2015-12-08 trunk 52928) [x86_64-linux]) at "/home/ew/rrrr/b/ruby"
target 1: b (ruby 2.3.0dev (2015-12-08 master 52928) [x86_64-linux]) at "/home/ew/ruby/b/ruby"

benchmark results:
minimum results in each 5 measurements.
Execution time (sec)
name a b
loop_whileloop2 0.102 0.103
vm2_case_lit* 1.657 0.549

Speedup ratio: compare with the result of `a' (greater is better)
name b
loop_whileloop2 0.988
vm2_case_lit* 3.017

  • benchmark/bm_vm2_case_lit.rb: new benchmark
  • compile.c (case_when_optimizable_literal): add nil/true/false
  • insns.def (opt_case_dispatch): ditto
  • vm.c (vm_redefinition_check_flag): ditto
  • vm.c (vm_init_redefined_flag): ditto
  • vm_core.h: ditto
  • object.c (InitVM_Object): define === explicitly for nil/true/false
  • test/ruby/test_case.rb (test_deoptimize_nil): new test
  • test/ruby/test_optimization.rb (test_opt_case_dispatch): update (test_eqq): new test [ruby-core:71923] [Feature #11769] Original patch by Aaron Patterson tenderlove@ruby-lang.org

git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@52931 b2dd03c8-39d4-4d8f-98ff-823fe69b080e

Revision 52931
Added by normalperson (Eric Wong) almost 4 years ago

compile optimized case dispatch for nil/true/false

nil/true/false are special literals just like floats, integers,
literal strings, and symbols. Optimize when statements with
them by using a jump table, too.

target 0: a (ruby 2.3.0dev (2015-12-08 trunk 52928) [x86_64-linux]) at "/home/ew/rrrr/b/ruby"
target 1: b (ruby 2.3.0dev (2015-12-08 master 52928) [x86_64-linux]) at "/home/ew/ruby/b/ruby"

benchmark results:
minimum results in each 5 measurements.
Execution time (sec)
name a b
loop_whileloop2 0.102 0.103
vm2_case_lit* 1.657 0.549

Speedup ratio: compare with the result of `a' (greater is better)
name b
loop_whileloop2 0.988
vm2_case_lit* 3.017

  • benchmark/bm_vm2_case_lit.rb: new benchmark
  • compile.c (case_when_optimizable_literal): add nil/true/false
  • insns.def (opt_case_dispatch): ditto
  • vm.c (vm_redefinition_check_flag): ditto
  • vm.c (vm_init_redefined_flag): ditto
  • vm_core.h: ditto
  • object.c (InitVM_Object): define === explicitly for nil/true/false
  • test/ruby/test_case.rb (test_deoptimize_nil): new test
  • test/ruby/test_optimization.rb (test_opt_case_dispatch): update (test_eqq): new test [ruby-core:71923] [Feature #11769] Original patch by Aaron Patterson tenderlove@ruby-lang.org

Revision 52931
Added by normal almost 4 years ago

compile optimized case dispatch for nil/true/false

nil/true/false are special literals just like floats, integers,
literal strings, and symbols. Optimize when statements with
them by using a jump table, too.

target 0: a (ruby 2.3.0dev (2015-12-08 trunk 52928) [x86_64-linux]) at "/home/ew/rrrr/b/ruby"
target 1: b (ruby 2.3.0dev (2015-12-08 master 52928) [x86_64-linux]) at "/home/ew/ruby/b/ruby"

benchmark results:
minimum results in each 5 measurements.
Execution time (sec)
name a b
loop_whileloop2 0.102 0.103
vm2_case_lit* 1.657 0.549

Speedup ratio: compare with the result of `a' (greater is better)
name b
loop_whileloop2 0.988
vm2_case_lit* 3.017

  • benchmark/bm_vm2_case_lit.rb: new benchmark
  • compile.c (case_when_optimizable_literal): add nil/true/false
  • insns.def (opt_case_dispatch): ditto
  • vm.c (vm_redefinition_check_flag): ditto
  • vm.c (vm_init_redefined_flag): ditto
  • vm_core.h: ditto
  • object.c (InitVM_Object): define === explicitly for nil/true/false
  • test/ruby/test_case.rb (test_deoptimize_nil): new test
  • test/ruby/test_optimization.rb (test_opt_case_dispatch): update (test_eqq): new test [ruby-core:71923] [Feature #11769] Original patch by Aaron Patterson tenderlove@ruby-lang.org

Revision 52931
Added by normal almost 4 years ago

compile optimized case dispatch for nil/true/false

nil/true/false are special literals just like floats, integers,
literal strings, and symbols. Optimize when statements with
them by using a jump table, too.

target 0: a (ruby 2.3.0dev (2015-12-08 trunk 52928) [x86_64-linux]) at "/home/ew/rrrr/b/ruby"
target 1: b (ruby 2.3.0dev (2015-12-08 master 52928) [x86_64-linux]) at "/home/ew/ruby/b/ruby"

benchmark results:
minimum results in each 5 measurements.
Execution time (sec)
name a b
loop_whileloop2 0.102 0.103
vm2_case_lit* 1.657 0.549

Speedup ratio: compare with the result of `a' (greater is better)
name b
loop_whileloop2 0.988
vm2_case_lit* 3.017

  • benchmark/bm_vm2_case_lit.rb: new benchmark
  • compile.c (case_when_optimizable_literal): add nil/true/false
  • insns.def (opt_case_dispatch): ditto
  • vm.c (vm_redefinition_check_flag): ditto
  • vm.c (vm_init_redefined_flag): ditto
  • vm_core.h: ditto
  • object.c (InitVM_Object): define === explicitly for nil/true/false
  • test/ruby/test_case.rb (test_deoptimize_nil): new test
  • test/ruby/test_optimization.rb (test_opt_case_dispatch): update (test_eqq): new test [ruby-core:71923] [Feature #11769] Original patch by Aaron Patterson tenderlove@ruby-lang.org

Revision 52931
Added by normal almost 4 years ago

compile optimized case dispatch for nil/true/false

nil/true/false are special literals just like floats, integers,
literal strings, and symbols. Optimize when statements with
them by using a jump table, too.

target 0: a (ruby 2.3.0dev (2015-12-08 trunk 52928) [x86_64-linux]) at "/home/ew/rrrr/b/ruby"
target 1: b (ruby 2.3.0dev (2015-12-08 master 52928) [x86_64-linux]) at "/home/ew/ruby/b/ruby"

benchmark results:
minimum results in each 5 measurements.
Execution time (sec)
name a b
loop_whileloop2 0.102 0.103
vm2_case_lit* 1.657 0.549

Speedup ratio: compare with the result of `a' (greater is better)
name b
loop_whileloop2 0.988
vm2_case_lit* 3.017

  • benchmark/bm_vm2_case_lit.rb: new benchmark
  • compile.c (case_when_optimizable_literal): add nil/true/false
  • insns.def (opt_case_dispatch): ditto
  • vm.c (vm_redefinition_check_flag): ditto
  • vm.c (vm_init_redefined_flag): ditto
  • vm_core.h: ditto
  • object.c (InitVM_Object): define === explicitly for nil/true/false
  • test/ruby/test_case.rb (test_deoptimize_nil): new test
  • test/ruby/test_optimization.rb (test_opt_case_dispatch): update (test_eqq): new test [ruby-core:71923] [Feature #11769] Original patch by Aaron Patterson tenderlove@ruby-lang.org

Revision 52931
Added by normal almost 4 years ago

compile optimized case dispatch for nil/true/false

nil/true/false are special literals just like floats, integers,
literal strings, and symbols. Optimize when statements with
them by using a jump table, too.

target 0: a (ruby 2.3.0dev (2015-12-08 trunk 52928) [x86_64-linux]) at "/home/ew/rrrr/b/ruby"
target 1: b (ruby 2.3.0dev (2015-12-08 master 52928) [x86_64-linux]) at "/home/ew/ruby/b/ruby"

benchmark results:
minimum results in each 5 measurements.
Execution time (sec)
name a b
loop_whileloop2 0.102 0.103
vm2_case_lit* 1.657 0.549

Speedup ratio: compare with the result of `a' (greater is better)
name b
loop_whileloop2 0.988
vm2_case_lit* 3.017

  • benchmark/bm_vm2_case_lit.rb: new benchmark
  • compile.c (case_when_optimizable_literal): add nil/true/false
  • insns.def (opt_case_dispatch): ditto
  • vm.c (vm_redefinition_check_flag): ditto
  • vm.c (vm_init_redefined_flag): ditto
  • vm_core.h: ditto
  • object.c (InitVM_Object): define === explicitly for nil/true/false
  • test/ruby/test_case.rb (test_deoptimize_nil): new test
  • test/ruby/test_optimization.rb (test_opt_case_dispatch): update (test_eqq): new test [ruby-core:71923] [Feature #11769] Original patch by Aaron Patterson tenderlove@ruby-lang.org

History

Updated by normalperson (Eric Wong) almost 4 years ago

tenderlove@ruby-lang.org wrote:

I've attached a patch that adds nil to the optimized case such that
the above code will use opt_case_dispatch. My patch defines ===
on nil, then adds nil to the list of "optimizable literals".

Cool. Might be worth it to do the same for true and false,
too, since we have space for them.

Updated by ko1 (Koichi Sasada) almost 4 years ago

  • Assignee set to ko1 (Koichi Sasada)

Updated by normalperson (Eric Wong) almost 4 years ago

Eric Wong normalperson@yhbt.net wrote:

Cool. Might be worth it to do the same for true and false,
too, since we have space for them.

Sythetic benchmark shows a 3x speedup on top of r52928:

http://80x24.org/spew/20151208001623.2666-1-e@80x24.org/raw

#4

Updated by Anonymous almost 4 years ago

  • Status changed from Open to Closed

Applied in changeset r52931.


compile optimized case dispatch for nil/true/false

nil/true/false are special literals just like floats, integers,
literal strings, and symbols. Optimize when statements with
them by using a jump table, too.

target 0: a (ruby 2.3.0dev (2015-12-08 trunk 52928) [x86_64-linux]) at "/home/ew/rrrr/b/ruby"
target 1: b (ruby 2.3.0dev (2015-12-08 master 52928) [x86_64-linux]) at "/home/ew/ruby/b/ruby"

benchmark results:
minimum results in each 5 measurements.
Execution time (sec)
name a b
loop_whileloop2 0.102 0.103
vm2_case_lit* 1.657 0.549

Speedup ratio: compare with the result of `a' (greater is better)
name b
loop_whileloop2 0.988
vm2_case_lit* 3.017

  • benchmark/bm_vm2_case_lit.rb: new benchmark
  • compile.c (case_when_optimizable_literal): add nil/true/false
  • insns.def (opt_case_dispatch): ditto
  • vm.c (vm_redefinition_check_flag): ditto
  • vm.c (vm_init_redefined_flag): ditto
  • vm_core.h: ditto
  • object.c (InitVM_Object): define === explicitly for nil/true/false
  • test/ruby/test_case.rb (test_deoptimize_nil): new test
  • test/ruby/test_optimization.rb (test_opt_case_dispatch): update (test_eqq): new test [ruby-core:71923] [Feature #11769] Original patch by Aaron Patterson tenderlove@ruby-lang.org

Also available in: Atom PDF