Author: Armin Rigo <[email protected]>
Branch: stm-gc-2
Changeset: r63442:26a92a01a8dc
Date: 2013-04-16 14:43 +0200
http://bitbucket.org/pypy/pypy/changeset/26a92a01a8dc/

Log:    When the StmGCThreadLocalAllocator is deleted, reattach its pages to
        the StmGCSharedArea.

diff --git a/rpython/memory/gc/stmshared.py b/rpython/memory/gc/stmshared.py
--- a/rpython/memory/gc/stmshared.py
+++ b/rpython/memory/gc/stmshared.py
@@ -11,8 +11,9 @@
 
 # Linux's glibc is good at 'malloc(1023*WORD)': the blocks ("pages") it
 # returns are exactly 1024 words apart, reserving only one extra word
-# for its internal data
-TRANSLATED_PAGE_SIZE = 1023 * WORD
+# for its internal data.  Here we assume that even on other systems it
+# will not use more than two words.
+TRANSLATED_PAGE_SIZE = 1022 * WORD
 
 # This is the largest size that StmGCSharedArea will map to its internal
 # "pages" structures.
@@ -29,11 +30,11 @@
 PAGE_HEADER = lltype.Struct('PageHeader',
     # -- The following pointer makes a chained list of pages.
     ('nextpage', PAGE_PTR),
-    # -- XXX
-    ('xxx1', lltype.Signed),
-    ('xxx2', llmemory.Address),
-    # -- The structure above is 3 words, which is a good value:
-    #    '(1023-3) % N' is zero or very small for various small N's,
+    # -- The following is only used when the page belongs to StmGCSharedArea.
+    #    It makes another free list, used for various purposes.
+    ('secondary_free_list', llmemory.Address),
+    # -- The structure above is 2 words, which is a good value:
+    #    '(1022-2) % 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)
@@ -46,6 +47,7 @@
     _alloc_flavor_ = 'raw'
 
     def __init__(self, gc, page_size, small_request_threshold):
+        "NOT_RPYTHON"
         self.gc = gc
         self.page_size = page_size
         self.small_request_threshold = small_request_threshold
@@ -58,20 +60,32 @@
         # is used, or if its usage says high after a major collection,
         # it belongs to the lists of StmGCThreadLocalAllocator.
         length = small_request_threshold / WORD + 1
-        self.low_usage_page = lltype.malloc(rffi.CArray(PAGE_PTR), length,
-                                            flavor='raw', zero=True,
-                                            immortal=True)
+        self.low_usage_pages = lltype.malloc(rffi.CArray(PAGE_PTR), length,
+                                             flavor='raw', zero=True,
+                                             immortal=True)
+        self.full_pages = lltype.malloc(rffi.CArray(PAGE_PTR), length,
+                                        flavor='raw', zero=True,
+                                        immortal=True)
         self.nblocks_for_size = lltype.malloc(rffi.CArray(lltype.Signed),
-                                              length, flavor='raw',
+                                              length, flavor='raw', zero=True,
                                               immortal=True)
         self.hdrsize = llmemory.raw_malloc_usage(llmemory.sizeof(PAGE_HEADER))
-        self.nblocks_for_size[0] = 0    # unused
         for i in range(1, length):
             self.nblocks_for_size[i] = (page_size - self.hdrsize) // (WORD * i)
         assert self.nblocks_for_size[length-1] >= 1
+        self.length = length
+        #
+        # Counters for statistics
+        self.count_global_pages = 0
 
     def setup(self):
-        self.ll_low_usage_lock = rthread.allocate_ll_lock()
+        self.ll_global_lock = rthread.allocate_ll_lock()
+
+    def acquire_global_lock(self):
+        rthread.acquire_NOAUTO(self.ll_global_lock, True)
+
+    def release_global_lock(self):
+        rthread.release_NOAUTO(self.ll_global_lock)
 
 
 # ------------------------------------------------------------
@@ -94,10 +108,11 @@
         # For each size N between WORD and 'small_request_threshold'
         # (included), the corresponding chained list contains pages
         # which store objects of size N.
-        length = sharedarea.small_request_threshold / WORD + 1
+        length = sharedarea.length
         self.pages_for_size = lltype.malloc(
             rffi.CArray(PAGE_PTR), length, flavor='raw', zero=True,
             track_allocation=False)
+        self.count_pages = 0    # for statistics
         #
         # This array contains 'length' chained lists of free locations.
         self.free_loc_for_size = lltype.malloc(
@@ -141,6 +156,7 @@
             return NULL
         if not we_are_translated():
             self._seen_pages.add(result)
+        self.count_pages += 1
         llarena.arena_reserve(result, llmemory.sizeof(PAGE_HEADER))
         #
         # Initialize the fields of the resulting page
@@ -213,7 +229,27 @@
         while lst.non_empty():
             self.free_object(lst.pop())
 
+    def gift_all_pages_to_shared_area(self):
+        """Send to the shared area all my pages.  For now we don't extract
+        the information about which locations are free or not; we just stick
+        them into 'full_pages' and leave the next global GC to figure it out.
+        """
+        stmshared = self.sharedarea
+        stmshared.acquire_global_lock()
+        i = stmshared.length - 1
+        while i >= 1:
+            lpage = self.pages_for_size[i]
+            if lpage:
+                gpage = stmshared.full_pages[i]
+                gpage_addr = llmemory.cast_ptr_to_adr(gpage)
+                lpage.secondary_free_list = gpage_addr
+                stmshared.full_pages[i] = lpage
+            i -= 1
+        stmshared.count_global_pages += self.count_pages
+        stmshared.release_global_lock()
+
     def delete(self):
+        self.gift_all_pages_to_shared_area()
         lltype.free(self.free_loc_for_size, flavor='raw',
                     track_allocation=False)
         lltype.free(self.pages_for_size, flavor='raw',
diff --git a/rpython/memory/gc/test/test_stmshared.py 
b/rpython/memory/gc/test/test_stmshared.py
--- a/rpython/memory/gc/test/test_stmshared.py
+++ b/rpython/memory/gc/test/test_stmshared.py
@@ -17,7 +17,7 @@
 
 def test_simple():
     gc = FakeGC()
-    shared = StmGCSharedArea(gc, 10*WORD, 2*WORD)
+    shared = StmGCSharedArea(gc, 9*WORD, 2*WORD)
     shared.setup()
     thl1 = StmGCThreadLocalAllocator(shared)
     thl1.malloc_object(2*WORD-1)
@@ -32,11 +32,12 @@
     assert len(thl1._seen_pages) == 3
     thl1.malloc_object(2*WORD)
     assert len(thl1._seen_pages) == 3
+    assert thl1.count_pages == 3
     thl1.delete()
 
 def test_free():
     gc = FakeGC()
-    shared = StmGCSharedArea(gc, 10*WORD, 2*WORD)
+    shared = StmGCSharedArea(gc, 9*WORD, 2*WORD)
     shared.setup()
     thl1 = StmGCThreadLocalAllocator(shared)
     obj = thl1.malloc_object(2*WORD)
@@ -48,7 +49,7 @@
 
 def test_big_object():
     gc = FakeGC()
-    shared = StmGCSharedArea(gc, 10*WORD, 2*WORD)
+    shared = StmGCSharedArea(gc, 9*WORD, 2*WORD)
     shared.setup()
     thl1 = StmGCThreadLocalAllocator(shared)
     obj = thl1.malloc_object(3*WORD)
@@ -58,7 +59,7 @@
 
 def test_allocation_is_thread_local():
     gc = FakeGC()
-    shared = StmGCSharedArea(gc, 10*WORD, 2*WORD)
+    shared = StmGCSharedArea(gc, 9*WORD, 2*WORD)
     shared.setup()
     thl1 = StmGCThreadLocalAllocator(shared)
     thl2 = StmGCThreadLocalAllocator(shared)
@@ -73,3 +74,16 @@
     #
     thl1.delete()
     thl2.delete()
+
+def test_dying_gift_to_shared_area():
+    gc = FakeGC()
+    shared = StmGCSharedArea(gc, 9*WORD, 2*WORD)
+    shared.setup()
+    thl1 = StmGCThreadLocalAllocator(shared)
+    thl1.malloc_object(2*WORD)
+    assert thl1.count_pages == 1
+    assert len(thl1._seen_pages) == 1
+    #
+    assert shared.count_global_pages == 0
+    thl1.delete()
+    assert shared.count_global_pages == 1
_______________________________________________
pypy-commit mailing list
[email protected]
http://mail.python.org/mailman/listinfo/pypy-commit

Reply via email to