Browse Source

pulled garbage collect frequency reduction code from 1_0_14

Darren Ranalli 17 years ago
parent
commit
b36dc682a3
2 changed files with 48 additions and 26 deletions
  1. 47 0
      direct/src/distributed/ConnectionRepository.py
  2. 1 26
      direct/src/showbase/ShowBase.py

+ 47 - 0
direct/src/distributed/ConnectionRepository.py

@@ -26,6 +26,10 @@ class ConnectionRepository(
     CM_NET=1
     CM_NET=1
     CM_NATIVE=2
     CM_NATIVE=2
 
 
+    gcNotify = directNotify.newCategory("GarbageCollect")
+
+    GarbageCollectTaskName = "allowGarbageCollect"
+    GarbageThresholdTaskName = "adjustGarbageCollectThreshold"
 
 
     def __init__(self, connectMethod, config, hasOwnerView=False):
     def __init__(self, connectMethod, config, hasOwnerView=False):
         assert self.notify.debugCall()
         assert self.notify.debugCall()
@@ -107,6 +111,45 @@ class ConnectionRepository(
             # garbage collection CPU usage is O(n), n = number of Python objects
             # garbage collection CPU usage is O(n), n = number of Python objects
             gc.set_debug(gc.DEBUG_SAVEALL)
             gc.set_debug(gc.DEBUG_SAVEALL)
 
 
+        if self.config.GetBool('want-garbage-collect-task', 1):
+            # manual garbage-collect task
+            taskMgr.add(self._garbageCollect, self.GarbageCollectTaskName, 200)
+            # periodically increase gc threshold if there is no garbage
+            taskMgr.doMethodLater(self.config.GetFloat('garbage-threshold-adjust-delay', 15 * 60.),
+                                  self._adjustGcThreshold, self.GarbageThresholdTaskName)
+            
+        self._gcDefaultThreshold = gc.get_threshold()
+
+    def _garbageCollect(self, task=None):
+        # allow a collect
+        # enable automatic garbage collection
+        gc.enable()
+        # creating an object with gc enabled causes garbage collection to trigger if appropriate
+        gct = GCTrigger()
+        # disable the automatic garbage collect during the rest of the frame
+        gc.disable()
+        return Task.cont
+
+    def _adjustGcThreshold(self, task):
+        # do an unconditional collect to make sure gc.garbage has a chance to be
+        # populated before we start increasing the auto-collect threshold
+        gc.collect()
+        if len(gc.garbage) == 0:
+            self.gcNotify.debug('no garbage found, doubling gc threshold')
+            a, b, c = gc.get_threshold()
+            gc.set_threshold(min(a * 2, 1 << 30), b, c)
+
+            task.delayTime = task.delayTime * 2
+            retVal = Task.again
+
+        else:
+            self.gcNotify.warning('garbage found, reverting gc threshold')
+            # the process is producing garbage, stick to the default collection threshold
+            gc.set_threshold(*self._gcDefaultThreshold)
+            retVal = Task.done
+
+        return retVal
+
     def generateGlobalObject(self, doId, dcname, values=None):
     def generateGlobalObject(self, doId, dcname, values=None):
         def applyFieldValues(distObj, dclass, values):
         def applyFieldValues(distObj, dclass, values):
             for i in range(dclass.getNumInheritedFields()):
             for i in range(dclass.getNumInheritedFields()):
@@ -583,3 +626,7 @@ class ConnectionRepository(
         if self.networkPlugPulled():
         if self.networkPlugPulled():
             self.notify.info('*** RESTORING SIMULATED PULLED-NETWORK-PLUG ***')
             self.notify.info('*** RESTORING SIMULATED PULLED-NETWORK-PLUG ***')
             self.setSimulatedDisconnect(0)
             self.setSimulatedDisconnect(0)
+
+class GCTrigger:
+    # used to trigger garbage collection
+    pass

+ 1 - 26
direct/src/showbase/ShowBase.py

@@ -54,8 +54,6 @@ class ShowBase(DirectObject.DirectObject):
 
 
     notify = directNotify.newCategory("ShowBase")
     notify = directNotify.newCategory("ShowBase")
 
 
-    GarbageCollectTaskName = "allowGarbageCollect"
-
     def __init__(self):
     def __init__(self):
         __builtin__.__dev__ = config.GetBool('want-dev', 0)
         __builtin__.__dev__ = config.GetBool('want-dev', 0)
         if config.GetBool('want-variable-dump', not __dev__):
         if config.GetBool('want-variable-dump', not __dev__):
@@ -367,10 +365,6 @@ class ShowBase(DirectObject.DirectObject):
         if self.windowType != 'none':
         if self.windowType != 'none':
             self.__doStartDirect()
             self.__doStartDirect()
 
 
-        if config.GetBool('want-garbage-collect-task', 1):
-            # manual garbage-collect task
-            taskMgr.add(self._garbageCollect, self.GarbageCollectTaskName, 200)
-            
         taskMgr.finalInit()
         taskMgr.finalInit()
 
 
         # Start IGLOOP
         # Start IGLOOP
@@ -2307,26 +2301,7 @@ class ShowBase(DirectObject.DirectObject):
         self.startDirect(fWantDirect = fDirect, fWantTk = fTk, fWantWx = fWx)
         self.startDirect(fWantDirect = fDirect, fWantTk = fTk, fWantWx = fWx)
 
 
     def run(self):
     def run(self):
-        try:
-            self.taskMgr.run()
-        except:
-            # make sure gc is enabled when we break out to the prompt
-            gc.enable()
-        else:
-            gc.enable()
-
-    def _garbageCollect(self, task=None):
-        # enable automatic garbage collection
-        gc.enable()
-        # creating an object with gc enabled causes garbage collection to trigger if appropriate
-        gct = GCTrigger()
-        # disable the automatic garbage collect during the rest of the frame
-        gc.disable()
-        return Task.cont
-
-class GCTrigger:
-    # used to trigger garbage collection
-    pass
+        self.taskMgr.run()
 
 
 
 
 # A class to encapsulate information necessary for multiwindow support.
 # A class to encapsulate information necessary for multiwindow support.