Author: Remi Meier <[email protected]>
Branch: stmgc-c8-gcc
Changeset: r79560:4850638fd47d
Date: 2015-09-09 11:49 +0200
http://bitbucket.org/pypy/pypy/changeset/4850638fd47d/

Log:    blindly try to improve performance of stmdict/stmset

diff --git a/pypy/module/pypystm/stmdict.py b/pypy/module/pypystm/stmdict.py
--- a/pypy/module/pypystm/stmdict.py
+++ b/pypy/module/pypystm/stmdict.py
@@ -16,23 +16,39 @@
 PARRAY = lltype.Ptr(ARRAY)
 
 
-
+# XXX: should have identity-dict strategy
 def really_find_equal_item(space, h, w_key):
     hkey = space.hash_w(w_key)
     entry = h.lookup(hkey)
     array = lltype.cast_opaque_ptr(PARRAY, entry.object)
+    if not array:
+        return (entry, array, -1)
+    if space.type(w_key).compares_by_identity():
+        # fastpath
+        return (entry, array, _find_equal_item(space, array, w_key))
+    # slowpath
+    return _really_find_equal_item_loop(space, h, w_key, entry, array, hkey)
+
[email protected]_look_inside
+def _really_find_equal_item_loop(space, h, w_key, entry, array, hkey):
+    assert not space.type(w_key).compares_by_identity() # assume it stays that 
way
     while True:
-        if not array:
-            return (entry, array, -1)
-
+        assert array
         i = _find_equal_item(space, array, w_key)
-        if not space.type(w_key).compares_by_identity():
-            entry2 = h.lookup(hkey)
-            array2 = lltype.cast_opaque_ptr(PARRAY, entry2.object)
-            if array2 != array:
-                entry = entry2
-                array = array2
-                continue
+        # custom __eq__ may have been called in _find_equal_item()
+        #
+        # Only if entry.object changed during the call to _find_equal_item()
+        # we have to re-lookup the entry. This is ok since 
entry.object=array!=NULL
+        # when we enter here and therefore, entry can only be thrown out of
+        # the hashtable if it gets NULLed somehow, thus, changing entry.object.
+        array2 = lltype.cast_opaque_ptr(PARRAY, entry.object)
+        if array != array2:
+            # re-get entry (and array)
+            entry = h.lookup(hkey)
+            array = lltype.cast_opaque_ptr(PARRAY, entry.object)
+            if not array:
+                return (entry, array, -1)
+            continue
 
         return (entry, array, i)
 
@@ -69,7 +85,7 @@
 
 def pop_from_entry(h, space, w_key):
     entry, array, i = really_find_equal_item(space, h, w_key)
-    if i < 0:
+    if i < 0: # or not array
         return None
     # found
     w_value = cast_gcref_to_instance(W_Root, array[i + 1])
@@ -97,28 +113,21 @@
         space.raise_key_error(w_key)
 
     def setitem_w(self, space, w_key, w_value):
-        hkey = space.hash_w(w_key)
-        entry = self.h.lookup(hkey)
-        array = lltype.cast_opaque_ptr(PARRAY, entry.object)
-        while True:
-            if array:
-                entry, array, i = really_find_equal_item(space, self.h, w_key)
-                if not array:
-                    continue
-                if i >= 0:
-                    # already there, update the value
-                    array[i + 1] = cast_instance_to_gcref(w_value)
-                    return
-                L = len(array)
-                narray = lltype.malloc(ARRAY, L + 2)
-                ll_arraycopy(array, narray, 0, 0, L)
-            else:
-                narray = lltype.malloc(ARRAY, 2)
-                L = 0
-            narray[L] = cast_instance_to_gcref(w_key)
-            narray[L + 1] = cast_instance_to_gcref(w_value)
-            self.h.writeobj(entry, lltype.cast_opaque_ptr(llmemory.GCREF, 
narray))
-            return
+        entry, array, i = really_find_equal_item(space, self.h, w_key)
+        if array:
+            if i >= 0:
+                # already there, update the value
+                array[i + 1] = cast_instance_to_gcref(w_value)
+                return
+            L = len(array)
+            narray = lltype.malloc(ARRAY, L + 2)
+            ll_arraycopy(array, narray, 0, 0, L)
+        else:
+            narray = lltype.malloc(ARRAY, 2)
+            L = 0
+        narray[L] = cast_instance_to_gcref(w_key)
+        narray[L + 1] = cast_instance_to_gcref(w_value)
+        self.h.writeobj(entry, lltype.cast_opaque_ptr(llmemory.GCREF, narray))
 
     def delitem_w(self, space, w_key):
         if pop_from_entry(self.h, space, w_key) is None:
