[pypy-svn] r77084 - in pypy/branch/gen2-gc/pypy/rpython/memory/gc: . test

arigo at codespeak.net arigo at codespeak.net
Wed Sep 15 13:45:51 CEST 2010


Author: arigo
Date: Wed Sep 15 13:45:50 2010
New Revision: 77084

Modified:
   pypy/branch/gen2-gc/pypy/rpython/memory/gc/minimarkpage.py
   pypy/branch/gen2-gc/pypy/rpython/memory/gc/test/test_minimarkpage.py
Log:
Test and write what occurs when a page becomes completely free.


Modified: pypy/branch/gen2-gc/pypy/rpython/memory/gc/minimarkpage.py
==============================================================================
--- pypy/branch/gen2-gc/pypy/rpython/memory/gc/minimarkpage.py	(original)
+++ pypy/branch/gen2-gc/pypy/rpython/memory/gc/minimarkpage.py	Wed Sep 15 13:45:50 2010
@@ -191,39 +191,76 @@
             # Pages completely freed are added to 'self.free_pages', and
             # become available for reuse by any size class.  Pages not
             # completely freed are re-chained in 'newlist'.
-            newlist = self.mass_free_in_list(self.page_for_size[size_class],
-                                             size_class, ok_to_free_func)
-            self.page_for_size[size_class] = newlist
+            self.mass_free_in_partial_list(size_class, ok_to_free_func)
             #
             size_class -= 1
 
 
-    def mass_free_in_list(self, page, size_class, ok_to_free_func):
-        remaining_list = page   #PAGE_NULL
+    def mass_free_in_partial_list(self, size_class, ok_to_free_func):
+        page = self.page_for_size[size_class]
         nblocks = self.nblocks_for_size[size_class]
         block_size = size_class * WORD
+        remaining_pages = PAGE_NULL
         #
         while page != PAGE_NULL:
-            self.walk_page(page, block_size, nblocks, ok_to_free_func)
-            page = page.nextpage
+            #
+            # Collect the page.
+            surviving = self.walk_page(page, block_size,
+                                       nblocks, ok_to_free_func)
+            nextpage = page.nextpage
+            #
+            if surviving > 0:
+                #
+                # Found at least 1 object surviving.  Re-insert the page
+                # in the chained list.
+                page.nextpage = remaining_pages
+                remaining_pages = page
+                #
+            else:
+                # No object survives; free the page.
+                self.free_page(page)
+
+            page = nextpage
         #
-        return remaining_list
+        self.page_for_size[size_class] = remaining_pages
+
+
+    def free_page(self, page):
+        """Free a whole page."""
+        #
+        # Done by inserting it in the 'free_pages' list.
+        pageaddr = llmemory.cast_ptr_to_adr(page)
+        pageaddr = llarena.getfakearenaaddress(pageaddr)
+        llarena.arena_reset(pageaddr, llmemory.sizeof(PAGE_HEADER), 0)
+        llarena.arena_reserve(pageaddr, llmemory.sizeof(llmemory.Address))
+        pageaddr.address[0] = self.free_pages
+        self.free_pages = pageaddr
 
 
     def walk_page(self, page, block_size, nblocks, ok_to_free_func):
         """Walk over all objects in a page, and ask ok_to_free_func()."""
         #
+        # 'freeblock' is the next free block, or NULL if there isn't any more.
         freeblock = page.freeblock
+        #
+        # 'prevfreeblockat' is the address of where 'freeblock' was read from.
+        prevfreeblockat = lltype.direct_fieldptr(page, 'freeblock')
+        prevfreeblockat = llmemory.cast_ptr_to_adr(prevfreeblockat)
+        #
         obj = llarena.getfakearenaaddress(llmemory.cast_ptr_to_adr(page))
         obj += self.hdrsize
-        surviving_count = 0
+        surviving = 0    # initially
         #
         nblocks -= page.nuninitialized
-        while nblocks > 0:
+        index = nblocks
+        while index > 0:
             #
             if obj == freeblock:
                 #
-                # 'obj' points to a free block.
+                # 'obj' points to a free block.  It means that
+                # 'prevfreeblockat.address[0]' does not need to be updated.
+                # Just read the next free block from 'obj.address[0]'.
+                prevfreeblockat = obj
                 freeblock = obj.address[0]
                 #
             else:
