[pypy-commit] pypy gc-forkfriendly-2: Move offline the 'nextpage' pointer from each page

arigo pypy.commits at gmail.com
Fri Feb 24 09:00:42 EST 2017


Author: Armin Rigo <arigo at tunes.org>
Branch: gc-forkfriendly-2
Changeset: r90338:42e9fc22ba08
Date: 2017-02-24 14:59 +0100
http://bitbucket.org/pypy/pypy/changeset/42e9fc22ba08/

Log:	Move offline the 'nextpage' pointer from each page

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
@@ -62,14 +62,6 @@
 
 PAGE_PTR = lltype.Ptr(lltype.ForwardReference())
 PAGE_HEADER = lltype.Struct('PageHeader',
-    # -- The following pointer makes a chained list of pages.  For non-full
-    #    pages, it is a chained list of pages having the same size class,
-    #    rooted in 'page_for_size[size_class]'.  For full pages, it is a
-    #    different chained list rooted in 'full_page_for_size[size_class]'.
-    #    For free pages, it is the list 'freepages' in the arena header.
-    ('nextpage', PAGE_PTR),
-    # -- The arena this page is part of.
-    ('arena', ARENA_PTR),
     # -- The number of free blocks.  The numbers of uninitialized and
     #    allocated blocks can be deduced from the context if needed.
     ('nfree', lltype.Signed),
@@ -77,11 +69,24 @@
     #    first uninitialized block (pointing to data that is uninitialized,
     #    or to the end of the page).
     ('freeblock', llmemory.Address),
+    # -- The following pointer makes a chained list of pages.  For non-full
+    #    pages, it is a chained list of pages having the same size class,
+    #    rooted in 'page_for_size[size_class]'.  For full pages, it is a
+    #    different chained list rooted in 'full_page_for_size[size_class]'.
+    #    For free pages, it is the list 'freepages' in the arena header.
+    # == NOTE: with offline_visited_flags, this pointer contains an
+    #    indirection.  It is only written once, and so it must not be
+    #    the first word of the page, because that is overwritten with
+    #    a chained list when the page becomes free again.
+    ('nextpage', llmemory.Address),
+    # -- The arena this page is part of.
+    ('arena', ARENA_PTR),
     # -- The structure above is 4 words, which is a good value:
     #    '(1024-4) % N' is zero or very small for various small N's,
     #    i.e. there is not much wasted space.
     )
 PAGE_PTR.TO.become(PAGE_HEADER)
+PAGE_PTR_PTR = rffi.CArrayPtr(PAGE_PTR)
 PAGE_NULL = lltype.nullptr(PAGE_HEADER)
 
 # ----------
@@ -153,6 +158,13 @@
         # the additional bookkeeping stuff.
         self.total_memory_used = r_uint(0)
 
