ささだです.

(2012/11/11 15:01), Shugo Maeda wrote:
> 2012/11/11 SASADA Koichi <ko1 / atdot.net>:
>> refinement を導入するときの性能に対する excuse が「method cache に殆どあ
>> たるから,(refinement に関係無い部分の)性能低下はない」という話だった
>> と思うのですが,今回のコードを見ると,それなりにメソッド探索コストが増え
>> そうな気がするんですが,いかがでしょうか.
>>
>> 昨日相談させて頂いたとおり,実装としては refinement は
>>  - メソッド探索から refinement 関係の処理を削除
>>  - 探索したメソッドが refine されたメソッドだったら,
>>    その時点で適切なメソッドを呼び出す
>> のが良いと思います.
> 
> 上記の変更の前に、とりあえずテストの追加と、それが通るような修正をしています。
> ただ、上記の変更って私が実装するという話なんでしたっけ?


 この件,私が実装しても shugo さんがされても良いかと思います.ただ,話
の順番がおかしい,という気がしています.refinement の導入は,
(refinement の関係の無い部分での)コストが十分に低い,という前提があっ
たと思います.しかし,今回の件は,この前提をひっくり返している,もしくは
ひっくり返す可能性があります.

 この場合,執りうる手段は,

(1) パフォーマンスが遅くなっても良いか,数値をもとに合意を得る
(2) module_eval の機能を性能を理由に reject する
(3) 速度の問題がない実装を用意する

の 3 つではないかと思います.それらをせずに,今回のように「とりあえず仕
様に合致させるために修正を突っ込んだ」というのは反対したいです.


 とりあえず,実際に,手元で測ってみました.

(a) ruby 2.0.0dev (2012-11-10 trunk 37604) [x86_64-linux] 11/10 の版
(b) ruby 2.0.0dev (2012-11-11 trunk 37624) [x86_64-linux] 今朝の trunk

                         (a)     (b)   # 単位は秒
loop_whileloop          1.029   1.024
vm1_yield*              1.414   1.780
vm2_defined_method      6.252   6.788
vm2_method              2.585   3.251
vm2_method_missing      4.558   5.066
vm2_method_with_block   2.576   3.326
vm2_poly_method         4.989   4.645
vm2_poly_method_ov      0.715   0.768
vm3_clearmethodcache    1.062   1.097
app_mandelbrot          2.625   2.738
app_tak                 1.958   2.016
app_tarai               1.336   1.441
so_mandelbrot           5.924   5.712

               (b)/(a) # 大きいと (2) が速い
loop_whileloop          1.005
vm1_yield*              0.795
vm2_defined_method      0.921
vm2_method              0.795
vm2_method_missing      0.900
vm2_method_with_block   0.774
vm2_poly_method         1.074
vm2_poly_method_ov      0.931
vm3_clearmethodcache    0.968
app_mandelbrot          0.959
app_tak                 0.971
app_tarai               0.927
so_mandelbrot           1.037

 単純な例(vm2_method)だと 2 割ほど遅くなっているようです.tarai だと
8% ですね.

# インラインメソッドキャッシュが効かない例(vm2_poly_method)だと速く
なっているのはなぜなんだろう....

 動くので「大問題」ではないと思いますが,このままリリースするには抵抗が
あります.


> だとすると、もうちょっと細かいところを確認したいです。
> 
> 基本的なアイデアは、refine対象のクラス(refineの引数)のメソッドにrefineされたこと
> を表す印を付けておいて、通常のメソッド探索でそのメソッドが見つかった時にはじめて
> refinements専用のパスで探索するということですよね。
> 
> 以下のような疑問があります。
> 
> * refineされたことを表すmethod entryの構造をどうするか
>   rb_method_type_tにVM_METHOD_TYPE_REFINEDみたいなのを追加するんでしたっけ。
>   もとのmethod entryはrb_method_entry_t::def->bodyとかから参照するんですかね。

 例えば,そんな感じのものを想定していました.

> * refineした時にrefine対象クラスにメソッドがない時はどうするか
>   メソッドがない時も常にrefineされたことを示すmethod entryを追加する?

 その点,私もあのあと気づいたのですが,refine されるメソッドは追加する
と良いと思います.

(そもそも,refine されるべきメソッドがないのに refine できる,って仕様
はどうなの,という気もしましたが.まぁ,そういうシチュエーションもあるの
かなぁ)

> * refineされたメソッドの呼出時にrb_call_info_tにどういう情報を格納するか
>   Twitterでは、refineされたことを示すmethod entryを入れておくということでしたが、
>   今のvm_call_methodの構造だとrb_call_info_tの中身を書き換えてgotoするような
>   形になっているので、どういう変更を意図されているのかよくわかりませんでした。

 goto は無いですが,この辺は特に変更は不要な気がします.

 結論が出たら,私が実装しますかね.

-- 
// SASADA Koichi at atdot dot net