inline method cache をよりよくする方法を思いついた気がしたんだけど,気のせいだったという話.
今は,vmstate(キャッシュしたときの状態)+CLASS_OF(recv) が等しければキャッシュヒットとしていたんだけど,必ず CLASS_OF(recv) のコストがかかってしまう.どうにかなんないものか,とずっと考えていた(数年来).
で,今回の変更で recv をインラインキャッシュと同じ構造体に突っ込んでいるんで,それなら recv と比較してマッチすれば,それはヒットにすればいいじゃん,という話.
つまり,vmstat が同じ,かつ(recv が同じ,または,CLASS_OF(recv) が同じ)とすればいいじゃん,という.で,それをコードにしたのが以下.
static void
vm_search_method(rb_call_info_t *ci, VALUE recv)
{
VALUE klass;
rb_method_entry_t *me;
#if OPT_INLINE_METHOD_CACHE
if (LIKELY(GET_VM_STATE_VERSION() == ci->vmstat)) {
if (recv == ci->recv) {
/* cache hit! */
goto finish;
}
else if ((klass = CLASS_OF(recv)) == ci->klass) {
/* cache hit! */
ci->recv = recv;
goto finish;
}
else {
goto klass_was_stored;
}
}
else {
klass = CLASS_OF(recv);
klass_was_stored:
me = rb_method_entry(klass, ci->mid, &ci->defined_class);
ci->me = me;
ci->recv = recv;
ci->klass = klass;
ci->vmstat = GET_VM_STATE_VERSION();
ci->call = vm_call_general;
}
finish:;
#else
klass = CLASS_OF(recv);
ci->me = rb_method_entry(klass, ci->mid, &ci->defined_class);
ci->call = vm_call_general;
ci->klass = klass;
ci->recv = recv;
#endif
}
goto とか使ってちょっと判りづらくなってるけど.
キャッシュミスのときのオーバヘッドは recv == ci->recv の判定のみなので,そんなにたいしたことないだろう,と思う.
で,これだとまずいことがわかったので reject.ci->recv は mark 対象じゃないので,GC される可能性があり,すなわち「たまたま recv が同じ場合がある」という話.ガーン.
あと,時間測ってみたら,殆どきかんかった....そもそも,ここはオーバヘッドじゃなかったのか?
http://www.atdot.net/fp_store/f.qt03cm/file.graph.png trunk が入れた結果で,効果なかったという.
CLASS_OFってそんなに重いんですか?