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

ruby-changes:47630

From: shyouhei <ko1@a...>
Date: Tue, 5 Sep 2017 13:49:04 +0900 (JST)
Subject: [ruby-changes:47630] shyouhei:r59746 (trunk): optimize rb_hash_bulk_insert to generally outperform 2.4.

shyouhei	2017-09-05 13:49:01 +0900 (Tue, 05 Sep 2017)

  New Revision: 59746

  https://svn.ruby-lang.org/cgi-bin/viewvc.cgi?view=revision&revision=59746

  Log:
    optimize rb_hash_bulk_insert to generally outperform 2.4.
    
    Specialized routine for small linear-probling hash instances to
    boost creation of such things [Bug #13861]
    
    Signed-off-by: Urabe, Shyouhei <shyouhei@r...>

  Modified files:
    trunk/st.c
Index: st.c
===================================================================
--- st.c	(revision 59745)
+++ st.c	(revision 59746)
@@ -2102,42 +2102,84 @@ st_rehash(st_table *tab) https://github.com/ruby/ruby/blob/trunk/st.c#L2102
 }
 
 #ifdef RUBY
-/* Mimics ruby's { foo => bar } syntax. This function is placed here
-   because it touches table internals and write barriers at once. */
-void
-rb_hash_bulk_insert(long argc, const VALUE *argv, VALUE hash)
+static st_data_t
+st_stringify(VALUE key)
 {
-    int i;
-    st_table *tab;
+    return (rb_obj_class(key) == rb_cString) ?
+        rb_str_new_frozen(key) : key;
+}
 
-    st_assert(argc % 2);
-    if (! argc)
-        return;
-    if (! RHASH(hash)->ntbl)
-        rb_hash_tbl_raw(hash);
-    tab = RHASH(hash)->ntbl;
+static void
+st_insert_single(st_table *tab, VALUE hash, VALUE key, VALUE val)
+{
+    st_data_t k = st_stringify(key);
+    st_table_entry e;
+    e.hash = do_hash(k, tab);
+    e.key = k;
+    e.record = val;
+
+    tab->entries[tab->entries_bound++] = e;
+    tab->num_entries++;
+    RB_OBJ_WRITTEN(hash, Qundef, k);
+    RB_OBJ_WRITTEN(hash, Qundef, val);
+}
+
+static void
+st_insert_linear(st_table *tab, long argc, const VALUE *argv, VALUE hash)
+{
+    long i;
+
+    for (i = 0; i < argc; /* */) {
+        st_data_t k = st_stringify(argv[i++]);
+        st_data_t v = argv[i++];
+        st_insert(tab, k, v);
+        RB_OBJ_WRITTEN(hash, Qundef, k);
+        RB_OBJ_WRITTEN(hash, Qundef, v);
+    }
+}
 
-    /* make room */
-    st_expand_table(tab, tab->num_entries + argc);
+static void
+st_insert_generic(st_table *tab, long argc, const VALUE *argv, VALUE hash)
+{
+    int i;
 
     /* push elems */
     for (i = 0; i < argc; /* */) {
         VALUE key = argv[i++];
         VALUE val = argv[i++];
-        st_data_t k = (rb_obj_class(key) == rb_cString) ?
-            rb_str_new_frozen(key) : key;
-        st_table_entry e;
-        e.hash = do_hash(k, tab);
-        e.key = k;
-        e.record = val;
-
-        tab->entries[tab->entries_bound++] = e;
-        tab->num_entries++;
-        RB_OBJ_WRITTEN(hash, Qundef, k);
-        RB_OBJ_WRITTEN(hash, Qundef, val);
+        st_insert_single(tab, hash, key, val);
     }
 
     /* reindex */
     st_rehash(tab);
 }
+
+/* Mimics ruby's { foo => bar } syntax. This function is placed here
+   because it touches table internals and write barriers at once. */
+void
+rb_hash_bulk_insert(long argc, const VALUE *argv, VALUE hash)
+{
+    st_index_t n;
+    st_table *tab = RHASH(hash)->ntbl;
+
+    st_assert(argc % 2);
+    if (! argc)
+        return;
+    if (! tab) {
+        VALUE tmp = rb_hash_new_with_size(argc / 2);
+        RBASIC_CLEAR_CLASS(tmp);
+        RHASH(hash)->ntbl = tab = RHASH(tmp)->ntbl;
+        RHASH(tmp)->ntbl = NULL;
+    }
+    n = tab->num_entries + argc / 2;
+    st_expand_table(tab, n);
+    if (UNLIKELY(tab->num_entries))
+        st_insert_generic(tab, argc, argv, hash);
+    else if (argc <= 2)
+        st_insert_single(tab, hash, argv[0], argv[1]);
+    else if (tab->bin_power <= MAX_POWER2_FOR_TABLES_WITHOUT_BINS)
+        st_insert_linear(tab, argc, argv, hash);
+    else
+        st_insert_generic(tab, argc, argv, hash);
+}
 #endif

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

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