@@ -148,27 +157,22 @@
 
     @unwrap_spec(w_default=WrappedDefault(None))
     def setdefault_w(self, space, w_key, w_default):
-        hkey = space.hash_w(w_key)
-        entry = self.h.lookup(hkey)
-        array = lltype.cast_opaque_ptr(PARRAY, entry.object)
-        while True:
-            if array:
-                entry, array, i = really_find_equal_item(space, self.h, w_key)
-                if not array:
-                    continue
-                if i >= 0:
-                    # already there, return the existing value
-                    return cast_gcref_to_instance(W_Root, array[i + 1])
-                L = len(array)
-                narray = lltype.malloc(ARRAY, L + 2)
-                ll_arraycopy(array, narray, 0, 0, L)
-            else:
-                narray = lltype.malloc(ARRAY, 2)
-                L = 0
-            narray[L] = cast_instance_to_gcref(w_key)
-            narray[L + 1] = cast_instance_to_gcref(w_default)
-            self.h.writeobj(entry, lltype.cast_opaque_ptr(llmemory.GCREF, 
narray))
-            return w_default
+        entry, array, i = really_find_equal_item(space, self.h, w_key)
+        if array:
+            if i >= 0:
+                # already there, return the existing value
+                return cast_gcref_to_instance(W_Root, array[i + 1])
+            L = len(array)
+            narray = lltype.malloc(ARRAY, L + 2)
+            ll_arraycopy(array, narray, 0, 0, L)
+        else:
+            narray = lltype.malloc(ARRAY, 2)
+            L = 0
+        narray[L] = cast_instance_to_gcref(w_key)
+        narray[L + 1] = cast_instance_to_gcref(w_default)
+        self.h.writeobj(entry, lltype.cast_opaque_ptr(llmemory.GCREF, narray))
+        return w_default
+
 
     def get_length(self):
         array, count = self.h.list()
diff --git a/pypy/module/pypystm/stmset.py b/pypy/module/pypystm/stmset.py
--- a/pypy/module/pypystm/stmset.py
+++ b/pypy/module/pypystm/stmset.py
@@ -17,27 +17,46 @@
 PARRAY = lltype.Ptr(ARRAY)
 
 
-
+# XXX: should have identity-dict strategy
 def really_find_equal_item(space, h, w_key):
     hkey = space.hash_w(w_key)
     entry = h.lookup(hkey)
     array = lltype.cast_opaque_ptr(PARRAY, entry.object)
+    if not array:
+        return (entry, array, -1)
+    if space.type(w_key).compares_by_identity():
+        # fastpath
+        return (entry, array, _find_equal_item(space, array, w_key))
+    # slowpath
+    return _really_find_equal_item_loop(space, h, w_key, entry, array, hkey)
+
[email protected]_look_inside
+def _really_find_equal_item_loop(space, h, w_key, entry, array, hkey):
+    assert not space.type(w_key).compares_by_identity() # assume it stays that 
way
     while True:
-        if not array:
-            return (entry, array, -1)
-
+        assert array
         i = _find_equal_item(space, array, w_key)
