Author: Maciej Fijalkowski <[email protected]>
Branch: incremental-nursery-cleanup
Changeset: r60693:7291c14e7c4a
Date: 2013-01-29 18:13 +0200
http://bitbucket.org/pypy/pypy/changeset/7291c14e7c4a/
Log: clean nursery in stages
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
@@ -341,6 +354,10 @@
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:
+ self.nursery_cleanup = nursery_cleanup
#
major_coll = env.read_float_from_env('PYPY_GC_MAJOR_COLLECT')
if major_coll > 1.0:
@@ -394,7 +411,8 @@
# the current position in the nursery:
self.nursery_free = self.nursery
# the end of the nursery:
- 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
# initialize the threshold
self.min_heap_size = max(self.min_heap_size, self.nursery_size *
self.major_collection_threshold)
@@ -458,7 +476,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)
@@ -501,7 +520,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)
@@ -560,7 +579,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)
@@ -579,12 +598,22 @@
if gen > 0:
self.major_collection()
- def collect_and_reserve(self, totalsize):
+ def move_nursery_top_and_malloc(self, totalsize):
+ llarena.arena_reset(self.nursery_top, self.nursery_cleanup, 2)
+ self.nursery_top += self.nursery_cleanup
+
+ 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_and_malloc(totalsize)
+ return prev_result
self.minor_collection()
#
if self.get_total_memory_used() > self.next_major_collection_threshold:
@@ -756,7 +785,7 @@
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_free = self.nursery_real_top
def can_malloc_nonmovable(self):
return True
@@ -836,7 +865,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?"
@@ -856,7 +885,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'
@@ -1263,10 +1292,12 @@
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
#
debug_print("minor collect, total memory used:",
self.get_total_memory_used())
@@ -1826,10 +1857,10 @@
ll_assert(reserved_size <= self.nonlarge_max,
"set_extra_threshold: too big!")
diff = reserved_size - self.extra_threshold
- if diff > 0 and self.nursery_free + diff > self.nursery_top:
+ if diff > 0 and self.nursery_free + diff > self.nursery_real_top:
self.minor_collection()
self.nursery_size -= diff
- self.nursery_top -= diff
+ self.nursery_real_top -= diff
self.extra_threshold += diff
_______________________________________________
pypy-commit mailing list
[email protected]
http://mail.python.org/mailman/listinfo/pypy-commit