ruby-changes:54639
From: naruse <ko1@a...>
Date: Fri, 18 Jan 2019 08:08:16 +0900 (JST)
Subject: [ruby-changes:54639] naruse:r66854 (ruby_2_6): merge revision(s) 66681, 66682, 66684, 66688, 66697, 66751, 66693, 66694: [Backport #15491]
naruse 2019-01-18 08:08:10 +0900 (Fri, 18 Jan 2019) New Revision: 66854 https://svn.ruby-lang.org/cgi-bin/viewvc.cgi?view=revision&revision=66854 Log: merge revision(s) 66681,66682,66684,66688,66697,66751,66693,66694: [Backport #15491] complex.c: Optimize Complex#+ for some conditions Optimize f_add defined in complex.c for some specific conditions. It makes Complex#+ about 1.4x faster than r66678. Compared to r66678: ``` mrkn-mbp15-late2016:complex-optim-o3 mrkn$ make benchmark ITEM=complex_float_ COMPARE_RUBY=/Users/mrkn/.rbenv/versions/trunk-o3/bin/ruby /Users/mrkn/src/github.com/ruby/ruby/revision.h unchanged /Users/mrkn/.rbenv/shims/ruby --disable=gems -rrubygems -I/Users/mrkn/src/github.com/ruby/ruby/benchmark/lib /Users/mrkn/src/github.com/ruby/ruby/benchmark/benchmark-driver/exe/benchmark-driver \ --executables="compare-ruby::/Users/mrkn/.rbenv/versions/trunk-o3/bin/ruby -I.ext/common --disable-gem" \ --executables="built-ruby::./miniruby -I/Users/mrkn/src/github.com/ruby/ruby/lib -I. -I.ext/common -r/Users/mrkn/src/github.com/ruby/ruby/prelude --disable-gem" \ $(find /Users/mrkn/src/github.com/ruby/ruby/benchmark -maxdepth 1 -name '*complex_float_*.yml' -o -name '*complex_float_*.rb' | sort) Calculating ------------------------------------- compare-ruby built-ruby complex_float_add 9.132M 12.864M i/s - 1.000M times in 0.109511s 0.077734s complex_float_div 600.723k 627.878k i/s - 1.000M times in 1.664662s 1.592666s complex_float_mul 2.320M 2.347M i/s - 1.000M times in 0.431039s 0.426113s complex_float_new 1.473M 1.489M i/s - 1.000M times in 0.678791s 0.671750s complex_float_power 1.690M 1.722M i/s - 1.000M times in 0.591863s 0.580775s complex_float_sub 8.870M 9.516M i/s - 1.000M times in 0.112740s 0.105091s Comparison: complex_float_add built-ruby: 12864383.7 i/s compare-ruby: 9131502.8 i/s - 1.41x slower complex_float_div built-ruby: 627878.0 i/s compare-ruby: 600722.5 i/s - 1.05x slower complex_float_mul built-ruby: 2346795.3 i/s compare-ruby: 2319975.7 i/s - 1.01x slower complex_float_new built-ruby: 1488649.1 i/s compare-ruby: 1473207.5 i/s - 1.01x slower complex_float_power built-ruby: 1721837.2 i/s compare-ruby: 1689580.2 i/s - 1.02x slower complex_float_sub built-ruby: 9515562.7 i/s compare-ruby: 8869966.3 i/s - 1.07x slower ``` suppress warning: method redefined; discarding old + introduced at r66681 complex.c: fix indentation complex.c: fix against redefining component methods This fixes the incompatibility (maybe unintentionally) introduced by removal of `#ifndef PRESERVE_SIGNEDZERO` guards in f_add, f_mul, and f_sub functions in r62701. [Bug #15491] [ruby-core:90843] complex.c: Optimize Complex#* and Complex#** Optimize f_mul for the core numeric class components. This change improves the computation time of Complex#* and Complex#**. ``` $ make benchmark ITEM=complex_float_ COMPARE_RUBY=/Users/mrkn/.rbenv/versions/2.6.0/bin/ruby generating known_errors.inc known_errors.inc unchanged /Users/mrkn/src/github.com/ruby/ruby/revision.h unchanged /Users/mrkn/.rbenv/shims/ruby --disable=gems -rrubygems -I/Users/mrkn/src/github.com/ruby/ruby/benchmark/lib /Users/mrkn/src/github.com/ruby/ruby/benchmark/benchmark-driver/exe/benchmark-driver \ --executables="compare-ruby::/Users/mrkn/.rbenv/versions/2.6.0/bin/ruby -I.ext/common --disable-gem" \ --executables="built-ruby::./miniruby -I/Users/mrkn/src/github.com/ruby/ruby/lib -I. -I.ext/common -r/Users/mrkn/src/github.com/ruby/ruby/prelude --disable-gem" \ $(find /Users/mrkn/src/github.com/ruby/ruby/benchmark -maxdepth 1 -name '*complex_float_*.yml' -o -name '*complex_float_*.rb' | sort) Calculating ------------------------------------- compare-ruby built-ruby complex_float_add 6.558M 13.012M i/s - 1.000M times in 0.152480s 0.076850s complex_float_div 576.821k 567.969k i/s - 1.000M times in 1.733640s 1.760660s complex_float_mul 1.690M 2.628M i/s - 1.000M times in 0.591786s 0.380579s complex_float_new 1.350M 1.268M i/s - 1.000M times in 0.740669s 0.788762s complex_float_power 1.571M 1.835M i/s - 1.000M times in 0.636507s 0.544909s complex_float_sub 8.635M 8.779M i/s - 1.000M times in 0.115814s 0.113906s Comparison: complex_float_add built-ruby: 13012361.7 i/s compare-ruby: 6558237.1 i/s - 1.98x slower complex_float_div compare-ruby: 576821.0 i/s built-ruby: 567968.8 i/s - 1.02x slower complex_float_mul built-ruby: 2627575.4 i/s compare-ruby: 1689800.0 i/s - 1.55x slower complex_float_new compare-ruby: 1350130.8 i/s built-ruby: 1267809.6 i/s - 1.06x slower complex_float_power built-ruby: 1835168.8 i/s compare-ruby: 1571074.6 i/s - 1.17x slower complex_float_sub built-ruby: 8779168.8 i/s compare-ruby: 8634534.7 i/s - 1.02x slower ``` complex.c: replace misused UNLIKELY with LIKELY test_complex.rb: fix tests for RUBYOPT="-w" test_complex.rb: use the same approach to fix failures as r66682. Modified directories: branches/ruby_2_6/ Modified files: branches/ruby_2_6/complex.c branches/ruby_2_6/internal.h branches/ruby_2_6/numeric.c branches/ruby_2_6/rational.c branches/ruby_2_6/test/ruby/test_complex.rb branches/ruby_2_6/version.h Index: ruby_2_6/complex.c =================================================================== --- ruby_2_6/complex.c (revision 66853) +++ ruby_2_6/complex.c (revision 66854) @@ -71,10 +71,27 @@ f_##n(VALUE x, VALUE y)\ https://github.com/ruby/ruby/blob/trunk/ruby_2_6/complex.c#L71 inline static VALUE f_add(VALUE x, VALUE y) { - if (FIXNUM_ZERO_P(y)) - return x; - if (FIXNUM_ZERO_P(x)) - return y; + if (RB_INTEGER_TYPE_P(x) && + LIKELY(rb_method_basic_definition_p(rb_cInteger, idPLUS))) { + if (FIXNUM_ZERO_P(x)) + return y; + if (FIXNUM_ZERO_P(y)) + return x; + return rb_int_plus(x, y); + } + else if (RB_FLOAT_TYPE_P(x) && + LIKELY(rb_method_basic_definition_p(rb_cFloat, idPLUS))) { + if (FIXNUM_ZERO_P(y)) + return x; + return rb_float_plus(x, y); + } + else if (RB_TYPE_P(x, T_RATIONAL) && + LIKELY(rb_method_basic_definition_p(rb_cRational, idPLUS))) { + if (FIXNUM_ZERO_P(y)) + return x; + return rb_rational_plus(x, y); + } + return rb_funcall(x, '+', 1, y); } @@ -106,20 +123,39 @@ f_gt_p(VALUE x, VALUE y) https://github.com/ruby/ruby/blob/trunk/ruby_2_6/complex.c#L123 inline static VALUE f_mul(VALUE x, VALUE y) { - if (FIXNUM_ZERO_P(y) && RB_INTEGER_TYPE_P(x)) - return ZERO; - if (FIXNUM_ZERO_P(x) && RB_INTEGER_TYPE_P(y)) - return ZERO; - if (y == ONE) return x; - if (x == ONE) return y; + if (RB_INTEGER_TYPE_P(x) && + LIKELY(rb_method_basic_definition_p(rb_cInteger, idMULT))) { + if (FIXNUM_ZERO_P(y)) + return ZERO; + if (FIXNUM_ZERO_P(x) && RB_INTEGER_TYPE_P(y)) + return ZERO; + if (x == ONE) return y; + if (y == ONE) return x; + return rb_int_mul(x, y); + } + else if (RB_FLOAT_TYPE_P(x) && + LIKELY(rb_method_basic_definition_p(rb_cFloat, idMULT))) { + if (y == ONE) return x; + return rb_float_mul(x, y); + } + else if (RB_TYPE_P(x, T_RATIONAL) && + LIKELY(rb_method_basic_definition_p(rb_cRational, idMULT))) { + if (y == ONE) return x; + return rb_rational_mul(x, y); + } + else if (LIKELY(rb_method_basic_definition_p(CLASS_OF(x), idMULT))) { + if (y == ONE) return x; + } return rb_funcall(x, '*', 1, y); } inline static VALUE f_sub(VALUE x, VALUE y) { - if (FIXNUM_ZERO_P(y)) + if (FIXNUM_ZERO_P(y) && + LIKELY(rb_method_basic_definition_p(CLASS_OF(x), idMINUS))) { return x; + } return rb_funcall(x, '-', 1, y); } Index: ruby_2_6/test/ruby/test_complex.rb =================================================================== --- ruby_2_6/test/ruby/test_complex.rb (revision 66853) +++ ruby_2_6/test/ruby/test_complex.rb (revision 66854) @@ -269,6 +269,39 @@ class Complex_Test < Test::Unit::TestCas https://github.com/ruby/ruby/blob/trunk/ruby_2_6/test/ruby/test_complex.rb#L269 assert_equal(Complex(Rational(5,3),Rational(2)), c + Rational(2,3)) end + def test_add_with_redefining_int_plus + assert_in_out_err([], <<-'end;', ['true'], []) + class Integer + remove_method :+ + def +(other); 42; end + end + a = Complex(1, 2) + Complex(0, 1) + puts a == Complex(42, 42) + end; + end + + def test_add_with_redefining_float_plus + assert_in_out_err([], <<-'end;', ['true'], []) + class Float + remove_method :+ + def +(other); 42.0; end + end + a = Complex(1.0, 2.0) + Complex(0, 1) + puts a == Complex(42.0, 42.0) + end; + end + + def test_add_with_redefining_rational_plus + assert_in_out_err([], <<-'end;', ['true'], []) + class Rational + remove_method :+ + def +(other); 355/113r; end + end + a = Complex(1r, 2r) + Complex(0, 1) + puts a == Complex(355/113r, 355/113r) + end; + end + def test_sub c = Complex(1,2) c2 = Complex(2,3) @@ -282,6 +315,39 @@ class Complex_Test < Test::Unit::TestCas https://github.com/ruby/ruby/blob/trunk/ruby_2_6/test/ruby/test_complex.rb#L315 assert_equal(Complex(Rational(1,3),Rational(2)), c - Rational(2,3)) end + def test_sub_with_redefining_int_minus + assert_in_out_err([], <<-'end;', ['true'], []) + class Integer + remove_method :- + def -(other); 42; end + end + a = Complex(1, 2) - Complex(0, 1) + puts a == Complex(42, 42) + end; + end + + def test_sub_with_redefining_float_minus + assert_in_out_err([], <<-'end;', ['true'], []) + class Float + remove_method :- + def -(other); 42.0; end + end + a = Complex(1.0, 2.0) - Complex(0, 1) + puts a == Complex(42.0, 42.0) + end; + end + + def test_sub_with_redefining_rational_minus + assert_in_out_err([], <<-'end;', ['true'], []) + class Rational + remove_method :- + def -(other); 355/113r; end + end + a = Complex(1r, 2r) - Complex(0, 1) + puts a == Complex(355/113r, 355/113r) + end; + end + def test_mul c = Complex(1,2) c2 = Complex(2,3) @@ -300,6 +366,42 @@ class Complex_Test < Test::Unit::TestCas https://github.com/ruby/ruby/blob/trunk/ruby_2_6/test/ruby/test_complex.rb#L366 c = Complex(0, Float::INFINITY) assert_equal(Complex(0, Float::INFINITY), c * Complex(1, 0)) assert_equal(Complex(-Float::INFINITY, 0), c * Complex(0, 1)) + + assert_equal(Complex(-0.0, -0.0), Complex(-0.0, 0) * Complex(0, 0)) + end + + def test_mul_with_redefining_int_mult + assert_in_out_err([], <<-'end;', ['true'], []) + class Integer + remove_method :* + def *(other); 42; end + end + a = Complex(2, 0) * Complex(1, 2) + puts a == Complex(0, 84) + end; + end + + def test_mul_with_redefining_float_mult + assert_in_out_err([], <<-'end;', ['true'], []) + class Float + remove_method :* + def *(other); 42.0; end + end + a = Complex(2.0, 0.0) * Complex(1, 2) + puts a == Complex(0.0, 84.0) + end; + end + + + def test_mul_with_redefining_rational_mult + assert_in_out_err([], <<-'end;', ['true'], []) + class Rational + remove_method :* + def *(other); 355/113r; end + end + a = Complex(2r, 0r) * Complex(1, 2) + puts a == Complex(0r, 2*355/113r) + end; end def test_div Index: ruby_2_6/internal.h =================================================================== --- ruby_2_6/internal.h (revision 66853) +++ ruby_2_6/internal.h (revision 66854) @@ -1677,8 +1677,10 @@ VALUE rb_int_pred(VALUE num); https://github.com/ruby/ruby/blob/trunk/ruby_2_6/internal.h#L1677 VALUE rb_int_uminus(VALUE num); VALUE rb_float_uminus(VALUE num); VALUE rb_int_plus(VALUE x, VALUE y); +VALUE rb_float_plus(VALUE x, VALUE y); VALUE rb_int_minus(VALUE x, VALUE y); VALUE rb_int_mul(VALUE x, VALUE y); +VALUE rb_float_mul(VALUE x, VALUE y); VALUE rb_int_idiv(VALUE x, VALUE y); VALUE rb_int_modulo(VALUE x, VALUE y); VALUE rb_int_round(VALUE num, int ndigits, enum ruby_num_rounding_mode mode); @@ -1970,6 +1972,7 @@ void rb_last_status_clear(void); https://github.com/ruby/ruby/blob/trunk/ruby_2_6/internal.h#L1972 VALUE rb_rational_canonicalize(VALUE x); VALUE rb_rational_uminus(VALUE self); VALUE rb_rational_plus(VALUE self, VALUE other); +VALUE rb_rational_mul(VALUE self, VALUE other); VALUE rb_lcm(VALUE x, VALUE y); VALUE rb_rational_reciprocal(VALUE x); VALUE rb_cstr_to_rat(const char *, int); Index: ruby_2_6/numeric.c =================================================================== --- ruby_2_6/numeric.c (revision 66853) +++ ruby_2_6/numeric.c (revision 66854) @@ -1018,8 +1018,8 @@ rb_float_uminus(VALUE flt) https://github.com/ruby/ruby/blob/trunk/ruby_2_6/numeric.c#L1018 * Returns a new Float which is the sum of +float+ and +other+. */ -static VALUE -flo_plus(VALUE x, VALUE y) +VALUE +rb_float_plus(VALUE x, VALUE y) { if (RB_TYPE_P(y, T_FIXNUM)) { return DBL2NUM(RFLOAT_VALUE(x) + (double)FIX2LONG(y)); @@ -1066,8 +1066,8 @@ flo_minus(VALUE x, VALUE y) https://github.com/ruby/ruby/blob/trunk/ruby_2_6/numeric.c#L1066 * Returns a new Float which is the product of +float+ and +other+. */ -static VALUE -flo_mul(VALUE x, VALUE y) +VALUE +rb_float_mul(VALUE x, VALUE y) { if (RB_TYPE_P(y, T_FIXNUM)) { return DBL2NUM(RFLOAT_VALUE(x) * (double)FIX2LONG(y)); @@ -5674,9 +5674,9 @@ Init_Numeric(void) https://github.com/ruby/ruby/blob/trunk/ruby_2_6/numeric.c#L5674 rb_define_alias(rb_cFloat, "inspect", "to_s"); rb_define_method(rb_cFloat, "coerce", flo_coerce, 1); rb_define_method(rb_cFloat, "-@", rb_float_uminus, 0); - rb_define_method(rb_cFloat, "+", flo_plus, 1); + rb_define_method(rb_cFloat, "+", rb_float_plus, 1); rb_define_method(rb_cFloat, "-", flo_minus, 1); - rb_define_method(rb_cFloat, "*", flo_mul, 1); + rb_define_method(rb_cFloat, "*", rb_float_mul, 1); rb_define_method(rb_cFloat, "/", flo_div, 1); rb_define_method(rb_cFloat, "quo", flo_quo, 1); rb_define_method(rb_cFloat, "fdiv", flo_quo, 1); Index: ruby_2_6/rational.c =================================================================== --- ruby_2_6/rational.c (revision 66853) +++ ruby_2_6/rational.c (revision 66854) @@ -877,8 +877,8 @@ f_muldiv(VALUE self, VALUE anum, VALUE a https://github.com/ruby/ruby/blob/trunk/ruby_2_6/rational.c#L877 * Rational(9, 8) * 4 #=> (9/2) * Rational(20, 9) * 9.8 #=> 21.77777777777778 */ -static VALUE -nurat_mul(VALUE self, VALUE other) +VALUE +rb_rational_mul(VALUE self, VALUE other) { if (RB_INTEGER_TYPE_P(other)) { { @@ -1396,7 +1396,7 @@ f_round_common(int argc, VALUE *argv, VA https://github.com/ruby/ruby/blob/trunk/ruby_2_6/rational.c#L1396 rb_raise(rb_eTypeError, "not an integer"); b = f_expt10(n); - s = nurat_mul(self, b); + s = rb_rational_mul(self, b); if (k_float_p(s)) { if (INT_NEGATIVE_P(n)) @@ -2734,7 +2734,7 @@ Init_Rational(void) https://github.com/ruby/ruby/blob/trunk/ruby_2_6/rational.c#L2734 rb_define_method(rb_cRational, "-@", rb_rational_uminus, 0); rb_define_method(rb_cRational, "+", rb_rational_plus, 1); rb_define_method(rb_cRational, "-", nurat_sub, 1); - rb_define_method(rb_cRational, "*", nurat_mul, 1); + rb_define_method(rb_cRational, "*", rb_rational_mul, 1); rb_define_method(rb_cRational, "/", nurat_div, 1); rb_define_method(rb_cRational, "quo", nurat_div, 1); rb_define_method(rb_cRational, "fdiv", nurat_fdiv, 1); Index: ruby_2_6/version.h =================================================================== --- ruby_2_6/version.h (revision 66853) +++ ruby_2_6/version.h (revision 66854) @@ -1,6 +1,6 @@ https://github.com/ruby/ruby/blob/trunk/ruby_2_6/version.h#L1 #define RUBY_VERSION "2.6.0" #define RUBY_RELEASE_DATE RUBY_RELEASE_YEAR_STR"-"RUBY_RELEASE_MONTH_STR"-"RUBY_RELEASE_DAY_STR -#define RUBY_PATCHLEVEL 22 +#define RUBY_PATCHLEVEL 23 #define RUBY_RELEASE_YEAR 2019 #define RUBY_RELEASE_MONTH 1 Index: ruby_2_6 =================================================================== --- ruby_2_6 (revision 66853) +++ ruby_2_6 (revision 66854) Property changes on: ruby_2_6 ___________________________________________________________________ Modified: svn:mergeinfo ## -0,0 +0,1 ## Merged /trunk:r66681-66682,66684,66688,66693-66694,66697,66751 -- ML: ruby-changes@q... Info: http://www.atdot.net/~ko1/quickml/