[pypy-svn] r17813 - in pypy/dist/pypy: rpython rpython/test translator

arigo at codespeak.net arigo at codespeak.net
Sat Sep 24 11:57:03 CEST 2005


Author: arigo
Date: Sat Sep 24 11:56:57 2005
New Revision: 17813

Modified:
   pypy/dist/pypy/rpython/lltype.py
   pypy/dist/pypy/rpython/test/test_lltype.py
   pypy/dist/pypy/translator/transform.py
Log:
Optimizations of translate_pypy, motivated by a profiled run which
you can see at the end of /tmp/PROFILE-out on the snake server:

* LowLevelType.__hash__ is called 99 million times.  Let's make it
  cache its result as best as possible.

* transform.checkgraphs() calls checkgraph() too many times --
  each graph was fully rechecked the same number of times as the
  number of blocks it contains.



Modified: pypy/dist/pypy/rpython/lltype.py
==============================================================================
--- pypy/dist/pypy/rpython/lltype.py	(original)
+++ pypy/dist/pypy/rpython/lltype.py	Sat Sep 24 11:56:57 2005
@@ -35,6 +35,10 @@
 
 
 class LowLevelType(object):
+    # the following line prevents '__cached_hash' to be in the __dict__ of
+    # the instance, which is needed for __eq__() and __hash__() to work.
+    __slots__ = ['__dict__', '__cached_hash']
+
     def __eq__(self, other):
         return self.__class__ is other.__class__ and (
             self is other or safe_equal(self.__dict__, other.__dict__))
@@ -44,20 +48,28 @@
 
     def __hash__(self):
         # cannot use saferecursive() -- see test_lltype.test_hash().
-        # this version uses a compromize between computation time and
-        # collision-avoidance that can be customized if needed.
+        # NB. the __cached_hash should neither be used nor updated
+        # if we enter with hash_level > 0, because the computed
+        # __hash__ can be different in this situation.
+        hash_level = 0
         try:
-            if TLS.nested_hash_level >= 3:
-                return 0
+            hash_level = TLS.nested_hash_level
+            if hash_level == 0:
+                return self.__cached_hash
         except AttributeError:
-            TLS.nested_hash_level = 0
+            pass
+        if hash_level >= 3:
+            return 0
         items = self.__dict__.items()
         items.sort()
-        TLS.nested_hash_level += 1
+        TLS.nested_hash_level = hash_level + 1
         try:
-            return hash((self.__class__,) + tuple(items))
+            result = hash((self.__class__,) + tuple(items))
         finally:
-            TLS.nested_hash_level -= 1
+            TLS.nested_hash_level = hash_level
+        if hash_level == 0:
+            self.__cached_hash = result
+        return result
 
     # due to this dynamic hash value, we should forbid
     # pickling, until we have an algorithm for that.

Modified: pypy/dist/pypy/rpython/test/test_lltype.py
==============================================================================
--- pypy/dist/pypy/rpython/test/test_lltype.py	(original)
+++ pypy/dist/pypy/rpython/test/test_lltype.py	Sat Sep 24 11:56:57 2005
@@ -305,6 +305,7 @@
     S = ForwardReference()
     S.become(Struct('S', ('p', Ptr(S))))
     assert S == S
+    hash(S)   # assert no crash, and force the __cached_hash computation
     S1 = Struct('S', ('p', Ptr(S)))
     assert S1 == S
     assert S == S1

Modified: pypy/dist/pypy/translator/transform.py
==============================================================================
--- pypy/dist/pypy/translator/transform.py	(original)
+++ pypy/dist/pypy/translator/transform.py	Sat Sep 24 11:56:57 2005
@@ -17,10 +17,13 @@
 
 
 def checkgraphs(self, blocks):
+    seen = {}
     for block in blocks:
         fn = self.annotated[block]
         graph = self.translator.flowgraphs[fn]
-        checkgraph(graph)
+        if graph not in seen:
+            checkgraph(graph)
+            seen[graph] = True
 
 def fully_annotated_blocks(self):
     """Ignore blocked blocks."""



More information about the Pypy-commit mailing list