[pypy-commit] pypy concurrent-marksweep: test_many_objects passes again :-)
arigo
noreply at buildbot.pypy.org
Fri Jan 6 18:59:48 CET 2012
Author: Armin Rigo <arigo at tunes.org>
Branch: concurrent-marksweep
Changeset: r51075:4f6d92354eb2
Date: 2012-01-06 18:59 +0100
http://bitbucket.org/pypy/pypy/changeset/4f6d92354eb2/
Log: test_many_objects passes again :-)
diff --git a/pypy/rpython/memory/gc/concurrentgen.py b/pypy/rpython/memory/gc/concurrentgen.py
--- a/pypy/rpython/memory/gc/concurrentgen.py
+++ b/pypy/rpython/memory/gc/concurrentgen.py
@@ -172,8 +172,8 @@
newsize = min(newsize, (sys.maxint - 65535) // 4)
self.minimal_nursery_size = r_uint(newsize)
self.total_memory_size = r_uint(4 * newsize) # total size
- self.nursery_size = r_uint(newsize) # size of the '->new...' box
- self.old_objects_size = r_uint(0) # size of the 'old objs' box
+ self.nursery_size = r_uint(newsize) # size of the '->new...' box
+ self.old_objects_size = r_uint(0) # approx size of 'old objs' box
self.nursery_size_still_available = intmask(self.nursery_size)
def _teardown(self):
@@ -387,11 +387,11 @@
self.handle_big_allocation(additional_size)
return
#
- if self.collector.running <= 0:
- #
- # The previous collection finished. If necessary, synchronize
- # the main thread with it.
- self.sync_end_of_collection()
+ waiting_for_major_collection = self.collector.major_collection_phase != 0
+ #
+ if (self.collector.running == 0 or
+ self.stop_collection(wait=waiting_for_major_collection)):
+ # The previous collection finished.
#
# Expand the nursery if we can, up to 25% of total_memory_size.
# In some cases, the limiting factor is that the nursery size
@@ -413,16 +413,34 @@
# Else, we trigger the next minor collection now.
self._start_minor_collection()
#
- # Now there is no new object left. Reset the nursery size
- # to be 3/4*total_memory_size - old_objects_size, and no
- # more than 25% of total_memory_size.
- newsize = (self.total_memory_size >> 2) * 3 - self.old_objects_size
- newsize = min(newsize, self.total_memory_size >> 2)
- self.nursery_size = newsize
- self.nursery_size_still_available = newsize
- return
+ # Now there is no new object left. Reset the nursery size to
+ # be at most 25% of total_memory_size, and initially no more than
+ # 3/4*total_memory_size - old_objects_size. If that value is not
+ # positive, then we immediately go into major collection mode.
+ three_quarters = (self.total_memory_size >> 2) * 3
+ if self.old_objects_size < three_quarters:
+ newsize = three_quarters - self.old_objects_size
+ newsize = min(newsize, self.total_memory_size >> 2)
+ self.nursery_size = newsize
+ self.nursery_size_still_available = intmask(newsize)
+ return
- xxx
+ yyy
+
+ else:
+ # The previous collection is not finished yet.
+ # At this point we want a full collection to occur.
+ debug_start("gc-major")
+ #
+ # We have to first wait for the previous minor collection to finish:
+ debug_start("gc-major-wait")
+ self.stop_collection(wait=True)
+ debug_stop("gc-major-wait")
+ #
+ # Start the major collection.
+ self._start_major_collection()
+ #
+ debug_stop("gc-major")
def sync_end_of_collection(self):
@@ -441,8 +459,12 @@
"collector thread not paused?")
- def _stop_collection(self):
- self.acquire(self.finished_lock)
+ def stop_collection(self, wait):
+ if wait:
+ self.acquire(self.finished_lock)
+ else:
+ if not self.try_acquire(self.finished_lock):
+ return False
self.collector.running = 0
#debug_print("collector.running = 0")
#
@@ -454,6 +476,8 @@
#
if self.DEBUG:
self.debug_check_lists()
+ #
+ return True
def execute_finalizers_ll(self):
@@ -576,7 +600,7 @@
self._start_minor_collection(major_collection_phase=1)
#
# Wait for it to finish
- self._stop_collection()
+ self.stop_collection(wait=True)
#
# Assert that this list is still empty (cleared by the call to
# _start_minor_collection)
@@ -676,13 +700,16 @@
ll_thread.c_thread_acquirelock(lock, 1)
else:
assert ll_thread.get_ident() == self.main_thread_ident
- while rffi.cast(lltype.Signed,
- ll_thread.c_thread_acquirelock(lock, 0)) == 0:
+ while not self.try_acquire(lock):
time.sleep(0.05)
# ---------- EXCEPTION FROM THE COLLECTOR THREAD ----------
if hasattr(self.collector, '_exc_info'):
self._reraise_from_collector_thread()
+ def try_acquire(self, lock):
+ res = ll_thread.c_thread_acquirelock(lock, 0)
+ return rffi.cast(lltype.Signed, res) != 0
+
def release(self, lock):
ll_thread.c_thread_releaselock(lock)
@@ -793,6 +820,7 @@
# * collector.running == -1: Done.
# The mutex_lock is acquired to go from 1 to 2, and from 2 to 3.
self.running = 0
+ self.major_collection_phase = 0
#
# when the collection starts, we make all young objects aging and
# move 'new_young_objects' into 'aging_objects'
@@ -903,24 +931,22 @@
# Else release mutex_lock and try again.
self.release(self.mutex_lock)
#
- # When we sweep during minor collections, we subtract the size of
+ # When we sweep during minor collections, we add the size of
# the surviving now-old objects to the following field. Note
# that the write barrier may make objects young again, without
# decreasing the value here. During the following minor
- # collection this variable will be decreased *again*. When the
+ # collection this variable will be increased *again*. When the
# write barrier triggers on an aging object, it is random whether
# its size ends up being accounted here or not --- but it will
# be at the following minor collection, because the object is
- # young again. So, careful about underflows.
- sz = self.gc.size_still_available_before_major
- if sz < 0 or r_uint(sz) < surviving_size:
- sz = -1 # trigger major collect the next time
+ # young again. So, careful about overflows.
+ ll_assert(surviving_size <= self.gc.total_memory_size,
+ "surviving_size too large")
+ limit = self.gc.total_memory_size - surviving_size
+ if self.gc.old_objects_size <= limit:
+ self.gc.old_objects_size += surviving_size
else:
- # do the difference, which results in a non-negative number
- # (in particular, surviving_size <= sys.maxint here)
- sz -= intmask(surviving_size)
- #
- self.gc.size_still_available_before_major = sz
+ self.gc.old_objects_size = self.gc.total_memory_size
#
self.running = 2
#debug_print("collection_running = 2")
diff --git a/pypy/rpython/memory/gc/concurrentgen.txt b/pypy/rpython/memory/gc/concurrentgen.txt
--- a/pypy/rpython/memory/gc/concurrentgen.txt
+++ b/pypy/rpython/memory/gc/concurrentgen.txt
@@ -87,7 +87,7 @@
|it| free |< old objects |
+--+---------+----------------------------------+
-Then we do "Step 2+" above, forcing another synchronous minor
+Then we do "Step 2+" below, forcing another synchronous minor
collection. (This is the only time during which the main thread has to
wait for the collector to finish; hopefully it is a very minor issue,
because it occurs only at the start of a major collection, and we wait
More information about the pypy-commit
mailing list