Author: Armin Rigo <[email protected]>
Branch: stm-gc-2
Changeset: r63204:8a6a4348b8c4
Date: 2013-04-10 20:18 +0200
http://bitbucket.org/pypy/pypy/changeset/8a6a4348b8c4/
Log: in-progress
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
@@ -27,18 +27,11 @@
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]'.
+ # -- The following pointer makes a chained list of pages.
('nextpage', PAGE_PTR),
- # -- The number of free blocks. The numbers of uninitialized and
- # allocated blocks can be deduced from the context if needed.
- ('nfree', lltype.Signed),
- # -- The chained list of free blocks. It ends as a pointer to the
- # first uninitialized block (pointing to data that is uninitialized,
- # or to the end of the page).
- ('freeblock', llmemory.Address),
+ # -- 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,
# i.e. there is not much wasted space.
@@ -96,93 +89,88 @@
self.sharedarea = sharedarea
self.chained_list = NULL
#
- # These two arrays contain each 'length' chained lists of pages.
+ # The array 'pages_for_size' contains 'length' chained lists
+ # of pages currently managed by this thread.
# For each size N between WORD and 'small_request_threshold'
# (included), the corresponding chained list contains pages
- # which store objects of size N. The 'page_for_size' lists are
- # for pages which still have room for at least one more object,
- # and the 'full_page_for_size' lists are for full pages.
+ # which store objects of size N.
length = sharedarea.small_request_threshold / WORD + 1
- self.page_for_size = lltype.malloc(rffi.CArray(PAGE_PTR), length,
- flavor='raw', zero=True,
- immortal=True)
- self.full_page_for_size = lltype.malloc(rffi.CArray(PAGE_PTR), length,
- flavor='raw', zero=True,
- immortal=True)
+ self.pages_for_size = lltype.malloc(
+ rffi.CArray(PAGE_PTR), length, flavor='raw', zero=True)
+ #
+ # This array contains 'length' chained lists of free object locations.
+ self.free_objects_for_size = lltype.malloc(
+ rffi.CArray(llmemory.Address), length, flavor='raw', zero=True)
#
if not we_are_translated():
self._seen_pages = set()
+ def free(self):
+ lltype.free(self.free_objects_for_size, flavor='raw')
+ lltype.free(self.pages_for_size, flavor='raw')
+ self.delete()
+
def _malloc_size_class(self, size_class):
"""Malloc one object of the given size_class (== number of WORDs)."""
ll_assert(size_class > 0, "malloc_size_class: null or neg size_class")
ll_assert(size_class <= self.sharedarea.small_request_threshold,
"malloc_size_class: too big")
#
- # Get the page to use
- page = self.page_for_size[size_class]
- if page == PAGE_NULL:
- page = self._allocate_new_page(size_class)
- #
- # The result is simply 'page.freeblock'
- result = page.freeblock
- nsize = size_class << WORD_POWER_2
- if page.nfree > 0:
- #
- # The 'result' was part of the chained list; read the next.
- page.nfree -= 1
- freeblock = result.address[0]
- llarena.arena_reset(result,
- llmemory.sizeof(llmemory.Address),
- 0)
- #
- else:
- # The 'result' is part of the uninitialized blocks.
- freeblock = result + nsize
- #
- page.freeblock = freeblock
- #
- pageaddr = llarena.getfakearenaaddress(llmemory.cast_ptr_to_adr(page))
- if freeblock - pageaddr > self.sharedarea.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.full_page_for_size[size_class] = page
- #
+ # The result is simply 'free_objects_for_size[size_class]'
+ result = self.free_objects_for_size[size_class]
+ if not result:
+ result = self._allocate_new_page(size_class)
+ self.free_objects_for_size[size_class] = result.address[0]
+ llarena.arena_reset(result, llmemory.sizeof(llmemory.Address), 0)
return result
+ _malloc_size_class._always_inline_ = True
+ def _free_size_class(self, obj, size_class):
+ """Free a single object 'obj', which is of the given size_class."""
+ # just link 'obj' to the start of 'free_objects_for_size[size_class]'
+ obj = llarena.getfakearenaaddress(obj)
+ llarena.arena_reset(obj, size_class << WORD_POWER_2, 0)
+ llarena.arena_reserve(obj, llmemory.sizeof(llmemory.Address))
+ obj.address[0] = self.free_objects_for_size[size_class]
+ self.free_objects_for_size[size_class] = obj
+ _free_size_class._always_inline_ = True
def _allocate_new_page(self, size_class):
"""Allocate and return a new page for the given size_class."""
#
- # If 'low_usage_page' has pages ready, return one of them.
- # Check both before acquiring the lock (NULL is the common case
- # and getting it occasionally wrong is not a problem), and after.
- result = NULL
- sharedarea = self.sharedarea
- if sharedarea.low_usage_page[size_class] != PAGE_NULL:
- XXX # self.ll_low_usage_lock...
- #
- # If unsuccessful, just raw-malloc a new page.
+ result = llarena.arena_malloc(self.sharedarea.page_size, 0)
if not result:
- result = llarena.arena_malloc(sharedarea.page_size, 0)
- if not result:
- fatalerror("FIXME: Out of memory! (should raise MemoryError)")
- return PAGE_NULL
- if not we_are_translated():
- self._seen_pages.add(result)
- llarena.arena_reserve(result, llmemory.sizeof(PAGE_HEADER))
+ fatalerror("FIXME: Out of memory! (should raise MemoryError)")
+ return PAGE_NULL
+ if not we_are_translated():
+ self._seen_pages.add(result)
+ llarena.arena_reserve(result, llmemory.sizeof(PAGE_HEADER))
#
# Initialize the fields of the resulting page
page = llmemory.cast_adr_to_ptr(result, PAGE_PTR)
- page.nfree = 0
- page.freeblock = result + sharedarea.hdrsize
- page.nextpage = 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
- return page
+ page.nextpage = self.pages_for_size[size_class]
+ self.pages_for_size[size_class] = page
+ #
+ # Initialize the chained list in the page
+ head = result + llmemory.sizeof(PAGE_HEADER)
+ ll_assert(not self.free_objects_for_size[size_class],
+ "free_objects_for_size is supposed to contain NULL here")
+ self.free_objects_for_size[size_class] = head
+ #
+ i = self.sharedarea.nblocks_for_size[size_class]
+ nsize = size_class << WORD_POWER_2
+ current = head
+ while True:
+ llarena.arena_reserve(current, llmemory.sizeof(llmemory.Address))
+ i -= 1
+ if i == 0:
+ break
+ next = current + nsize
+ current.address[0] = next
+ current = next
+ current.address[0] = llmemory.NULL
+ #
+ return head
def malloc_object(self, totalsize):
@@ -204,9 +192,14 @@
self.gc.set_obj_revision(obj, self.chained_list)
self.chained_list = obj
- def free_object(self, adr2):
- adr1 = adr2 - self.gc.gcheaderbuilder.size_gc_header
- llarena.arena_free(llarena.getfakearenaaddress(adr1))
+ def free_object(self, obj):
+ osize = self.gc.get_size_incl_hash(obj)
+ if osize <= self.sharedarea.small_request_threshold:
+ size_class = (osize + WORD_POWER_2 - 1) >> WORD_POWER_2
+ self._free_size_class(obj, size_class)
+ else:
+ adr1 = obj - self.gc.gcheaderbuilder.size_gc_header
+ llarena.arena_free(llarena.getfakearenaaddress(adr1))
def free_and_clear(self):
obj = self.chained_list
diff --git a/rpython/memory/gc/stmtls.py b/rpython/memory/gc/stmtls.py
--- a/rpython/memory/gc/stmtls.py
+++ b/rpython/memory/gc/stmtls.py
@@ -77,7 +77,7 @@
self._cleanup_state()
self._unregister_with_C_code()
self.local_weakrefs.delete()
- self.sharedarea_tls.delete()
+ self.sharedarea_tls.free()
self._free_nursery(self.nursery_start)
free_non_gc_object(self)
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
@@ -19,3 +19,25 @@
assert len(thl1._seen_pages) == 3
thl1.malloc_object(2*WORD)
assert len(thl1._seen_pages) == 3
+ thl1.free()
+
+class FakeGC:
+ def __init__(self):
+ self._object_sizes = {}
+ def set_size(self, obj, size):
+ assert obj not in self._object_sizes
+ self._object_sizes[obj] = size
+ def get_size_incl_hash(self, obj):
+ return self._object_sizes[obj]
+
+def test_free():
+ gc = FakeGC()
+ shared = StmGCSharedArea(gc, 10*WORD, 2*WORD)
+ shared.setup()
+ thl1 = StmGCThreadLocalAllocator(shared)
+ obj = thl1.malloc_object(2*WORD)
+ gc.set_size(obj, 2*WORD)
+ thl1.free_object(obj)
+ obj2 = thl1.malloc_object(2*WORD)
+ assert obj2 == obj # reusing the same location
+ thl1.free()
_______________________________________________
pypy-commit mailing list
[email protected]
http://mail.python.org/mailman/listinfo/pypy-commit