ao benchを高速化しているのですが、うまく行かない

今は、なんだかんだ忙しいのであまりプログラムをいじっていないのですが、時間があるとao benchを高速化することに凝っています。いろいろ試しているのですが、いまいち効果がでません。

例えばこんなことを試してみました。

  1. インスタンス変数はGCの関係上BOX化した形式(VALUE)で格納する必要がある
  2. こうすると、浮動小数点型のデータを扱うと、インスタンス変数の代入のたびにFloatオブジェクトをアロケートする必要がある。
  3. ところで、インスタンス変数が浮動小数点型であると型推論できると代入の際には元のインスタンス変数にはFloatオブジェクトが格納されているのを保障できる。また、このFloatオブジェクトは他の場所から指さないことも保障できる。
  4. そのため、Floatオブジェクトを新たにアロケートする代わりに元のインスタンス変数に入っているFloatオブジェクトを再利用するようにすると、速度がアップするんじゃないかなと考えた。
  5. 試してみたが、1%くらいしか(2分中2秒くらい)速度が上がらない。

なぜだーー、と思いついかっとなって http://d.hatena.ne.jp/miura1729/20090512/1242123708 で使ったGC profiler起動オプションを使ってみました。

ruby19 yarv2llvm.rb --gc-profile sample/ao-render.rb > ao.ppm
GC 2685 invokes.
Index    Invoke Time(sec)       Use Size(byte)     Total Size(byte)         Total Object                    GC Time(ms)
    1               0.219               655920              1425408                71253         0.00000000000000000000
    2               0.281               696520              1441792                72072         0.00000000000000000000
    3               0.469               713680              2572288               128583        16.00000000000001421085
    4               0.891               728540              4227072               211302        15.00000000000001421085
    5               1.360               773540              4243456               212121        14.99999999999990230037
 
                 中略

 2666             130.969               906800              4866048               243243        15.99999999999113242666
 2667             131.016               906880              4866048               243243        14.99999999998635757947
 2668             131.063               906920              4866048               243243        14.99999999998635757947
 2669             131.110               906840              4866048               243243        14.99999999998635757947
 2670             131.156               906900              4866048               243243        16.00000000001955413609
 2671             131.203               906760              4866048               243243        16.00000000001955413609
 2672             131.250               906940              4866048               243243         0.00000000000000000000
 2673             131.281               906940              4866048               243243        16.00000000001955413609
 2674             131.328               906820              4866048               243243        16.00000000001955413609
 2675             131.375               906920              4866048               243243        16.00000000001955413609
 2676             131.422               906960              4866048               243243        15.99999999999113242666
 2677             131.469               906860              4866048               243243        15.99999999999113242666
 2678             131.516               906860              4866048               243243        14.99999999998635757947
 2679             131.563               906900              4866048               243243        14.99999999998635757947

見てみると、1秒間に20回くらいGCが起動されて最終的に1/3がGCで費やされています。オブジェクトのアロケーションも含めると2/3がメモリ操作じゃないかなと思います。やはり、エスケープ解析必要かなと思います。オブジェクトの寿命を掴んで再利用したりとか。

追伸

BOX化されたデータを箱入りデータと呼ぶのはどうでしょう?

追記
Floatオブジェクトの再利用はnbodyでは効果があるみたいです。



Floatオブジェクトの再利用をいれた場合

time ruby19 yarv2llvm.rb bm_so_nbody.rb
-0.169074947
-0.169083520

real	0m5.073s
user	0m4.544s
sys	0m0.310s

Floatオブジェクトの再利用をいれた場合のコンパイル時間

time ruby19 yarv2llvm.rb --compile-only bm_so_nbody.rb

real	0m3.826s
user	0m3.404s
sys	0m0.342s

Floatオブジェクトの再利用をいれない場合

time ruby19 yarv2llvm.rb bm_so_nbody.rb
-0.169074947
-0.169083520

real	0m6.414s
user	0m6.059s
sys	0m0.310s

Floatオブジェクトの再利用をいれない場合のコンパイル時間

time ruby19 yarv2llvm.rb --compile-only bm_so_nbody.rb

real	0m3.784s
user	0m3.451s
sys	0m0.311s

Ruby 1.9.2 で実行した場合

time ruby19 bm_so_nbody.rb
-0.169074947
-0.169083520

real	0m16.602s
user	0m16.405s
sys	0m0.093s

ruby19 -v
ruby 1.9.2dev (2009-05-06 trunk 23350) [i386-cygwin]