From 5499651ee75538a4d8a3bb4a7442f5f59f36acd8 Mon Sep 17 00:00:00 2001 From: Koichi Sasada Date: Wed, 16 Dec 2020 12:03:36 +0900 Subject: tuning ivar set * make rb_init_iv_list() simple * introduce vm_setivar_slowpath() for cache miss cases ../clean/miniruby is 647ee6f091. Calculating ------------------------------------- ./miniruby ../clean/miniruby ../ruby_2_7/miniruby vm_ivar_init 7.388M 6.814M 5.771M i/s - 30.000M times in 4.060420s 4.402534s 5.198781s vm_ivar_init_subclass 2.158M 2.147M 1.974M i/s - 3.000M times in 1.390328s 1.397587s 1.519951s vm_ivar_set 128.607M 97.931M 140.668M i/s - 30.000M times in 0.233269s 0.306338s 0.213268s vm_ivar 144.315M 151.722M 117.734M i/s - 30.000M times in 0.207879s 0.197730s 0.254811s Comparison: vm_ivar_init ./miniruby: 7388398.8 i/s ../clean/miniruby: 6814257.1 i/s - 1.08x slower ../ruby_2_7/miniruby: 5770583.9 i/s - 1.28x slower vm_ivar_init_subclass ./miniruby: 2157763.6 i/s ../clean/miniruby: 2146557.0 i/s - 1.01x slower ../ruby_2_7/miniruby: 1973747.9 i/s - 1.09x slower vm_ivar_set ../ruby_2_7/miniruby: 140668063.8 i/s ./miniruby: 128606912.1 i/s - 1.09x slower ../clean/miniruby: 97931027.8 i/s - 1.44x slower vm_ivar ../clean/miniruby: 151722121.9 i/s ./miniruby: 144314526.5 i/s - 1.05x slower ../ruby_2_7/miniruby: 117734305.5 i/s - 1.29x slower --- vm_insnhelper.c | 100 +++++++++++++++++++++++++++++++------------------------- 1 file changed, 56 insertions(+), 44 deletions(-) (limited to 'vm_insnhelper.c') diff --git a/vm_insnhelper.c b/vm_insnhelper.c index d565b79f92..f343f71bd6 100644 --- a/vm_insnhelper.c +++ b/vm_insnhelper.c @@ -1190,70 +1190,82 @@ vm_getivar(VALUE obj, ID id, const rb_iseq_t *iseq, IVC ic, const struct rb_call } } + +NOINLINE(static VALUE vm_setivar_slowpath(VALUE obj, ID id, VALUE val, const rb_iseq_t *iseq, IVC ic, const struct rb_callcache *cc, int is_attr)); + +static VALUE +vm_setivar_slowpath(VALUE obj, ID id, VALUE val, const rb_iseq_t *iseq, IVC ic, const struct rb_callcache *cc, int is_attr) +{ + rb_check_frozen_internal(obj); + +#if OPT_IC_FOR_IVAR + if (RB_TYPE_P(obj, T_OBJECT)) { + struct st_table *iv_index_tbl = ROBJECT_IV_INDEX_TBL(obj); + struct rb_iv_index_tbl_entry *ent; + + if (iv_index_tbl_lookup(iv_index_tbl, id, &ent)) { + if (!is_attr) { + ic->entry = ent; + RB_OBJ_WRITTEN(iseq, Qundef, ent->class_value); + } + else if (ent->index >= INT_MAX) { + rb_raise(rb_eArgError, "too many instance variables"); + } + else { + vm_cc_attr_index_set(cc, (int)(ent->index + 1)); + } + + uint32_t index = ent->index; + + if (UNLIKELY(index >= ROBJECT_NUMIV(obj))) { + rb_init_iv_list(obj); + } + VALUE *ptr = ROBJECT_IVPTR(obj); + RB_OBJ_WRITE(obj, &ptr[index], val); + RB_DEBUG_COUNTER_INC(ivar_set_ic_miss_iv_hit); + + return val; + } + } +#endif + RB_DEBUG_COUNTER_INC(ivar_set_ic_miss); + return rb_ivar_set(obj, id, val); +} + static inline VALUE vm_setivar(VALUE obj, ID id, VALUE val, const rb_iseq_t *iseq, IVC ic, const struct rb_callcache *cc, int is_attr) { #if OPT_IC_FOR_IVAR - rb_check_frozen_internal(obj); - - if (LIKELY(RB_TYPE_P(obj, T_OBJECT))) { - VALUE klass = RBASIC(obj)->klass; - uint32_t index; + if (LIKELY(RB_TYPE_P(obj, T_OBJECT)) && + LIKELY(!RB_OBJ_FROZEN_RAW(obj))) { VM_ASSERT(!rb_ractor_shareable_p(obj)); if (LIKELY( - (!is_attr && RB_DEBUG_COUNTER_INC_UNLESS(ivar_set_ic_miss_serial, ic->entry && ic->entry->class_serial == RCLASS_SERIAL(klass))) || + (!is_attr && RB_DEBUG_COUNTER_INC_UNLESS(ivar_set_ic_miss_serial, ic->entry && ic->entry->class_serial == RCLASS_SERIAL(RBASIC(obj)->klass))) || ( is_attr && RB_DEBUG_COUNTER_INC_UNLESS(ivar_set_ic_miss_unset, vm_cc_attr_index(cc) > 0)))) { - VALUE *ptr = ROBJECT_IVPTR(obj); - index = !is_attr ? ic->entry->index : vm_cc_attr_index(cc)-1; + uint32_t index = !is_attr ? ic->entry->index : vm_cc_attr_index(cc)-1; - if (index >= ROBJECT_NUMIV(obj)) { - st_table * iv_idx_tbl = ROBJECT_IV_INDEX_TBL(obj); - rb_init_iv_list(obj, ROBJECT_NUMIV(obj), (uint32_t)iv_idx_tbl->num_entries, iv_idx_tbl); - ptr = ROBJECT_IVPTR(obj); + if (UNLIKELY(index >= ROBJECT_NUMIV(obj))) { + rb_init_iv_list(obj); } + VALUE *ptr = ROBJECT_IVPTR(obj); RB_OBJ_WRITE(obj, &ptr[index], val); RB_DEBUG_COUNTER_INC(ivar_set_ic_hit); return val; /* inline cache hit */ } - else { - struct st_table *iv_index_tbl = ROBJECT_IV_INDEX_TBL(obj); - struct rb_iv_index_tbl_entry *ent; - - if (iv_index_tbl_lookup(iv_index_tbl, id, &ent)) { - if (!is_attr) { - ic->entry = ent; - RB_OBJ_WRITTEN(iseq, Qundef, ent->class_value); - } - else if (ent->index >= INT_MAX) { - rb_raise(rb_eArgError, "too many instance variables"); - } - else { - vm_cc_attr_index_set(cc, (int)(ent->index + 1)); - } - - index = ent->index; - - VALUE *ptr = ROBJECT_IVPTR(obj); - if (index >= ROBJECT_NUMIV(obj)) { - rb_init_iv_list(obj, ROBJECT_NUMIV(obj), (uint32_t)iv_index_tbl->num_entries, iv_index_tbl); - ptr = ROBJECT_IVPTR(obj); - } - RB_OBJ_WRITE(obj, &ptr[index], val); - RB_DEBUG_COUNTER_INC(ivar_set_ic_miss_iv_hit); - - return val; - } - /* fall through */ - } } else { RB_DEBUG_COUNTER_INC(ivar_set_ic_miss_noobject); } #endif /* OPT_IC_FOR_IVAR */ - RB_DEBUG_COUNTER_INC(ivar_set_ic_miss); - return rb_ivar_set(obj, id, val); + return vm_setivar_slowpath(obj, id, val, iseq, ic, cc, is_attr); +} + +VALUE +rb_vm_setivar(VALUE obj, ID id, VALUE val, const rb_iseq_t *iseq, IVC ic) +{ + return vm_setivar(obj, id, val, iseq, ic, NULL, false); } static inline VALUE -- cgit v1.2.3