-        if not space.type(w_key).compares_by_identity():
-            entry2 = h.lookup(hkey)
-            array2 = lltype.cast_opaque_ptr(PARRAY, entry2.object)
-            if array2 != array:
-                entry = entry2
-                array = array2
-                continue
+        # custom __eq__ may have been called in _find_equal_item()
+        #
+        # Only if entry.object changed during the call to _find_equal_item()
+        # we have to re-lookup the entry. This is ok since 
entry.object=array!=NULL
+        # when we enter here and therefore, entry can only be thrown out of
+        # the hashtable if it gets NULLed somehow, thus, changing entry.object.
+        array2 = lltype.cast_opaque_ptr(PARRAY, entry.object)
+        if array != array2:
+            # re-get entry (and array)
+            entry = h.lookup(hkey)
+            array = lltype.cast_opaque_ptr(PARRAY, entry.object)
+            if not array:
+                return (entry, array, -1)
+            continue
 
         return (entry, array, i)
 
+
 def _find_equal_item(space, array, w_key):
+    # result by this function is based on 'array'. If the entry
+    # changes, the result is stale.
     w_item = cast_gcref_to_instance(W_Root, array[0])
     if space.eq_w(w_key, w_item):
         return 0
@@ -45,6 +64,7 @@
         return _run_next_iterations(space, array, w_key)
     return -1
 
+
 @jit.dont_look_inside
 def _run_next_iterations(space, array, w_key):
     i = 1
@@ -70,32 +90,21 @@
         return space.w_False
 
     def add_w(self, space, w_key):
-        hkey = space.hash_w(w_key)
-        entry = self.h.lookup(hkey)
-        array = lltype.cast_opaque_ptr(PARRAY, entry.object)
-        while True:
-            if array:
-                entry, array, i = really_find_equal_item(space, self.h, w_key)
-                if not array:
-                    continue
-                if i >= 0:
-                    return      # already there
-                L = len(array)
-                narray = lltype.malloc(ARRAY, L + 1)
-                ll_arraycopy(array, narray, 0, 0, L)
-            else:
-                narray = lltype.malloc(ARRAY, 1)
-                L = 0
-            narray[L] = cast_instance_to_gcref(w_key)
-            self.h.writeobj(entry, lltype.cast_opaque_ptr(llmemory.GCREF, 
narray))
-            return
+        entry, array, i = really_find_equal_item(space, self.h, w_key)
+        if array:
+            if i >= 0:
+                return      # already there
+            L = len(array)
+            narray = lltype.malloc(ARRAY, L + 1)
+            ll_arraycopy(array, narray, 0, 0, L)
+        else:
+            narray = lltype.malloc(ARRAY, 1)
+            L = 0
+
+        narray[L] = cast_instance_to_gcref(w_key)
+        self.h.writeobj(entry, lltype.cast_opaque_ptr(llmemory.GCREF, narray))
 
     def try_remove(self, space, w_key):
-        hkey = space.hash_w(w_key)
-        entry = self.h.lookup(hkey)
-        array = lltype.cast_opaque_ptr(PARRAY, entry.object)
-        if not array:
-            return False
         entry, array, i = really_find_equal_item(space, self.h, w_key)
         if not array or i < 0:
             return False
diff --git a/rpython/rlib/rstm.py b/rpython/rlib/rstm.py
--- a/rpython/rlib/rstm.py
+++ b/rpython/rlib/rstm.py
@@ -317,6 +317,11 @@
             # self._content[key] = value
         else:
             try:
+                # set entry to value (since somebody may still have
+                # a reference to it), then delete it from the table,
+                # as that may happen *anytime* if _obj==NULL
+                entry = self.lookup(key)
+                entry._obj = value
                 del self._content[key]
             except KeyError:
                 pass
_______________________________________________
pypy-commit mailing list
[email protected]
https://mail.python.org/mailman/listinfo/pypy-commit

Reply via email to