2008-12-12
nbodyが動きました
|yarv2llvmでnbodyが動きました。まだ、attr_accessorとかサポートしていないので、プログラムに手を加えています。
sample/bm_so_nbody.rbがソースです。(http://github.com/miura1729/yarv2llvm/tree/master/sample/bm_so_nbody.rb)
実行速度を測ってみました。N=200_000です。
-0.169075164 -0.169083713 real 0m16.674s user 0m16.577s sys 0m0.108s
yarv2llvm
-0.169075163828524 -0.169083712569648 real 0m6.576s user 0m5.982s sys 0m0.592s
これは、コンパイル時間込みの場合です。その場合で2倍強、コンパイル時間が約2秒くらいなのでコンパイル時間を入れないと3倍強という感じです。fibだと30倍以上だったので、ずいぶんな速度低下です。インスタンス変数のアクセスとかRubyのランタイムを呼びまくっているのでこんなものかなーと思います。インスタンス変数のアクセスをキャッシュするとかすると速度が上がるんじゃないかなと思っています。
それよりも、nbodyみたいな比較的複雑なプログラムでも型矛盾を起さずにコンパイルできてしまうことにびっくりです。
追記(2008/12/13)
インスタンス変数のlvalueをスタック上にキャッシュするようにしてみました。
-0.169075163828524 195827.292170961 real 0m5.342s user 0m4.872s sys 0m0.483s
ちょっと速くなるが答えが違う。おそらくバグが取れてもこれより速くなることは無いと思うのでこの方法でも5倍くらいまでしか行かないようです。この場合も型変換のオーバヘッドが残るのですが、これを何とかする方法が思いつきません。
ドキュメントに
「Real Programmers Don't Use Instance Variables」
とか
「Instance Variables Considered Harmful」
とか書いておいたほうが効果があるのかもしれません。
追記2(2008/12/14)
バグが取れました。ポインタのデリファレンスの回数を間違えていました。
-0.169075163828524 -0.169083712569648 real 0m5.333s user 0m4.716s sys 0m0.638s
スピードアップの方法を考えました。インスタンス変数を型推論で決定したネイティブな表現で格納する配列を用意し、そのポインタをstruct RObjectのstruct st_table *iv_index_tblに格納するって方法です。llvmから復帰するときは、RCLASS_IV_INDEX_TBL(rb_obj_class(obj))で戻しておきます。
- 25 http://www.rubyist.net/~kazu/samidare/
- 4 http://llvmruby.org/wordpress-llvmruby/
- 4 http://www.rubyinside.com/llvmruby-a-compiler-toolkit-available-to-rubyists-1362.html
- 3 http://a.hatena.ne.jp/fujita-y/
- 2 http://d.hatena.ne.jp/keywordmobile/LLVM
- 2 http://github.com/miura1729/yarv2llvm/tree/master
- 2 http://reader.livedoor.com/reader/
- 2 http://tech.slashdot.org/article.pl?sid=08/12/09/1540216
- 2 http://www.google.co.jp/search?hl=ja&client=firefox-a&rls=org.mozilla:ja:official&hs=yP&q=バイナリパッチ&btnG=検索&lr=lang_ja
- 1 http://72.14.235.132/search?q=cache:N9GSEi8Y5rUJ:it_yougo.shooti.jp/s/504352/1+llvm+ビットコード&hl=ja&ct=clnk&cd=13&gl=jp&lr=lang_ja&client=firefox-a
これまで見る限りはメソッドの定義だけではなく呼び出し側の情報も判断すると、型が判らなくてVALUE型になっちゃうことはほとんど無くて、たいていはちゃんと型が決まるようです。ただ、ほとんどのRubyのCで書かれたAPIはVALUE型のデータを渡す必要があるのでAPIを呼び出すと型変換が必要になります。nbodyでは変数の型がdoubleと判っているのにrb_ivar_setを呼び出すためにrb_float_newを呼び出すコードが出力されていてかなり悲しくなりました。