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ってそんなに重いんですか?