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