[pypy-commit] pypy gc-forkfriendly-2: Speed tweaks including a bug fix

arigo pypy.commits at gmail.com
Fri Feb 24 02:22:54 EST 2017


Author: Armin Rigo <arigo at tunes.org>
Branch: gc-forkfriendly-2
Changeset: r90334:6a642098cb7f
Date: 2017-02-24 08:22 +0100
http://bitbucket.org/pypy/pypy/changeset/6a642098cb7f/

Log:	Speed tweaks including a bug fix

diff --git a/rpython/memory/gc/minimarkpage.py b/rpython/memory/gc/minimarkpage.py
--- a/rpython/memory/gc/minimarkpage.py
+++ b/rpython/memory/gc/minimarkpage.py
@@ -533,8 +533,8 @@
         surviving = 0    # initially
         skip_free_blocks = page.nfree
         #
-        if self.offline_visited_flags:
-            ok_to_free_func = self.get_unvisited
+        vblocknext = r_uint(0)
+        vblock = rffi.cast(rffi.ULONGLONG, -1)
         #
         while True:
             #
@@ -558,7 +558,16 @@
                 ll_assert(freeblock > obj,
                           "freeblocks are linked out of order")
                 #
-                if ok_to_free_func(obj):
+                if self.offline_visited_flags:
+                    if self.visited_flags_limit_reached(obj, vblocknext):
+                        vblocknext = (
+                            self.get_64bit_limit_for_next_visited_flags(obj))
+                        vblock = self.fetch_64bit_visited_flags(obj)
+                    vblockmask = self.get_64bit_mask_visited_flag(obj)
+                    ok = not (vblock & vblockmask)
+                else:
+                    ok = ok_to_free_func(obj)
+                if ok:
                     #
                     # The object should die.
                     llarena.arena_reset(obj, _dummy_size(block_size), 0)
@@ -581,9 +590,6 @@
         # Update the global total size of objects.
         self.total_memory_used += r_uint(surviving * block_size)
         #
-        if self.offline_visited_flags:
-            self.reset_block_of_visited_flags_for_one_page(page)
-        #
         # Return the number of surviving objects.
         return surviving
 
@@ -615,46 +621,71 @@
 
     @staticmethod
     @always_inline
-    def get_visited(obj):
+    def get_64bit_ptr_visited_flags(obj):
         numeric = rffi.cast(lltype.Unsigned, obj)
         base = rffi.cast(rffi.CCHARP, numeric & ~(OFFL_ARENA_SIZE - 1))
