Author: Armin Rigo <[email protected]>
Branch:
Changeset: r46116:e7121092d73f
Date: 2011-07-30 22:41 +0200
http://bitbucket.org/pypy/pypy/changeset/e7121092d73f/
Log: Fix the test. This gives a first approximation of the .NET
AddMemoryPressure(). This version is simpler than a counter that
needs to be carefully incremented and decremented by the exact same
amount. The idea is to use track_allocation=False to know when a
raw malloc is going to be attached to a GC object (good enough for
now). All such raw mallocs make the next major collection occur
earlier. So the major collection is triggered when
sum( GC object surviving minor collections + rawmallocs
with track_allocation=False ) > trigger
The raw mallocs are attached to GC objects with a __del__, which are
never allocated young, so they will survive at least until the major
collection. But if they survive for longer, they are ignored for
future major collections. This is again an approximation, but in
the "safe" way. Indeed, *not* ignoring them would simply mean
having a higher trigger, computed as (1.82*previous size).
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
@@ -390,6 +390,11 @@
# initialize the threshold
self.min_heap_size = max(self.min_heap_size, self.nursery_size *
self.major_collection_threshold)
+ # the following two values are usually equal, but during raw mallocs
+ # of arrays, next_major_collection_threshold is decremented to make
+ # the next major collection arrive earlier.
+ # See translator/c/test/test_newgc, test_nongc_attached_to_gc
+ self.next_major_collection_initial = self.min_heap_size
self.next_major_collection_threshold = self.min_heap_size
self.set_major_threshold_from(0.0)
debug_stop("gc-set-nursery-size")
@@ -397,7 +402,7 @@
def set_major_threshold_from(self, threshold, reserving_size=0):
# Set the next_major_collection_threshold.
- threshold_max = (self.next_major_collection_threshold *
+ threshold_max = (self.next_major_collection_initial *
self.growth_rate_max)
if threshold > threshold_max:
threshold = threshold_max
@@ -412,6 +417,7 @@
else:
bounded = False
#
+ self.next_major_collection_initial = threshold
self.next_major_collection_threshold = threshold
return bounded
@@ -718,9 +724,18 @@
def set_max_heap_size(self, size):
self.max_heap_size = float(size)
if self.max_heap_size > 0.0:
+ if self.max_heap_size < self.next_major_collection_initial:
+ self.next_major_collection_initial = self.max_heap_size
if self.max_heap_size < self.next_major_collection_threshold:
self.next_major_collection_threshold = self.max_heap_size
+ def raw_malloc_varsize_hint(self, sizehint):
+ self.next_major_collection_threshold -= sizehint
+ 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
+
def can_malloc_nonmovable(self):
return True
@@ -1600,7 +1615,7 @@
# Max heap size: gives an upper bound on the threshold. If we
# already have at least this much allocated, raise MemoryError.
if bounded and (float(self.get_total_memory_used()) + reserving_size >=
- self.next_major_collection_threshold):
+ self.next_major_collection_initial):
#
# First raise MemoryError, giving the program a chance to
# quit cleanly. It might still allocate in the nursery,
diff --git a/pypy/rpython/memory/gctransform/framework.py
b/pypy/rpython/memory/gctransform/framework.py
--- a/pypy/rpython/memory/gctransform/framework.py
+++ b/pypy/rpython/memory/gctransform/framework.py
@@ -386,6 +386,18 @@
else:
self.malloc_varsize_nonmovable_ptr = None
+ if getattr(GCClass, 'raw_malloc_varsize_hint', False):
+ def raw_malloc_varsize_hint(length, itemsize):
+ totalmem = length * itemsize
+ if totalmem > 0:
+ gcdata.gc.raw_malloc_varsize_hint(totalmem)
+ #else: probably an overflow -- the following rawmalloc
+ # will fail then
+ self.raw_malloc_varsize_hint_ptr = getfn(
+ raw_malloc_varsize_hint,
+ [annmodel.SomeInteger(), annmodel.SomeInteger()],
+ annmodel.s_None, minimal_transform = False)
+
self.identityhash_ptr = getfn(GCClass.identityhash.im_func,
[s_gc, s_gcref],
annmodel.SomeInteger(),
diff --git a/pypy/rpython/memory/gctransform/transform.py
b/pypy/rpython/memory/gctransform/transform.py
--- a/pypy/rpython/memory/gctransform/transform.py
+++ b/pypy/rpython/memory/gctransform/transform.py
@@ -590,6 +590,16 @@
def gct_fv_raw_malloc_varsize(self, hop, flags, TYPE, v_length,
c_const_size, c_item_size,
c_offset_to_length):
+ track_allocation = flags.get('track_allocation', True)
+ if not track_allocation:
+ # idea: raw mallocs with track_allocation=False correspond
+ # generally to raw mallocs of stuff that we store in GC objects.
+ # So we tell the GC about such raw mallocs, so that it can
+ # adjust its total size estimate.
+ if hasattr(self, 'raw_malloc_varsize_hint_ptr'):
+ hop.genop("direct_call",
+ [self.raw_malloc_varsize_hint_ptr,
+ v_length, c_item_size])
if c_offset_to_length is None:
if flags.get('zero'):
fnptr = self.raw_malloc_varsize_no_length_zero_ptr
@@ -605,7 +615,7 @@
[self.raw_malloc_varsize_ptr, v_length,
c_const_size, c_item_size, c_offset_to_length],
resulttype=llmemory.Address)
- if flags.get('track_allocation', True):
+ if track_allocation:
hop.genop("track_alloc_start", [v_raw])
return v_raw
diff --git a/pypy/translator/c/test/test_newgc.py
b/pypy/translator/c/test/test_newgc.py
--- a/pypy/translator/c/test/test_newgc.py
+++ b/pypy/translator/c/test/test_newgc.py
@@ -1403,15 +1403,20 @@
# allocate a total of ~77GB, but if the automatic gc'ing works,
# it should never need more than a few MBs at once
am1 = am2 = am3 = None
- for i in range(100000):
+ res = 0
+ for i in range(1, 100001):
+ if am3 is not None:
+ res += rffi.cast(lltype.Signed, am3.buf[0])
am3 = am2
am2 = am1
am1 = A(i * 4)
- return 42
+ am1.buf[0] = rffi.cast(rffi.INT, i-50000)
+ return res
return f
def test_nongc_attached_to_gc(self):
- self.run("nongc_attached_to_gc")
+ res = self.run("nongc_attached_to_gc")
+ assert res == -99997
# ____________________________________________________________________
_______________________________________________
pypy-commit mailing list
[email protected]
http://mail.python.org/mailman/listinfo/pypy-commit