From: ko1@... Date: 2018-12-20T00:52:30+00:00 Subject: [ruby-dev:50720] [Ruby trunk Feature#15435] Float の Infinity に生成済みの値を使用する Issue #15435 has been updated by ko1 (Koichi Sasada). # コードのご提案時には、アイディア(アルゴリズム)を書いて頂けるとありがたいです。 パッチを見たところ、Flonum 生成時に、範囲外で heap から生成する直前に `isinf()` でチェックして、inf であれば、事前に allocate した inf オブジェクトを返す、と理解しました。 ```C if (isinf(d)) { return d < 0 ? rb_float_negative_infinity : rb_float_positive_infinity; } ``` というわけで、`isinf(d)` が入るのを許容できるか、という議論になるんじゃないかと思います。 で、このパスでは heap allocate が入るので、`isinf(d)` check の負荷は問題にならなそうだから、いいような気がします。 でも、ベンチマークで 2% 負荷が増えてるんですね、意外と大きいのかな...。heap にはほとんど落ちないと思っているんですが、heap に落ちる率がわかると、もうちょっと勢いよく、行きましょう! って言えそうです。アプリをお持ちだったりしますか? 以下、その他のコメントです。 > rb_global_variable(&rb_float_negative_infinity); > rb_float_negative_infinity = rb_float_new_in_heap(-HUGE_VAL); (1) `rb_global_variable` よりも、`rb_gc_register_mark_object` でオブジェクト自体を登録したほうが良いです。 (2) Infinity じゃなくて、いっそ NegativeInfinity という定数も用意してしまったらどうだろう。 benchmark-driver でループ回数指定じゃないモードの方が、この場合良さそうです(どうやるのかよく覚えてない)。 ---------------------------------------- Feature #15435: Float の Infinity に生成済みの値を使用する https://bugs.ruby-lang.org/issues/15435#change-75787 * Author: shuujii (Shuji KOBAYASHI) * Status: Open * Priority: Normal * Assignee: * Target version: ---------------------------------------- Float の Infinity はしばしば使われると思うのですが、Flonum が有効でも即値に ならないので、演算の結果や C から DBL2NUM で返却される場合などに毎回オブ ジェクトが生成されます。 Ruby リポジトリーで、Infinity オブジェクトが生成されると明確に分かる場所を簡 単に調べた限りでは20数箇所ありました。 ~~~ $ grep 'DBL2NUM.*HUGE_VAL' $(git ls-files | awk '/\.c$/ && !/^(spec|ext\/-test-)\//') | wc -l 21 $ egrep -- '-Float::INFINITY' $(git ls-files | egrep '^(lib|ext)/.*\.rb$') | wc -l 2 ~~~ それで、Infinity の場合は生成済みのオブジェクトを返すようにしてはどうでしょ うか。 パッチを添付します。添付のベンチマークを benchmark-driver で実行した限りでは、 演算結果が Infinity になる場合は性能が向上し、そうでない場合は有意な差はない (計測の度にかなりばらつきがあるが概ね10%以内の差におさまる) ようでした。 ~~~ Calculating ------------------------------------- compare-ruby built-ruby positive_infinity 34.531M 62.540M i/s - 3.000M times in 0.195822s 0.107997s negative_infinity 42.581M 94.234M i/s - 3.000M times in 0.159061s 0.071766s flonum 142.010M 150.967M i/s - 3.000M times in 0.047544s 0.045120s heap 33.952M 34.629M i/s - 3.000M times in 0.199321s 0.195063s Comparison: positive_infinity built-ruby: 62540441.7 i/s compare-ruby: 34530877.6 i/s - 1.81x slower negative_infinity built-ruby: 94234135.1 i/s compare-ruby: 42580998.6 i/s - 2.21x slower flonum built-ruby: 150967185.7 i/s compare-ruby: 142010146.8 i/s - 1.06x slower heap built-ruby: 34629459.1 i/s compare-ruby: 33952081.8 i/s - 1.02x slower ~~~ ---Files-------------------------------- use-predefined-infinity.patch (8.97 KB) benchmark.yml (192 Bytes) -- https://bugs.ruby-lang.org/