[前][次][番号順一覧][スレッド一覧]

ruby-changes:64199

From: Koichi <ko1@a...>
Date: Wed, 16 Dec 2020 13:06:36 +0900 (JST)
Subject: [ruby-changes:64199] 5499651ee7 (master): tuning ivar set

https://git.ruby-lang.org/ruby.git/commit/?id=5499651ee7

From 5499651ee75538a4d8a3bb4a7442f5f59f36acd8 Mon Sep 17 00:00:00 2001
From: Koichi Sasada <ko1@a...>
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

diff --git a/internal/variable.h b/internal/variable.h
index 34ad4e1..057becc 100644
--- a/internal/variable.h
+++ b/internal/variable.h
@@ -52,7 +52,7 @@ VALUE rb_gvar_get(ID); https://github.com/ruby/ruby/blob/trunk/internal/variable.h#L52
 VALUE rb_gvar_set(ID, VALUE);
 VALUE rb_gvar_defined(ID);
 void rb_const_warn_if_deprecated(const rb_const_entry_t *, VALUE, ID);
-void rb_init_iv_list(VALUE obj, uint32_t len, uint32_t newsize, st_table * index_tbl);
+void rb_init_iv_list(VALUE obj);
 MJIT_SYMBOL_EXPORT_END
 
 static inline bool
diff --git a/variable.c b/variable.c
index 45385fb..5b430a7 100644
--- a/variable.c
+++ b/variable.c
@@ -1413,8 +1413,8 @@ rb_obj_transient_heap_evacuate(VALUE obj, int promote) https://github.com/ruby/ruby/blob/trunk/variable.c#L1413
 }
 #endif
 
-void
-rb_init_iv_list(VALUE obj, uint32_t len, uint32_t newsize, st_table * index_tbl)
+static void
+init_iv_list(VALUE obj, uint32_t len, uint32_t newsize, st_table *index_tbl)
 {
     VALUE *ptr = ROBJECT_IVPTR(obj);
     VALUE *newptr;
@@ -1435,6 +1435,15 @@ rb_init_iv_list(VALUE obj, uint32_t len, uint32_t newsize, st_table * index_tbl) https://github.com/ruby/ruby/blob/trunk/variable.c#L1435
     ROBJECT(obj)->as.heap.iv_index_tbl = index_tbl;
 }
 
+void
+rb_init_iv_list(VALUE obj)
+{
+    st_table *index_tbl = ROBJECT_IV_INDEX_TBL(obj);
+    uint32_t newsize = (uint32_t)index_tbl->num_entries;
+    uint32_t len = ROBJECT_NUMIV(obj);
+    init_iv_list(obj, len, newsize, index_tbl);
+}
+
 static VALUE
 obj_ivar_set(VALUE obj, ID id, VALUE val)
 {
@@ -1453,7 +1462,7 @@ obj_ivar_set(VALUE obj, ID id, VALUE val) https://github.com/ruby/ruby/blob/trunk/variable.c#L1462
     len = ROBJECT_NUMIV(obj);
     if (len <= ivup.index) {
         uint32_t newsize = iv_index_tbl_newsize(&ivup);
-        rb_init_iv_list(obj, len, newsize, ivup.u.iv_index_tbl);
+        init_iv_list(obj, len, newsize, ivup.u.iv_index_tbl);
     }
     RB_OBJ_WRITE(obj, &ROBJECT_IVPTR(obj)[ivup.index], val);
 
diff --git a/vm_insnhelper.c b/vm_insnhelper.c
index d565b79..f343f71 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 https://github.com/ruby/ruby/blob/trunk/vm_insnhelper.c#L1190
     }
 }
 
+
+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 v0.10.2


--
ML: ruby-changes@q...
Info: http://www.atdot.net/~ko1/quickml/

[前][次][番号順一覧][スレッド一覧]