[pypy-commit] pypy gc-incminimark-pinning: Merge gc-incminimark-pinning-countlimit into gc-incminimark-pinning.

groggi noreply at buildbot.pypy.org
Mon Jun 2 17:24:56 CEST 2014


Author: Gregor Wegberg <code at gregorwegberg.com>
Branch: gc-incminimark-pinning
Changeset: r71865:d72628c24e5e
Date: 2014-05-30 17:05 +0200
http://bitbucket.org/pypy/pypy/changeset/d72628c24e5e/

Log:	Merge gc-incminimark-pinning-countlimit into gc-incminimark-pinning.

	We have to limit the amount of pinned objects by the number of
	pinned objects as AddressStack does not support sorting over
	multiple chunks!

diff --git a/rpython/memory/gc/incminimark.py b/rpython/memory/gc/incminimark.py
--- a/rpython/memory/gc/incminimark.py
+++ b/rpython/memory/gc/incminimark.py
@@ -256,6 +256,11 @@
         # 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,
+
+        # Number of  objects that are allowed to be pinned in the nursery
+        # at the same time.  Must be lesser than or equal to the chunk size
+        # of an AddressStack.
+        "max_number_of_pinned_objects": 100,
         }
 
     def __init__(self, config,
@@ -268,6 +273,7 @@
                  major_collection_threshold=2.5,
                  growth_rate_max=2.5,   # for tests
                  card_page_indices=0,
+                 max_number_of_pinned_objects=100,
                  large_object=8*WORD,
                  ArenaCollectionClass=None,
                  **kwds):
@@ -284,6 +290,7 @@
         self.max_heap_size = 0.0
         self.max_heap_size_already_raised = False
         self.max_delta = float(r_uint(-1))
+        self.max_number_of_pinned_objects = max_number_of_pinned_objects
         #
         self.card_page_indices = card_page_indices
         if self.card_page_indices > 0:
@@ -965,6 +972,8 @@
             # Reason: It would be possible that the first caller unpins
             # while the second caller thinks it's still pinned.
             return False
+        if self.pinned_objects_in_nursery >= self.max_number_of_pinned_objects:
+            return False
 
         self.header(obj).tid |= GCFLAG_PINNED
         self.pinned_objects_in_nursery += 1
@@ -979,7 +988,6 @@
         self.header(obj).tid &= ~GCFLAG_PINNED
         self.pinned_objects_in_nursery -= 1
 
-
     def shrink_array(self, obj, smallerlength):
         #
         # Only objects in the nursery can be "resized".  Resizing them
diff --git a/rpython/memory/gc/test/test_object_pinning.py b/rpython/memory/gc/test/test_object_pinning.py
--- a/rpython/memory/gc/test/test_object_pinning.py
+++ b/rpython/memory/gc/test/test_object_pinning.py
@@ -33,6 +33,7 @@
 
     # XXX test with multiple mallocs, and only part of them is pinned
 
+
 class TestIncminimark(PinningGCTest):
     from rpython.memory.gc.incminimark import IncrementalMiniMarkGC as GCClass
 
@@ -213,6 +214,50 @@
         py.test.raises(Exception, self.malloc, S)
 
 
-    # XXX test/define what happens if we try to pin an object that is too
-    # big for the nursery and will be raw-malloc'ed.
+class TestIncminimarkFewPinnedObjects(BaseDirectGCTest):
+    from rpython.memory.gc.incminimark import IncrementalMiniMarkGC as GCClass
 
+    GC_PARAMS = {'max_number_of_pinned_objects': 5
+    }
+
+    def test_pinning_limit(self):
+        for instance_nr in xrange(self.GC_PARAMS['max_number_of_pinned_objects']):
+            ptr = self.malloc(S)
+            adr = llmemory.cast_ptr_to_adr(ptr)
+            ptr.someInt = 100 + instance_nr
+            self.stackroots.append(ptr)
+            self.gc.pin(adr)
+        #
+        # now we reached the maximum amount of pinned objects
+        ptr = self.malloc(S)
+        adr = llmemory.cast_ptr_to_adr(ptr)
+        self.stackroots.append(ptr)
+        assert not self.gc.pin(adr)
+
+
+class TestIncminimarkManyPinnedObjects(BaseDirectGCTest):
+    from rpython.memory.gc.incminimark import IncrementalMiniMarkGC as GCClass
+    
+    GC_PARAMS_PLENTY_PINNED_OBJECTS = {'max_number_of_pinned_objects': 50
+    }
+
+    def get_max_nursery_objects(self, TYPE):
+        typeid = self.get_type_id(TYPE)
+        size = self.gc.fixed_size(typeid) + self.gc.gcheaderbuilder.size_gc_header
+        raw_size = llmemory.raw_malloc_usage(size)
+        return self.gc.nursery_size // raw_size
+
+    def test_full_pinned_nursery_pin_fail(self):
+        object_mallocs = self.get_max_nursery_objects(S)
+        # just to be sure we do not run into the limit as we test not the limiter
+        # but rather the case of a nursery full with pinned objects.
+        assert object_mallocs < self.gc.max_number_of_pinned_objects
+        for instance_nr in xrange(object_mallocs):
+            ptr = self.malloc(S)
+            adr = llmemory.cast_ptr_to_adr(ptr)
+            ptr.someInt = 100 + instance_nr
+            self.stackroots.append(ptr)
+            self.gc.pin(adr)
+        #
+        # nursery should be full now, at least no space for another `S`. Next malloc should fail.
+        py.test.raises(Exception, self.malloc, S)


More information about the pypy-commit mailing list