+        if not offline_visited_flags:
+            self.ARENA_WITH_OFFL = ARENA
+        else:
+            self.ARENA_WITH_OFFL = lltype.Struct('ArenaReferenceOffl',
+                ('arena_super', ARENA),
+                ('nextindirections', lltype.Array(PAGE_PTR)))
+
 
     def _new_page_ptr_list(self, length):
         return lltype.malloc(rffi.CArray(PAGE_PTR), length,
@@ -195,8 +207,8 @@
         if freeblock - pageaddr > self.page_size - nsize:
             # This was the last free block, so unlink the page from the
             # chained list and put it in the 'full_page_for_size' list.
-            self.page_for_size[size_class] = page.nextpage
-            page.nextpage = self.full_page_for_size[size_class]
+            self.page_for_size[size_class] = self.getnextpage(page)
+            self.setnextpage(page, self.full_page_for_size[size_class])
             self.full_page_for_size[size_class] = page
         #
         llarena.arena_reserve(result, _dummy_size(size))
@@ -227,6 +239,17 @@
             ll_assert(self.num_uninitialized_pages > 0,
                       "fully allocated arena found in self.current_arena")
             self.num_uninitialized_pages -= 1
+            #
+            if self.offline_visited_flags:
+                # initialize the 'page.nextpage' indirection
+                arena_with_offl = lltype.cast_pointer(
+                    lltype.Ptr(self.ARENA_WITH_OFFL), arena)
+                array = arena_with_offl.nextindirections
+                array = lltype.direct_arrayitems(array)
+                p = lltype.direct_ptradd(array, self.num_uninitialized_pages)
+                page = llmemory.cast_adr_to_ptr(result, PAGE_PTR)
+                page.nextpage = llmemory.cast_ptr_to_adr(p)
+            #
             if self.num_uninitialized_pages > 0:
                 freepages = result + self.page_size
             else:
@@ -248,7 +271,7 @@
         page.arena = arena
         page.nfree = 0
         page.freeblock = result + self.hdrsize
-        page.nextpage = PAGE_NULL
+        self.setnextpage(page, PAGE_NULL)
         ll_assert(self.page_for_size[size_class] == PAGE_NULL,
                   "allocate_new_page() called but a page is already waiting")
         self.page_for_size[size_class] = page
@@ -327,7 +350,12 @@
             arena_base.arena._from_minimarkpage = True
         #
         # Allocate an ARENA object and initialize it
-        arena = lltype.malloc(ARENA, flavor='raw', track_allocation=False)
+        if not self.offline_visited_flags:
+            arena = lltype.malloc(ARENA, flavor='raw', track_allocation=False)
+        else:
+            arena_with_offl = lltype.malloc(self.ARENA_WITH_OFFL, npages,
+                                         flavor='raw', track_allocation=False)
+            arena = arena_with_offl.arena_super
         arena.base = arena_base
         arena.nfreepages = 0        # they are all uninitialized pages
         arena.totalpages = npages
@@ -458,7 +486,7 @@
                 #
                 # Collect the page.
                 surviving = self.walk_page(page, block_size, ok_to_free_func)
-                nextpage = page.nextpage
+                nextpage = self.getnextpage(page)
                 #
                 if surviving == nblocks:
                     #
@@ -466,14 +494,14 @@
                     # 'remaining_full_pages' chained list.
                     ll_assert(step == 0,
                               "A non-full page became full while freeing")
-                    page.nextpage = remaining_full_pages
+                    self.setnextpage(page, remaining_full_pages)
                     remaining_full_pages = page
                     #
                 elif surviving > 0:
                     #
                     # There is at least 1 object surviving.  Re-insert
                     # the page in the 'remaining_partial_pages' chained list.
-                    page.nextpage = remaining_partial_pages
+                    self.setnextpage(page, remaining_partial_pages)
                     remaining_partial_pages = page
                     #
                 else:
@@ -619,6 +647,21 @@
         return getattr(arena, '_from_minimarkpage', False)
 
 
+    @always_inline
+    def getnextpage(self, page):
+        if not self.offline_visited_flags:
+            return llmemory.cast_adr_to_ptr(page.nextpage, PAGE_PTR)
+        else:
+            return llmemory.cast_adr_to_ptr(page.nextpage, PAGE_PTR_PTR)[0]
+
+    @always_inline
+    def setnextpage(self, page, nextp):
+        if not self.offline_visited_flags:
+            page.nextpage = llmemory.cast_ptr_to_adr(nextp)
+        else:
+            llmemory.cast_adr_to_ptr(page.nextpage, PAGE_PTR_PTR)[0] = nextp
+
+
     @staticmethod
     @always_inline
     def get_64bit_ptr_visited_flags(obj):
diff --git a/rpython/memory/gc/test/test_minimarkpage.py b/rpython/memory/gc/test/test_minimarkpage.py
--- a/rpython/memory/gc/test/test_minimarkpage.py
+++ b/rpython/memory/gc/test/test_minimarkpage.py
@@ -38,7 +38,7 @@
         assert page.nfree == 0
         page1 = page.freeblock - hdrsize
         assert llmemory.cast_ptr_to_adr(page) == page1
-        assert page.nextpage == PAGE_NULL
+        assert ac.getnextpage(page) == PAGE_NULL
     #
     ac = ArenaCollection(arenasize, pagesize, 99)
     assert ac.num_uninitialized_pages == 0
@@ -83,7 +83,7 @@
             chainedlists = ac.page_for_size
         else:
             chainedlists = ac.full_page_for_size
-        page.nextpage = chainedlists[size_class]
+        ac.setnextpage(page, chainedlists[size_class])
         page.arena = ac.current_arena
         chainedlists[size_class] = page
         if fill_with_objects:
@@ -285,7 +285,7 @@
                                hdrsize + 2*WORD: False}
     page = getpage(ac, 0)
     assert page == ac.page_for_size[2]
-    assert page.nextpage == PAGE_NULL
+    assert ac.getnextpage(page) == PAGE_NULL
     assert ac._nuninitialized(page, 2) == 1
     assert page.nfree == 0
     chkob(ac, 0, 4*WORD, page.freeblock)
@@ -313,7 +313,7 @@
                                hdrsize + 4*WORD: False}
     page = getpage(ac, 0)
     assert page == ac.full_page_for_size[2]
-    assert page.nextpage == PAGE_NULL
+    assert ac.getnextpage(page) == PAGE_NULL
     assert ac._nuninitialized(page, 2) == 0
     assert page.nfree == 0
     assert freepages(ac) == NULL
@@ -331,7 +331,7 @@
     page = getpage(ac, 0)
     pageaddr = pagenum(ac, 0)
     assert page == ac.page_for_size[2]
-    assert page.nextpage == PAGE_NULL
+    assert ac.getnextpage(page) == PAGE_NULL
     assert ac._nuninitialized(page, 2) == 0
     assert page.nfree == 2
     assert page.freeblock == pageaddr + hdrsize + 2*WORD
@@ -356,7 +356,7 @@
     page = getpage(ac, 0)
     pageaddr = pagenum(ac, 0)
     assert page == ac.page_for_size[2]
-    assert page.nextpage == PAGE_NULL
+    assert ac.getnextpage(page) == PAGE_NULL
     assert ac._nuninitialized(page, 2) == 4
     assert page.nfree == 4
     assert page.freeblock == pageaddr + hdrsize + 2*WORD
@@ -384,7 +384,7 @@
     page = getpage(ac, 0)
     pageaddr = pagenum(ac, 0)
     assert page == ac.page_for_size[2]
-    assert page.nextpage == PAGE_NULL
+    assert ac.getnextpage(page) == PAGE_NULL
     assert ac._nuninitialized(page, 2) == 4
     assert page.nfree == 6
     fb = page.freeblock


More information about the pypy-commit mailing list