-        ofs = (numeric // OFFL_RATIO) & (OFFL_SYSTEM_PAGE_SIZE - 1)
-        singlebit = 1 << ((numeric // (OFFL_RATIO/8)) & 7)
-        return (ord(base[ofs]) & singlebit) != 0
+        ofs = (numeric // OFFL_RATIO) & (OFFL_SYSTEM_PAGE_SIZE - 8)
+        return rffi.cast(rffi.ULONGLONGP, rffi.ptradd(base, ofs))
+
+    @staticmethod
+    @always_inline
+    def get_64bit_mask_visited_flag(obj):
+        numeric = rffi.cast(lltype.Unsigned, obj)
+        shift = (numeric // (OFFL_RATIO/8)) & 63
+        return rffi.cast(rffi.ULONGLONG, 1) << shift
+
+    @staticmethod
+    @always_inline
+    def get_visited(obj):
+        """test the visited flag corresponding to 'obj'"""
+        p = ArenaCollection.get_64bit_ptr_visited_flags(obj)
+        mask = ArenaCollection.get_64bit_mask_visited_flag(obj)
+        return (p[0] & mask) != 0
 
     @staticmethod
     @always_inline
     def set_visited(obj):
-        numeric = rffi.cast(lltype.Unsigned, obj)
-        base = rffi.cast(rffi.CCHARP, numeric & ~(OFFL_ARENA_SIZE - 1))
-        ofs = (numeric // OFFL_RATIO) & (OFFL_SYSTEM_PAGE_SIZE - 1)
-        singlebit = 1 << ((numeric // (OFFL_RATIO/8)) & 7)
-        base[ofs] = chr(ord(base[ofs]) | singlebit)
+        """set (to 1) the visited flag corresponding to 'obj'"""
+        p = ArenaCollection.get_64bit_ptr_visited_flags(obj)
+        mask = ArenaCollection.get_64bit_mask_visited_flag(obj)
+        p[0] |= mask
 
     @staticmethod
     @always_inline
     def clear_visited(obj):
-        numeric = rffi.cast(lltype.Unsigned, obj)
-        base = rffi.cast(rffi.CCHARP, numeric & ~(OFFL_ARENA_SIZE - 1))
-        ofs = (numeric // OFFL_RATIO) & (OFFL_SYSTEM_PAGE_SIZE - 1)
-        singlebit = 1 << ((numeric // (OFFL_RATIO/8)) & 7)
-        base[ofs] = chr(ord(base[ofs]) & ~singlebit)
+        """clear the visited flag corresponding to 'obj'"""
+        # (Note: should not be used too often.  Due to the fact that the
+        # same flag might be used for two objects if they are a single
+        # word each, this might occasionally clear too much.  It is
+        # still fine in this case because we clear the flag only to
+        # force re-visiting the object later during major collection)
+        p = ArenaCollection.get_64bit_ptr_visited_flags(obj)
+        mask = ArenaCollection.get_64bit_mask_visited_flag(obj)
+        p[0] &= ~mask
 
     @staticmethod
     @always_inline
-    def get_unvisited(obj):
+    def get_64bit_limit_for_next_visited_flags(obj):
+        """get a result that encodes the last possible position of an
+        object after 'obj' where the corresponding visited flag is in
+        the same 64-bit block as 'obj'."""
         numeric = rffi.cast(lltype.Unsigned, obj)
-        base = rffi.cast(rffi.CCHARP, numeric & ~(OFFL_ARENA_SIZE - 1))
-        ofs = (numeric // OFFL_RATIO) & (OFFL_SYSTEM_PAGE_SIZE - 1)
-        singlebit = 1 << ((numeric // (OFFL_RATIO/8)) & 7)
-        return (ord(base[ofs]) & singlebit) == 0
+        return numeric | (64 * OFFL_RATIO / 8 - 1)
 
     @staticmethod
-    def reset_block_of_visited_flags_for_one_page(page):
-        numeric = rffi.cast(lltype.Unsigned, page)
-        base = rffi.cast(rffi.CCHARP, numeric & ~(OFFL_ARENA_SIZE - 1))
-        ofs = (numeric // OFFL_RATIO) & (OFFL_SYSTEM_PAGE_SIZE - 1)
-        rpy_memset(base, 0, OFFL_SYSTEM_PAGE_SIZE // OFFL_RATIO)
+    @always_inline
+    def visited_flags_limit_reached(obj, vblocknext):
+        """return True if 'obj' is beyond the limit computed by
+        get_64bit_limit_for_next_visited_flags()."""
+        return rffi.cast(lltype.Unsigned, obj) > vblocknext
+
+    @staticmethod
+    @always_inline
+    def fetch_64bit_visited_flags(obj):
+        p = ArenaCollection.get_64bit_ptr_visited_flags(obj)
+        result = p[0]
+        p[0] = rffi.cast(rffi.ULONGLONG, 0)
+        return result
 
 
 # ____________________________________________________________
@@ -748,7 +779,7 @@
     void *p = mmap(NULL, map_size, PROT_READ | PROT_WRITE,
                    MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
     if (p == MAP_FAILED) {
-        perror("Fatal RPython error: mmap");
+        perror("Fatal RPython error: out of memory");
         abort();
     }
 
@@ -776,7 +807,3 @@
 rpy_free_arena = rffi.llexternal(
     'rpy_free_arena', [llmemory.Address], lltype.Void,
     compilation_info=eci, _nowrapper=True)
-
-rpy_memset = rffi.llexternal(
-    'memset', [rffi.CCHARP, lltype.Signed, lltype.Signed], lltype.Void,
-    _nowrapper=True)


More information about the pypy-commit mailing list