@@ -232,67 +269,29 @@
                           "freeblocks are linked out of order")
                 #
                 if ok_to_free_func(obj):
-                    xxx
+                    #
+                    # The object should die.
+                    llarena.arena_reset(obj, _dummy_size(block_size), 0)
+                    llarena.arena_reserve(obj,
+                                          llmemory.sizeof(llmemory.Address),
+                                          False)
+                    # Insert 'obj' in the linked list of free blocks.
+                    prevfreeblockat.address[0] = obj
+                    prevfreeblockat = obj
+                    obj.address[0] = freeblock
+                    #
                 else:
-                    # The object should survive.
-                    surviving_count += 1
+                    # The object survives.
+                    surviving += 1
             #
             obj += block_size
-            nblocks -= 1
+            index -= 1
         #
-        # Return the number of objects left
-        return surviving_count
-
-
-    def free(self, obj, size):
-        """Free a previously malloc'ed block."""
-        ll_assert(size > 0, "free: size is null or negative")
-        ll_assert(size <= self.small_request_threshold, "free: size too big")
-        ll_assert((size & (WORD-1)) == 0, "free: size is not aligned")
-        #
-        llarena.arena_reset(obj, _dummy_size(size), False)
-        pageaddr = start_of_page(obj, self.page_size)
-        if not we_are_translated():
-            hdrsize = llmemory.raw_malloc_usage(llmemory.sizeof(PAGE_HEADER))
-            assert obj - pageaddr >= hdrsize
-            assert (obj - pageaddr - hdrsize) % size == 0
-        page = llmemory.cast_adr_to_ptr(pageaddr, PAGE_PTR)
-        size_class = size / WORD
-        #
-        # Increment the number of known free objects
-        nfree = page.nfree + 1
-        if nfree < self.nblocks_for_size[size_class]:
-            #
-            # Not all objects in this page are freed yet.
-            # Add the free block to the chained list.
-            page.nfree = nfree
-            llarena.arena_reserve(obj, llmemory.sizeof(llmemory.Address),
-                                  False)
-            obj.address[0] = page.freeblock
-            page.freeblock = obj
-            #
-            # If the page was full, then it now has space and should be
-            # linked back in the page_for_size[] linked list.
-            if nfree == 1:
-                page.nextpage = self.page_for_size[size_class]
-                if page.nextpage != PAGE_NULL:
-                    page.nextpage.prevpage = page
-                self.page_for_size[size_class] = page
-            #
-        else:
-            # The page becomes completely free.  Remove it from
-            # the page_for_size[] linked list.
-            if page == self.page_for_size[size_class]:
-                self.page_for_size[size_class] = page.nextpage
-            else:
-                prev = page.prevpage
-                next = page.nextpage
-                prev.nextpage = next
-                next.prevpage = prev
-            #
-            # Free the page, putting it back in the chained list of the arena
-            # where it belongs
-            xxx#...
+        # Update the number of free objects.
+        page.nfree = nblocks - surviving
+        #
+        # Return the number of surviving objects.
+        return surviving
 
 
 # ____________________________________________________________

Modified: pypy/branch/gen2-gc/pypy/rpython/memory/gc/test/test_minimarkpage.py
==============================================================================
--- pypy/branch/gen2-gc/pypy/rpython/memory/gc/test/test_minimarkpage.py	(original)
+++ pypy/branch/gen2-gc/pypy/rpython/memory/gc/test/test_minimarkpage.py	Wed Sep 15 13:45:50 2010
@@ -213,3 +213,16 @@
     assert page.nuninitialized == 1
     assert page.nfree == 0
     chkob(ac, 0, 4*WORD, page.freeblock)
+    assert ac.free_pages == NULL
+
+def test_mass_free_emptied_page():
+    pagesize = hdrsize + 7*WORD
+    ac = arena_collection_for_test(pagesize, "2", fill_with_objects=2)
+    ok_to_free = OkToFree(ac, True)
+    ac.mass_free(ok_to_free)
+    assert ok_to_free.seen == [hdrsize + 0*WORD,
+                               hdrsize + 2*WORD]
+    pageaddr = pagenum(ac, 0)
+    assert pageaddr == ac.free_pages
+    assert pageaddr.address[0] == NULL
+    assert ac.page_for_size[2] == PAGE_NULL



More information about the Pypy-commit mailing list