AOベンチ高速化計画(その2)

細かいパラメータをいじって、

time ruby19 yarv2llvm.rb --no-type-message sample/ao-render.rb > ao.ppm

real	2m48.370s
user	2m46.888s
sys	0m0.732s

という記録を出しました。前は200秒だったので、15%くらい速くなっています。いじったパラメータはメソッド内にいくつそのインスタンス変数があればキャッシュするかというものです。

こんな背景から、インスタンス変数のアドレス(lvalue)をキャッシュしています。

  1. yarv2llvmではRubyAPIを使って直接読み書きすることもできます。でも、そうするとアクセスのたびにハッシュテーブルを引くことになります。
  2. そこでインスタンス変数のlvalueをスタック上にキャッシュし、インスタンス変数のアクセスをキャッシュしたlvalueに対して行うようにします。lvalueは本物の変数のアドレスですから、ちゃんと別のメソッドから参照しても正しい値が得られます。

しかし、メソッド内に1つしか変数が無ければ(そしてそれがループ内でなければ)、キャッシュしても無意味ですし、スタック上にlvaueを書き出すだけ無駄になります。そういうことで、メソッド上にいくつインスタンス変数があるか数えています、そしてある閾値を越えるまでキャッシュしないようにしています。しかし、サンタ問題を動かすのには常にlvalueがキャッシュされている必要があるので、常にキャッシュするように設定されていました。それを最適な値(2)としたら、速くなりました。

一方、うまいアイデアが浮かんだので試してみました。Inline cacheのようなものをインスタンス変数にも適用するというもので、個々のインスタンス変数のアクセスについて(または、キャッシュを設定している場所について)、2つのグローバル変数(「Rubyの」ではなく、「LLVMの」)を用意します。1つは前回アクセスした時のself、もう1つは前回アクセスしたときのlvalueを入れておきます。Rubyはselfのインスタンス変数しか直接アクセスできないので、selfが前回と同じなら同じlvalueになっているはずです。そこで、もう1つのグローバル変数からlvalueを得ます。もし、selfが前回と違えば通常のようにハッシュを検索します。
これでかなり速くなるぞって思ったら遅くなりました。

real	3m45.814s
user	3m43.842s
sys	0m0.826s

キャッシュヒットの判定処理がうまく行っていないのか、メモリーキャッシュの関係か悩んでいます。