ruby-changes:54466
From: mrkn <ko1@a...>
Date: Tue, 1 Jan 2019 21:20:09 +0900 (JST)
Subject: [ruby-changes:54466] mrkn:r66681 (trunk): complex.c: Optimize Complex#+ for some conditions
mrkn 2019-01-01 21:20:05 +0900 (Tue, 01 Jan 2019) New Revision: 66681 https://svn.ruby-lang.org/cgi-bin/viewvc.cgi?view=revision&revision=66681 Log: 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 ``` Modified files: trunk/complex.c trunk/internal.h trunk/numeric.c trunk/test/ruby/test_complex.rb Index: complex.c =================================================================== --- complex.c (revision 66680) +++ complex.c (revision 66681) @@ -75,6 +75,20 @@ f_add(VALUE x, VALUE y) https://github.com/ruby/ruby/blob/trunk/complex.c#L75 return x; if (FIXNUM_ZERO_P(x)) return y; + + if (RB_INTEGER_TYPE_P(x) && + UNLIKELY(rb_method_basic_definition_p(rb_cInteger, idPLUS))) { + return rb_int_plus(x, y); + } + else if (RB_FLOAT_TYPE_P(x) && + UNLIKELY(rb_method_basic_definition_p(rb_cFloat, idPLUS))) { + return rb_float_plus(x, y); + } + else if (RB_TYPE_P(x, T_RATIONAL) && + UNLIKELY(rb_method_basic_definition_p(rb_cRational, idPLUS))) { + return rb_rational_plus(x, y); + } + return rb_funcall(x, '+', 1, y); } Index: internal.h =================================================================== --- internal.h (revision 66680) +++ internal.h (revision 66681) @@ -1655,6 +1655,7 @@ VALUE rb_int_pred(VALUE num); https://github.com/ruby/ruby/blob/trunk/internal.h#L1655 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_int_idiv(VALUE x, VALUE y); Index: numeric.c =================================================================== --- numeric.c (revision 66680) +++ numeric.c (revision 66681) @@ -1018,8 +1018,8 @@ rb_float_uminus(VALUE flt) https://github.com/ruby/ruby/blob/trunk/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)); @@ -5674,7 +5674,7 @@ Init_Numeric(void) https://github.com/ruby/ruby/blob/trunk/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, "/", flo_div, 1); Index: test/ruby/test_complex.rb =================================================================== --- test/ruby/test_complex.rb (revision 66680) +++ test/ruby/test_complex.rb (revision 66681) @@ -269,6 +269,36 @@ class Complex_Test < Test::Unit::TestCas https://github.com/ruby/ruby/blob/trunk/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 + def +(other); 42; end + end + a = Complex(1, 2) + Complex(0, 1) + puts a == Complex(1, 42) + end; + end + + def test_add_with_redefining_float_plus + assert_in_out_err([], <<-'end;', ['true'], []) + class Float + def +(other); 42.0; end + end + a = Complex(1, 2.0) + Complex(0, 1) + puts a == Complex(1, 42.0) + end; + end + + def test_add_with_redefining_rational_plus + assert_in_out_err([], <<-'end;', ['true'], []) + class Rational + def +(other); 355/113r; end + end + a = Complex(1, 2r) + Complex(0, 1) + puts a == Complex(1, 355/113r) + end; + end + def test_sub c = Complex(1,2) c2 = Complex(2,3) -- ML: ruby-changes@q... Info: http://www.atdot.net/~ko1/quickml/