[pypy-commit] pypy stackroot-speedup: (fijal, arigo)

arigo noreply at buildbot.pypy.org
Sat Jan 28 16:55:47 CET 2012


Author: Armin Rigo <arigo at tunes.org>
Branch: stackroot-speedup
Changeset: r51910:641b24e593c6
Date: 2012-01-28 16:30 +0100
http://bitbucket.org/pypy/pypy/changeset/641b24e593c6/

Log:	(fijal, arigo)

	Trying to speed up the stack root walking step of minor collections.
	The idea is to mark and detect the limit of the previous stack root
	walking, so that we don't need to repeat tracing over the already-
	scanned, already-old objects.

diff --git a/pypy/rpython/lltypesystem/ll2ctypes.py b/pypy/rpython/lltypesystem/ll2ctypes.py
--- a/pypy/rpython/lltypesystem/ll2ctypes.py
+++ b/pypy/rpython/lltypesystem/ll2ctypes.py
@@ -1266,6 +1266,9 @@
     def _cast_to_ptr(self, TP):
         return force_cast(TP, self.intval)
 
+    def _cast_to_int(self, symbolic="ignored"):
+        return long(self)    # 'self' is already a subclass of long...
+
     def __repr__(self):
         return '<_lladdress %s>' % (self.void_p,)
 
diff --git a/pypy/rpython/memory/gctransform/shadowstack.py b/pypy/rpython/memory/gctransform/shadowstack.py
--- a/pypy/rpython/memory/gctransform/shadowstack.py
+++ b/pypy/rpython/memory/gctransform/shadowstack.py
@@ -1,7 +1,7 @@
 from pypy.rpython.memory.gctransform.framework import BaseRootWalker
 from pypy.rpython.memory.gctransform.framework import sizeofaddr
 from pypy.rpython.annlowlevel import llhelper
-from pypy.rpython.lltypesystem import lltype, llmemory
+from pypy.rpython.lltypesystem import lltype, llmemory, rffi
 from pypy.rlib.debug import ll_assert
 from pypy.rlib.nonconst import NonConstant
 from pypy.annotation import model as annmodel
@@ -10,6 +10,11 @@
 class ShadowStackRootWalker(BaseRootWalker):
     need_root_stack = True
 
+    # special values in the shadowstack (different values than
+    # the jit's MARKER, which is 8):
+    MARKER_NOT_TRACED = 16
+    MARKER_TRACED     = 24
+
     def __init__(self, gctransformer):
         BaseRootWalker.__init__(self, gctransformer)
         # NB. 'self' is frozen, but we can use self.gcdata to store state
@@ -42,12 +47,34 @@
                     addr += sizeofaddr
             self.rootstackhook = jit_walk_stack_root
         else:
-            def default_walk_stack_root(callback, addr, end):
+            def default_walk_stack_root(callback, start, end, is_minor):
                 gc = self.gc
-                while addr != end:
+                addr = end
+                while addr != start:
+                    addr -= sizeofaddr
+                    value = llmemory.cast_adr_to_int(addr.address[0])
+                    #
+                    # If myaddr contains MARKER_TRACED, and if we are doing
+                    # a minor collection, then stop here.  The previous items
+                    # have all been traced at least once already, so they
+                    # cannot contain young pointers.
+                    if value == self.MARKER_TRACED:
+                        if is_minor:
+                            break
+                        continue     # ignore the marker and continue
+                    #
+                    # If myaddr contains MARKER_NOT_TRACED, replace it by
+                    # MARKER_TRACED.
+                    if value == self.MARKER_NOT_TRACED:
+                        addr.address[0] = rffi.cast(llmemory.Address,
+                                                    self.MARKER_TRACED)
+                        continue
+                    #
+                    # Regular part follows: invoke 'callback' if myaddr really
+                    # points to an object
                     if gc.points_to_valid_gc_object(addr):
                         callback(gc, addr)
-                    addr += sizeofaddr
+                #
             self.rootstackhook = default_walk_stack_root
 
         self.shadow_stack_pool = ShadowStackPool(gcdata)
diff --git a/pypy/rpython/memory/gctransform/test/test_shadowstack.py b/pypy/rpython/memory/gctransform/test/test_shadowstack.py
new file mode 100644
--- /dev/null
+++ b/pypy/rpython/memory/gctransform/test/test_shadowstack.py
@@ -0,0 +1,54 @@
+from pypy.rpython.memory.gctransform.shadowstack import ShadowStackRootWalker
+from pypy.rpython.memory.gctransform.shadowstack import sizeofaddr
+from pypy.rpython.lltypesystem import lltype, llmemory, rffi
+
+
+class MockGC:
+    def points_to_valid_gc_object(self, addr):
+        n = rffi.cast(lltype.Signed, addr.address[0])
+        if n > 0x1000:
+            return True
+        if n == 0:
+            return False
+        assert 0, "oups, bogus address: 0x%x" % n
+
+class MockGCData:
+    gc = MockGC()
+
+class MockGcTransformer:
+    gcdata = MockGCData()
+    translator = None
+    root_stack_depth = None
+
+
+def test_default_walk_stack_root():
+    for (minor, already_traced) in [(False, False),
+                                    (False, True),
+                                    (True, False),
+                                    (True, True)]:
+        root_stack_size = sizeofaddr * 5
+        a = llmemory.raw_malloc(root_stack_size)
+        a.address[0] = llmemory.NULL
+        a.address[1] = rffi.cast(llmemory.Address, 0x1234)
+        if already_traced:
+            marker = ShadowStackRootWalker.MARKER_TRACED
+        else:
+            marker = ShadowStackRootWalker.MARKER_NOT_TRACED
+        a.address[2] = rffi.cast(llmemory.Address, marker)
+        a.address[3] = rffi.cast(llmemory.Address, 0x5678)
+        a.address[4] = llmemory.NULL
+        walker = ShadowStackRootWalker(MockGcTransformer())
+        seen = []
+        def callback(gc, addr):
+            assert gc == walker.gc
+            seen.append(rffi.cast(lltype.Signed, addr.address[0]))
+        aend = a + 5 * sizeofaddr
+        walker.rootstackhook(callback, a, aend, is_minor=minor)
+        marker = rffi.cast(lltype.Signed, a.address[2])
+        assert marker == ShadowStackRootWalker.MARKER_TRACED
+        if minor and already_traced:
+            assert seen == [0x5678]
+        else:
+            assert seen == [0x5678, 0x1234]
+        llmemory.raw_free(a)
+


More information about the pypy-commit mailing list