From: Shin-ichiro HARA Date: 2002-10-30T16:11:49+09:00 Subject: [ruby-dev:18609] Re: new scope-in-state [Re: import-module (Re: Re: scope-in-state)] 原です。 >>import-module もアイデアのいただける所はいただいて、スピードアップ >>したいのですが、明日からしばらく南の島でコンピュータの無い生活を送 >>らなければならないのが残念です。(^^; お久しぶりです。南の島から戻りました。体はずいぶん前から戻ってますが、 頭の方も徐々に戻しています。 例の scope-in-state, import-module 問題の続きです。 In [ruby-dev:18082] >At 23:20 02/08/26 +0900, you wrote: >けいじゅ@日本ラショナルソフトウェアです. >>>multi thread(1000000 loops in a scope) : 11.0412 >>>scope in state(1000000 loops in a scope): 6.6583 新たに import-module Ver.0.74 別名、import-module turbo:-) というのを 作ってみました。結果は次の通り (ruby 1.6.7 (2002-07-11)[i386-cygwin] Windows2000): $ ./test times 10 m c L 1000000 scope-in-state (1000000 loops in a scope) : 4.7907 (1.0000) import-module (1000000 loops in a scope) : 5.0576 (1.0557) つまり、scope-in-state の 5% 以内に迫っています。この "loops in a scope" (以下 LOOPS と略)っていうのは、 Foo.import_module(Bar) do 1000000.times do o.foo end end こういう感じの計測でしたね。で、何が turbo かというと、こっちです。 $ ./test times 10 m c S 100000 import-module (scopes in 100000 loops) : 7.9654 (1.0000) scope-in-state (scopes in 100000 loops) : 11.2032 (1.4065) ここで、"scopes in loops"(以下 SCOPES と略)というのは、 100000.times do Foo.import_module(Bar) do o.foo end end でした。これって import-module の初期バージョンに対して 200 倍ぐらいの スピードになったんですよ。turbo でしょう。 中身ですが、scope-in-state を大分参考にしました(っていうか独立に作っ たつもりが、最終的にはそっくり)。scope-in-state は、実に細かいオプティ マイズがされてて、驚きました。私もプロファイラと睨めっこしたんですが、 どうしても速くならない。最終的にはやはり *arg の展開のところがネックだっ たと気づいたのですが、この展開の所は、標準の profile.rb では出力されま せんよね、、、 >で実体を呼び出していたのですが, プロファイラを見て調べてみると, *argで >受けるところで配列が生成されるので, そこで呼び出しコストが発生していた >みたいで, ということは、石塚さんの使ってるプロファイラは何なのかな? ところで、 import-module が行っているのは、scope-in-state の(勝手に命 名させてもらうと)「代理継承列法」のパクリの、Hash による(今、命名し た)「擬代理継承列法」です。ついでに、import-module-pip.rb という代理 継承列法バージョンも作ってみました。LOOPS の結果: $ ./test times 10 p c L 1000000 import-module-pip (1000000 loops in a scope) : 4.5838 (1.0000) scope-in-state (1000000 loops in a scope) : 4.7934 (1.0457) import-module-pip の方が 4% ぐらい速い種明かしをすると、パラメータの受 け渡しで、*arg -> *arg -> *arg -> *arg と送るより *arg -> arg -> arg -> *arg の方が早いように、ブロックも &b -> &b -> &b -> &b より、&b -> b -> b -> &b とした方が速かったんです。因みに SCOPES の方は $ ./test times 10 p c S 100000 scope-in-state (scopes in 100000 loops) : 11.1864 (1.0000) import-module-pip (scopes in 100000 loops) : 13.4977 (1.2066) です。import-module-pip が 20% 近く遅いのは、ちょっと差がありすぎのよ うな気がするんですが、もしかすると次のような scope-in-state の仕様のせ いかもしれません。 ----------------------------- require "scope-in-state" class Foo def foo; p "Foo"; end end module S module Foo def foo; p "S"; end end end module T module Foo def foo; p "T"; end end end ScopeS = ScopeInState.new(S) ScopeT = ScopeInState.new(T) foo = Foo.new ScopeS.scope_in do ScopeT.scope_in do ScopeS.scope_in do foo.foo # -> "T" ?? end end end ----------------------------- ?? が "S" でないのは、モジュールが一つの(代理)継承列で一回しか include できないせいなので、直接メソッド定義を eval すればいいと思います。そうす ると SCOPES の差は縮まる気がするのですが、実際はわかりません。 single thread バージョンの方も、必要性の低い堅牢さを捨てたら、初期バー ジョンより SCOPES で、500 倍ぐらい速くなりました。 $ ./test times 10 s c S 100000 scope-in-state (scopes in 100000 loops) : 11.6216 (1.0000) import-module-single-thread (scopes in 100000 loops) : 13.4670 (1.1588) もちろん、import-module-single-thread の LOOPS の方はもともと限界まで 行ってるので今まで通りです。 と、さんざんこねくり回しておいて、いまさらこんなこと言うのも何なんです が、最初コンセプトの話だったはずがいつのまにか実装のでのスピード競争み たいになってしまって、これがどのぐらい意味があるかちょっと疑問ですね。 そもそも LOOPS と SCOPES という2つテストが極端すぎて適切でない、とい うか、もっと別のケースも考慮すべきですよね。特に LOOPS の方は、OS や CPU によってもずいぶん結果が違うし、実は import-module.rb, import-module-pip.rb には、決して使われない関数が定義されているのです が、それを削るとなぜか有意の差で遅くなるんです。ファイル名を変えても差 がでる。これはもう異常な世界です(^^;。 さしあたって、かなり実用性あるものができたのは良かったかな。