From b08dacfea39ad8da3f1fd7fdd0e4538cc892ec44 Mon Sep 17 00:00:00 2001 From: Jeremy Evans Date: Thu, 18 Nov 2021 15:10:20 -0800 Subject: Optimize dynamic string interpolation for symbol/true/false/nil/0-9 This provides a significant speedup for symbol, true, false, nil, and 0-9, class/module, and a small speedup in most other cases. Speedups (using included benchmarks): :symbol :: 60% 0-9 :: 50% Class/Module :: 50% nil/true/false :: 20% integer :: 10% [] :: 10% "" :: 3% One reason this approach is faster is it reduces the number of VM instructions for each interpolated value. Initial idea, approach, and benchmarks from Eric Wong. I applied the same approach against the master branch, updating it to handle the significant internal changes since this was first proposed 4 years ago (such as CALL_INFO/CALL_CACHE -> CALL_DATA). I also expanded it to optimize true/false/nil/0-9/class/module, and added handling of missing methods, refined methods, and RUBY_DEBUG. This renames the tostring insn to anytostring, and adds an objtostring insn that implements the optimization. This requires making a few functions non-static, and adding some non-static functions. This disables 4 YJIT tests. Those tests should be reenabled after YJIT optimizes the new objtostring insn. Implements [Feature #13715] Co-authored-by: Eric Wong Co-authored-by: Alan Wu Co-authored-by: Yusuke Endoh Co-authored-by: Koichi Sasada --- benchmark/vm_dstr_ary.rb | 6 ++++++ benchmark/vm_dstr_bool.rb | 7 +++++++ benchmark/vm_dstr_class_module.rb | 10 ++++++++++ benchmark/vm_dstr_digit.rb | 7 +++++++ benchmark/vm_dstr_int.rb | 5 +++++ benchmark/vm_dstr_nil.rb | 6 ++++++ benchmark/vm_dstr_obj.rb | 6 ++++++ benchmark/vm_dstr_obj_def.rb | 8 ++++++++ benchmark/vm_dstr_str.rb | 6 ++++++ benchmark/vm_dstr_sym.rb | 6 ++++++ 10 files changed, 67 insertions(+) create mode 100644 benchmark/vm_dstr_ary.rb create mode 100644 benchmark/vm_dstr_bool.rb create mode 100644 benchmark/vm_dstr_class_module.rb create mode 100644 benchmark/vm_dstr_digit.rb create mode 100644 benchmark/vm_dstr_int.rb create mode 100644 benchmark/vm_dstr_nil.rb create mode 100644 benchmark/vm_dstr_obj.rb create mode 100644 benchmark/vm_dstr_obj_def.rb create mode 100644 benchmark/vm_dstr_str.rb create mode 100644 benchmark/vm_dstr_sym.rb (limited to 'benchmark') diff --git a/benchmark/vm_dstr_ary.rb b/benchmark/vm_dstr_ary.rb new file mode 100644 index 0000000000..1d3aa3b97b --- /dev/null +++ b/benchmark/vm_dstr_ary.rb @@ -0,0 +1,6 @@ +i = 0 +x = y = [] +while i<6_000_000 # benchmark loop 2 + i += 1 + str = "foo#{x}bar#{y}baz" +end diff --git a/benchmark/vm_dstr_bool.rb b/benchmark/vm_dstr_bool.rb new file mode 100644 index 0000000000..631ca54755 --- /dev/null +++ b/benchmark/vm_dstr_bool.rb @@ -0,0 +1,7 @@ +i = 0 +x = true +y = false +while i<6_000_000 # benchmark loop 2 + i += 1 + str = "foo#{x}bar#{y}baz" +end diff --git a/benchmark/vm_dstr_class_module.rb b/benchmark/vm_dstr_class_module.rb new file mode 100644 index 0000000000..becf0861c7 --- /dev/null +++ b/benchmark/vm_dstr_class_module.rb @@ -0,0 +1,10 @@ +i = 0 +class A; end unless defined?(A) +module B; end unless defined?(B) +x = A +y = B +while i<6_000_000 # benchmark loop 2 + i += 1 + str = "foo#{x}bar#{y}baz" +end + diff --git a/benchmark/vm_dstr_digit.rb b/benchmark/vm_dstr_digit.rb new file mode 100644 index 0000000000..caaa395192 --- /dev/null +++ b/benchmark/vm_dstr_digit.rb @@ -0,0 +1,7 @@ +i = 0 +x = 0 +y = 9 +while i<6_000_000 # benchmark loop 2 + i += 1 + str = "foo#{x}bar#{y}baz" +end diff --git a/benchmark/vm_dstr_int.rb b/benchmark/vm_dstr_int.rb new file mode 100644 index 0000000000..ed380d7595 --- /dev/null +++ b/benchmark/vm_dstr_int.rb @@ -0,0 +1,5 @@ +i = 0 +while i<6_000_000 # benchmark loop 2 + i += 1 + str = "foo#{i}bar#{i}baz" +end diff --git a/benchmark/vm_dstr_nil.rb b/benchmark/vm_dstr_nil.rb new file mode 100644 index 0000000000..ec4f5d6c67 --- /dev/null +++ b/benchmark/vm_dstr_nil.rb @@ -0,0 +1,6 @@ +i = 0 +x = y = nil +while i<6_000_000 # benchmark loop 2 + i += 1 + str = "foo#{x}bar#{y}baz" +end diff --git a/benchmark/vm_dstr_obj.rb b/benchmark/vm_dstr_obj.rb new file mode 100644 index 0000000000..fb78637ead --- /dev/null +++ b/benchmark/vm_dstr_obj.rb @@ -0,0 +1,6 @@ +i = 0 +x = y = Object.new +while i<6_000_000 # benchmark loop 2 + i += 1 + str = "foo#{x}bar#{y}baz" +end diff --git a/benchmark/vm_dstr_obj_def.rb b/benchmark/vm_dstr_obj_def.rb new file mode 100644 index 0000000000..99ff7b98fb --- /dev/null +++ b/benchmark/vm_dstr_obj_def.rb @@ -0,0 +1,8 @@ +i = 0 +o = Object.new +def o.to_s; -""; end +x = y = o +while i<6_000_000 # benchmark loop 2 + i += 1 + str = "foo#{x}bar#{y}baz" +end diff --git a/benchmark/vm_dstr_str.rb b/benchmark/vm_dstr_str.rb new file mode 100644 index 0000000000..45fc107892 --- /dev/null +++ b/benchmark/vm_dstr_str.rb @@ -0,0 +1,6 @@ +i = 0 +x = y = "" +while i<6_000_000 # benchmark loop 2 + i += 1 + str = "foo#{x}bar#{y}baz" +end diff --git a/benchmark/vm_dstr_sym.rb b/benchmark/vm_dstr_sym.rb new file mode 100644 index 0000000000..484b8f8150 --- /dev/null +++ b/benchmark/vm_dstr_sym.rb @@ -0,0 +1,6 @@ +i = 0 +x = y = :z +while i<6_000_000 # benchmark loop 2 + i += 1 + str = "foo#{x}bar#{y}baz" +end -- cgit v1.2.3