[pypy-commit] pypy gc-minimark-pinning: enough support for nursery_barriers to pass one test, still xxx left
fijal
noreply at buildbot.pypy.org
Thu Apr 12 22:02:18 CEST 2012
Author: Maciej Fijalkowski <fijall at gmail.com>
Branch: gc-minimark-pinning
Changeset: r54316:399757c26f46
Date: 2012-04-12 22:01 +0200
http://bitbucket.org/pypy/pypy/changeset/399757c26f46/
Log: enough support for nursery_barriers to pass one test, still xxx left
diff --git a/pypy/rpython/memory/gc/minimark.py b/pypy/rpython/memory/gc/minimark.py
--- a/pypy/rpython/memory/gc/minimark.py
+++ b/pypy/rpython/memory/gc/minimark.py
@@ -305,12 +305,10 @@
# GCFLAG_HAS_SHADOW to their future location at the next
# minor collection.
self.nursery_objects_shadows = self.AddressDict()
- # all pinned objects in the nursery
- self.pinned_objects = self.AddressStack()
# all pinned objects that were in the nursery *before* last
# minor collect. This is a sorted stack that should be consulted when
# considering next nursery ceiling
- self.nursery_barriers = self.AddressStack()
+ self.nursery_barriers = self.AddressDeque()
#
# Allocate a nursery. In case of auto_nursery_size, start by
@@ -452,6 +450,7 @@
def debug_rotate_nursery(self):
if self.debug_rotating_nurseries is not None:
+ ll_assert(self.nursery_barriers.empty(), "non empty nursery barriers with rotating nursery")
debug_start("gc-debug")
oldnurs = self.nursery
llarena.arena_protect(oldnurs, self._nursery_memory_size(), True)
@@ -587,22 +586,27 @@
and finally reserve 'totalsize' bytes at the start of the
now-empty nursery.
"""
- self.minor_collection()
+ if not self.nursery_top == self.nursery + self.nursery_size:
+ xxx
+ self.minor_collection(totalsize)
+ # try allocating now, otherwise we do a major collect
+ do_major_collect = False
#
- if self.get_total_memory_used() > self.next_major_collection_threshold:
+ if do_major_collect or (self.get_total_memory_used() > self.next_major_collection_threshold):
self.major_collection()
#
# The nursery might not be empty now, because of
# execute_finalizers(). If it is almost full again,
# we need to fix it with another call to minor_collection().
if self.nursery_free + totalsize > self.nursery_top:
- self.minor_collection()
+ self.minor_collection(totalsize)
#
result = self.nursery_free
self.nursery_free = result + totalsize
ll_assert(self.nursery_free <= self.nursery_top, "nursery overflow")
#
if self.debug_tiny_nursery >= 0: # for debugging
+ ll_assert(not self.nursery_barriers.non_empty(), "no support for nursery debug and pinning")
if self.nursery_top - self.nursery_free > self.debug_tiny_nursery:
self.nursery_free = self.nursery_top - self.debug_tiny_nursery
#
@@ -1245,7 +1249,7 @@
# ----------
# Nursery collection
- def minor_collection(self):
+ def minor_collection(self, min_size=0):
"""Perform a minor collection: find the objects from the nursery
that remain alive and move them out."""
#
@@ -1303,9 +1307,34 @@
#
# All live nursery objects are out, and the rest dies. Fill
# the whole nursery with zero and reset the current nursery pointer.
- llarena.arena_reset(self.nursery, self.nursery_size, 2)
+ # self.nursery_barriers are *not* freed
+ # XXX sort the nursery_barriers
+ new_barriers = self.AddressDeque()
+ prev = self.nursery
+ size_gc_header = self.gcheaderbuilder.size_gc_header
+ while self.nursery_barriers.non_empty():
+ next = self.nursery_barriers.popleft()
+ llarena.arena_reset(prev, next - prev, 2)
+ # clean the visited flag
+ obj = next + size_gc_header
+ self.header(obj).tid &= ~GCFLAG_VISITED
+ prev = prev + (next - prev) + (size_gc_header +
+ self.get_size(obj))
+ new_barriers.append(next)
+ llarena.arena_reset(prev, self.nursery_top - prev, 2)
+ self.nursery_barriers.delete()
+ self.nursery_barriers = new_barriers
self.debug_rotate_nursery()
self.nursery_free = self.nursery
+ self.nursery_barriers.append(self.nursery + self.nursery_size)
+ self.nursery_top = self.nursery_barriers.popleft()
+ while self.nursery_barriers.non_empty() and self.nursery_free + min_size > self.nursery_top:
+ cur_obj_size = size_gc_header + self.get_size(self.nursery_free +
+ size_gc_header)
+ self.nursery_free = self.nursery_free + cur_obj_size
+ self.nursery_top = self.nursery_barriers.popleft()
+ if self.nursery_free + min_size > self.nursery_top:
+ ll_assert(False, "too many pinned objects")
#
debug_print("minor collect, total memory used:",
self.get_total_memory_used())
@@ -1442,7 +1471,16 @@
return
#
size_gc_header = self.gcheaderbuilder.size_gc_header
- if self.header(obj).tid & GCFLAG_HAS_SHADOW == 0:
+ if self.header(obj).tid & GCFLAG_PINNED:
+ hdr = self.header(obj)
+ if hdr.tid & GCFLAG_VISITED:
+ return
+ hdr.tid |= GCFLAG_VISITED
+ ll_assert(not self.header(obj).tid & GCFLAG_HAS_SHADOW, "support shadow with pinning")
+ ll_assert(not self.header(obj).tid & GCFLAG_HAS_CARDS, "support cards with pinning")
+ self.nursery_barriers.append(obj - size_gc_header)
+ return
+ elif self.header(obj).tid & GCFLAG_HAS_SHADOW == 0:
#
# Common case: 'obj' was not already forwarded (otherwise
# tid == -42, containing all flags), and it doesn't have the
diff --git a/pypy/rpython/memory/test/test_gc.py b/pypy/rpython/memory/test/test_gc.py
--- a/pypy/rpython/memory/test/test_gc.py
+++ b/pypy/rpython/memory/test/test_gc.py
@@ -6,8 +6,7 @@
from pypy.rpython.test.test_llinterp import get_interpreter
from pypy.rpython.lltypesystem import lltype
from pypy.rpython.lltypesystem.lloperation import llop
-from pypy.rlib.objectmodel import we_are_translated
-from pypy.rlib.objectmodel import compute_unique_id
+from pypy.rlib.objectmodel import we_are_translated, compute_unique_id
from pypy.rlib import rgc
from pypy.rlib.rstring import StringBuilder
from pypy.rlib.rarithmetic import LONG_BIT
@@ -938,5 +937,34 @@
GC_CAN_MALLOC_NONMOVABLE = True
BUT_HOW_BIG_IS_A_BIG_STRING = 11*WORD
+ # those tests are here because they'll be messy and useless
+ # on GCs that can't pin objects
+
+ def test_pinning_collect(self):
+ from pypy.rpython.lltypesystem import llmemory
+
+ TP = lltype.GcStruct('x', ('x', lltype.Signed), ('y', lltype.Signed))
+
+ def f(i):
+ e = lltype.malloc(TP)
+ e.x = 3
+ prev = llmemory.cast_ptr_to_adr(e)
+ rgc.pin(e)
+ for k in range(i):
+ lltype.malloc(TP)
+ res = int(llmemory.cast_ptr_to_adr(e) == prev)
+ for k in range(i):
+ lltype.malloc(TP)
+ res += int(llmemory.cast_ptr_to_adr(e) == prev)
+ assert e.x == 3 # noone overwrote it
+ rgc.unpin(e)
+ for k in range(i):
+ lltype.malloc(TP)
+ assert e.x == 3 # noone overwrote it
+ return res
+
+ res = self.interpret(f, [10])
+ assert res == 2
+
class TestMiniMarkGCCardMarking(TestMiniMarkGC):
GC_PARAMS = {'card_page_indices': 4}
More information about the pypy-commit
mailing list