[pypy-commit] pypy jitframe-on-heap: merge incremental-nursery-cleanup
fijal
noreply at buildbot.pypy.org
Sat Feb 2 23:36:54 CET 2013
Author: Maciej Fijalkowski <fijall at gmail.com>
Branch: jitframe-on-heap
Changeset: r60827:74a3226a59c6
Date: 2013-02-03 00:35 +0200
http://bitbucket.org/pypy/pypy/changeset/74a3226a59c6/
Log: merge incremental-nursery-cleanup
diff --git a/rpython/rtyper/memory/gc/minimark.py b/rpython/rtyper/memory/gc/minimark.py
--- a/rpython/rtyper/memory/gc/minimark.py
+++ b/rpython/rtyper/memory/gc/minimark.py
@@ -2,41 +2,45 @@
Environment variables can be used to fine-tune the following parameters:
- PYPY_GC_NURSERY The nursery size. Defaults to '4MB'. Small values
- (like 1 or 1KB) are useful for debugging.
+ PYPY_GC_NURSERY The nursery size. Defaults to '4MB'. Small values
+ (like 1 or 1KB) are useful for debugging.
- PYPY_GC_MAJOR_COLLECT Major collection memory factor. Default is '1.82',
- which means trigger a major collection when the
- memory consumed equals 1.82 times the memory
- really used at the end of the previous major
- collection.
+ PYPY_GC_NURSERY_CLEANUP The interval at which nursery is cleaned up. Must
+ be smaller than the nursery size and bigger than the
+ biggest object we can allotate in the nursery.
- PYPY_GC_GROWTH Major collection threshold's max growth rate.
- Default is '1.4'. Useful to collect more often
- than normally on sudden memory growth, e.g. when
- there is a temporary peak in memory usage.
+ PYPY_GC_MAJOR_COLLECT Major collection memory factor. Default is '1.82',
+ which means trigger a major collection when the
+ memory consumed equals 1.82 times the memory
+ really used at the end of the previous major
+ collection.
- PYPY_GC_MAX The max heap size. If coming near this limit, it
- will first collect more often, then raise an
- RPython MemoryError, and if that is not enough,
- crash the program with a fatal error. Try values
- like '1.6GB'.
+ PYPY_GC_GROWTH Major collection threshold's max growth rate.
+ Default is '1.4'. Useful to collect more often
+ than normally on sudden memory growth, e.g. when
+ there is a temporary peak in memory usage.
- PYPY_GC_MAX_DELTA The major collection threshold will never be set
- to more than PYPY_GC_MAX_DELTA the amount really
- used after a collection. Defaults to 1/8th of the
- total RAM size (which is constrained to be at most
- 2/3/4GB on 32-bit systems). Try values like '200MB'.
+ PYPY_GC_MAX The max heap size. If coming near this limit, it
+ will first collect more often, then raise an
+ RPython MemoryError, and if that is not enough,
+ crash the program with a fatal error. Try values
+ like '1.6GB'.
- PYPY_GC_MIN Don't collect while the memory size is below this
- limit. Useful to avoid spending all the time in
- the GC in very small programs. Defaults to 8
- times the nursery.
+ PYPY_GC_MAX_DELTA The major collection threshold will never be set
+ to more than PYPY_GC_MAX_DELTA the amount really
+ used after a collection. Defaults to 1/8th of the
+ total RAM size (which is constrained to be at most
+ 2/3/4GB on 32-bit systems). Try values like '200MB'.
- PYPY_GC_DEBUG Enable extra checks around collections that are
- too slow for normal use. Values are 0 (off),
- 1 (on major collections) or 2 (also on minor
- collections).
+ PYPY_GC_MIN Don't collect while the memory size is below this
+ limit. Useful to avoid spending all the time in
+ the GC in very small programs. Defaults to 8
+ times the nursery.
+
+ PYPY_GC_DEBUG Enable extra checks around collections that are
+ too slow for normal use. Values are 0 (off),
+ 1 (on major collections) or 2 (also on minor
+ collections).
"""
# XXX Should find a way to bound the major collection threshold by the
# XXX total addressable size. Maybe by keeping some minimarkpage arenas
@@ -208,11 +212,18 @@
# minimal allocated size of the nursery is 2x the following
# number (by default, at least 132KB on 32-bit and 264KB on 64-bit).
"large_object": (16384+512)*WORD,
+
+ # This is the chunk that we cleanup in the nursery. The point is
+ # to avoid having to trash all the caches just to zero the nursery,
+ # so we trade it by cleaning it bit-by-bit, as we progress through
+ # nursery. Has to fit at least one large object
+ "nursery_cleanup": 32768 * WORD,
}
def __init__(self, config,
read_from_env=False,
nursery_size=32*WORD,
+ nursery_cleanup=8*WORD,
page_size=16*WORD,
arena_size=64*WORD,
small_request_threshold=5*WORD,
@@ -226,6 +237,7 @@
assert small_request_threshold % WORD == 0
self.read_from_env = read_from_env
self.nursery_size = nursery_size
+ self.nursery_cleanup = nursery_cleanup
self.small_request_threshold = small_request_threshold
self.major_collection_threshold = major_collection_threshold
self.growth_rate_max = growth_rate_max
@@ -248,6 +260,7 @@
self.nursery = NULL
self.nursery_free = NULL
self.nursery_top = NULL
+ self.nursery_real_top = NULL
self.debug_tiny_nursery = -1
self.debug_rotating_nurseries = None
self.extra_threshold = 0
@@ -342,6 +355,12 @@
if newsize < minsize:
self.debug_tiny_nursery = newsize & ~(WORD-1)
newsize = minsize
+
+ nursery_cleanup = env.read_from_env('PYPY_GC_NURSERY_CLEANUP')
+ if nursery_cleanup > 0:
+ if nursery_cleanup < self.nonlarge_max + 1:
+ nursery_cleanup = self.nonlarge_max + 1
+ self.nursery_cleanup = nursery_cleanup
#
major_coll = env.read_float_from_env('PYPY_GC_MAJOR_COLLECT')
if major_coll > 1.0:
@@ -394,8 +413,9 @@
self.nursery = self._alloc_nursery()
# the current position in the nursery:
self.nursery_free = self.nursery
+ self.nursery_top = self.nursery + self.nursery_cleanup
# the end of the nursery:
- self.nursery_top = self.nursery + self.nursery_size
+ self.nursery_real_top = self.nursery + self.nursery_size
# initialize the threshold
self.min_heap_size = max(self.min_heap_size, self.nursery_size *
self.major_collection_threshold)
@@ -459,7 +479,8 @@
newnurs = self.debug_rotating_nurseries.pop(0)
llarena.arena_protect(newnurs, self._nursery_memory_size(), False)
self.nursery = newnurs
- self.nursery_top = self.nursery + self.nursery_size
+ self.nursery_top = self.nursery + self.nursery_cleanup
+ self.nursery_real_top = self.nursery + self.nursery_size
debug_print("switching from nursery", oldnurs,
"to nursery", self.nursery,
"size", self.nursery_size)
@@ -502,7 +523,7 @@
result = self.nursery_free
self.nursery_free = result + totalsize
if self.nursery_free > self.nursery_top:
- result = self.collect_and_reserve(totalsize)
+ result = self.collect_and_reserve(result, totalsize)
#
# Build the object.
llarena.arena_reserve(result, totalsize)
@@ -561,7 +582,7 @@
result = self.nursery_free
self.nursery_free = result + totalsize
if self.nursery_free > self.nursery_top:
- result = self.collect_and_reserve(totalsize)
+ result = self.collect_and_reserve(result, totalsize)
#
# Build the object.
llarena.arena_reserve(result, totalsize)
@@ -580,12 +601,24 @@
if gen > 0:
self.major_collection()
- def collect_and_reserve(self, totalsize):
+ def move_nursery_top(self, totalsize):
+ size = min(self.nursery_real_top - self.nursery_top,
+ self.nursery_cleanup)
+ llarena.arena_reset(self.nursery_top, size, 2)
+ self.nursery_top += size
+
+ def collect_and_reserve(self, prev_result, totalsize):
"""To call when nursery_free overflows nursery_top.
+ First check if the nursery_top is the real top, otherwise we
+ can just move the top of one cleanup and continue
+
Do a minor collection, and possibly also a major collection,
and finally reserve 'totalsize' bytes at the start of the
now-empty nursery.
"""
+ if self.nursery_top < self.nursery_real_top:
+ self.move_nursery_top(totalsize)
+ return prev_result
self.minor_collection()
#
if self.get_total_memory_used() > self.next_major_collection_threshold:
@@ -594,7 +627,7 @@
# 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:
+ if self.nursery_free + totalsize > self.nursery_real_top:
self.minor_collection()
#
result = self.nursery_free
@@ -757,7 +790,8 @@
if self.next_major_collection_threshold < 0:
# cannot trigger a full collection now, but we can ensure
# that one will occur very soon
- self.nursery_free = self.nursery_top
+ self.nursery_top = self.nursery_real_top
+ self.nursery_free = self.nursery_real_top
def can_malloc_nonmovable(self):
return True
@@ -837,7 +871,7 @@
def is_in_nursery(self, addr):
ll_assert(llmemory.cast_adr_to_int(addr) & 1 == 0,
"odd-valued (i.e. tagged) pointer unexpected here")
- return self.nursery <= addr < self.nursery_top
+ return self.nursery <= addr < self.nursery_real_top
def appears_to_be_young(self, addr):
# "is a valid addr to a young object?"
@@ -857,7 +891,7 @@
if not self.is_valid_gc_object(addr):
return False
- if self.nursery <= addr < self.nursery_top:
+ if self.nursery <= addr < self.nursery_real_top:
return True # addr is in the nursery
#
# Else, it may be in the set 'young_rawmalloced_objects'
@@ -1264,10 +1298,13 @@
self.free_young_rawmalloced_objects()
#
# 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)
+ # the nursery up to the cleanup point with zeros
+ llarena.arena_reset(self.nursery, self.nursery_size, 0)
+ llarena.arena_reset(self.nursery, self.nursery_cleanup, 2)
self.debug_rotate_nursery()
self.nursery_free = self.nursery
+ self.nursery_top = self.nursery + self.nursery_cleanup
+ self.nursery_real_top = self.nursery + self.nursery_size
#
debug_print("minor collect, total memory used:",
self.get_total_memory_used())
More information about the pypy-commit
mailing list