[pypy-svn] r79900 - pypy/branch/gc-debug/pypy/rpython/memory/gc

arigo at codespeak.net arigo at codespeak.net
Wed Dec 8 17:14:02 CET 2010


Author: arigo
Date: Wed Dec  8 17:14:01 2010
New Revision: 79900

Modified:
   pypy/branch/gc-debug/pypy/rpython/memory/gc/base.py
   pypy/branch/gc-debug/pypy/rpython/memory/gc/minimark.py
Log:

- Use PYPY_GC_DEBUG=2 to also do debug checks after minor collections
  (slow).

- Implemented a scheme where, if PYPY_GC_DEBUG is set, we allocate 23
  nurseries instead of just 1.  After every minor collection we switch
  to the next one.  The unused nurseries are mprotect()ed.  This should
  allow us to quickly spot places that still use pointers to one of the
  old nurseries.



Modified: pypy/branch/gc-debug/pypy/rpython/memory/gc/base.py
==============================================================================
--- pypy/branch/gc-debug/pypy/rpython/memory/gc/base.py	(original)
+++ pypy/branch/gc-debug/pypy/rpython/memory/gc/base.py	Wed Dec  8 17:14:01 2010
@@ -40,8 +40,7 @@
         # More stuff that needs to be initialized when the GC is already
         # fully working.  (Only called by gctransform/framework for now.)
         from pypy.rpython.memory.gc import env
-        if env.read_from_env('PYPY_GC_DEBUG') > 0:
-            self.DEBUG = True
+        self.DEBUG = env.read_from_env('PYPY_GC_DEBUG')
 
     def _teardown(self):
         pass

Modified: pypy/branch/gc-debug/pypy/rpython/memory/gc/minimark.py
==============================================================================
--- pypy/branch/gc-debug/pypy/rpython/memory/gc/minimark.py	(original)
+++ pypy/branch/gc-debug/pypy/rpython/memory/gc/minimark.py	Wed Dec  8 17:14:01 2010
@@ -3,7 +3,9 @@
 Environment variables can be used to fine-tune the following parameters:
     
  PYPY_GC_NURSERY        The nursery size.  Defaults to half the size of
-                        the L2 cache.  Try values like '1.2MB'.
+                        the L2 cache.  Try values like '1.2MB'.  Minimum
+                        is about 64KB.   Use 1 to force every malloc to
+                        do a minor collection for debugging.
 
  PYPY_GC_MAJOR_COLLECT  Major collection memory factor.  Default is '1.82',
                         which means trigger a major collection when the
@@ -34,7 +36,9 @@
                         times the nursery.
 
  PYPY_GC_DEBUG          Enable extra checks around collections that are
-                        too slow for normal use.
+                        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
@@ -227,6 +231,7 @@
         self.nursery_free = NULL
         self.nursery_top  = NULL
         self.debug_always_do_minor_collect = False
+        self.debug_rotating_nurseries = None
         #
         # The ArenaCollection() handles the nonmovable objects allocation.
         if ArenaCollectionClass is None:
@@ -335,17 +340,24 @@
             self.allocate_nursery()
 
 
-    def allocate_nursery(self):
-        debug_start("gc-set-nursery-size")
-        debug_print("nursery size:", self.nursery_size)
+    def _nursery_memory_size(self):
+        extra = self.nonlarge_gcptrs_max + 1
+        return self.nursery_size + extra
+
+    def _alloc_nursery(self):
         # the start of the nursery: we actually allocate a bit more for
         # the nursery than really needed, to simplify pointer arithmetic
         # in malloc_fixedsize_clear().  The few extra pages are never used
         # anyway so it doesn't even count.
-        extra = self.nonlarge_gcptrs_max + 1
-        self.nursery = llarena.arena_malloc(self.nursery_size + extra, 2)
-        if not self.nursery:
+        nursery = llarena.arena_malloc(self._nursery_memory_size(), 2)
+        if not nursery:
             raise MemoryError("cannot allocate nursery")
+        return nursery
+
+    def allocate_nursery(self):
+        debug_start("gc-set-nursery-size")
+        debug_print("nursery size:", self.nursery_size)
+        self.nursery = self._alloc_nursery()
         # the current position in the nursery:
         self.nursery_free = self.nursery
         # the end of the nursery:
@@ -379,6 +391,39 @@
         return bounded
 
 
+    def post_setup(self):
+        # set up extra stuff for PYPY_GC_DEBUG.
+        MovingGCBase.post_setup(self)
+        if self.DEBUG and llarena.has_protect:
+            # gc debug mode: allocate 23 nurseries instead of just 1,
+            # and use them alternatively, while mprotect()ing the unused
+            # ones to detect invalid access.
+            debug_start("gc-debug")
+            self.debug_rotating_nurseries = []
+            for i in range(22):
+                nurs = self._alloc_nursery()
+                llarena.arena_protect(nurs, self._nursery_memory_size(), True)
+                self.debug_rotating_nurseries.append(nurs)
+            debug_print("allocated", len(self.debug_rotating_nurseries),
+                        "extra nurseries")
+            debug_stop("gc-debug")
+
+    def debug_rotate_nursery(self):
+        if self.debug_rotating_nurseries is not None:
+            debug_start("gc-debug")
+            oldnurs = self.nursery
+            llarena.arena_protect(oldnurs, self._nursery_memory_size(), True)
+            self.debug_rotating_nurseries.append(oldnurs)
+            #
+            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
+            debug_print("switching to nursery", self.nursery,
+                        "size", self.nursery_size)
+            debug_stop("gc-debug")
+
+
     def malloc_fixedsize_clear(self, typeid, size, can_collect=True,
                                needs_finalizer=False, contains_weakptr=False):
         ll_assert(can_collect, "!can_collect")
@@ -1003,13 +1048,14 @@
         # 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)
+        self.debug_rotate_nursery()
         self.nursery_free = self.nursery
         #
         debug_print("minor collect, total memory used:",
                     self.get_total_memory_used())
+        if self.DEBUG >= 2:
+            self.debug_check_consistency()     # expensive!
         debug_stop("gc-minor")
-        if 0:  # not we_are_translated():
-            self.debug_check_consistency()     # xxx expensive!
 
 
     def collect_roots_in_nursery(self):



More information about the Pypy-commit mailing list