Browse Source

quicker discovery of LeakDetector objects

Darren Ranalli 18 years ago
parent
commit
61550870cb
2 changed files with 49 additions and 14 deletions
  1. 29 12
      direct/src/showbase/ContainerLeakDetector.py
  2. 20 2
      direct/src/showbase/LeakDetectors.py

+ 29 - 12
direct/src/showbase/ContainerLeakDetector.py

@@ -265,6 +265,14 @@ class FindContainers(Job):
         # set up the base containers, the ones that hold most objects
         ref = ContainerRef(Indirection(evalStr='__builtin__.__dict__'))
         self._id2baseStartRef[id(__builtin__.__dict__)] = ref
+        # container for objects that want to make sure they are found by
+        # the object exploration algorithm, including objects that exist
+        # just to measure things such as C++ memory usage, scene graph size,
+        # framerate, etc. See LeakDetectors.py
+        if not hasattr(__builtin__, "leakDetectors"):
+            __builtin__.leakDetectors = {}
+        ref = ContainerRef(Indirection(evalStr='leakDetectors'))
+        self._id2baseStartRef[id(leakDetectors)] = ref
         for i in self._addContainerGen(__builtin__.__dict__, ref):
             pass
         try:
@@ -369,9 +377,9 @@ class FindContainers(Job):
 
     def run(self):
         try:
-            # this toggles between the sets of start refs every time we start a new traversal
-            workingListSelector = loopGen([self._baseStartRefWorkingList,
-                                           self._discoveredStartRefWorkingList])
+            # this yields a different set of start refs every time we start a new traversal
+            # force creation of a new workingListSelector inside the while loop right off the bat
+            workingListSelector = nullGen()
             # this holds the current step of the current traversal
             curObjRef = None
             while True:
@@ -381,7 +389,19 @@ class FindContainers(Job):
                 #import pdb;pdb.set_trace()
                 if curObjRef is None:
                     # choose an object to start a traversal from
-                    startRefWorkingList = workingListSelector.next()
+                    try:
+                        startRefWorkingList = workingListSelector.next()
+                    except StopIteration:
+                        # do relative # of traversals on each set based on how many refs it contains
+                        baseLen = len(self._baseStartRefWorkingList.source)
+                        discLen = len(self._discoveredStartRefWorkingList.source)
+                        minLen = float(max(1, min(baseLen, discLen)))
+                        # this will cut down the traversals of the larger set by 2/3
+                        minLen *= 3.
+                        workingListSelector = flywheel([self._baseStartRefWorkingList, self._discoveredStartRefWorkingList],
+                                                       [baseLen/minLen, discLen/minLen])
+                        yield None
+                        continue
 
                     # grab the next start ref from this sequence and see if it's still valid
                     while True:
@@ -396,12 +416,12 @@ class FindContainers(Job):
                                 break
                             # make a generator that yields containers a # of times that is
                             # proportional to their length
-                            for flywheel in makeFlywheelGen(
+                            for fw in makeFlywheelGen(
                                 startRefWorkingList.source.values(),
                                 countFunc=lambda x: self.getStartObjAffinity(x),
                                 scale=.05):
                                 yield None
-                            startRefWorkingList.refGen = flywheel
+                            startRefWorkingList.refGen = fw
                     if curObjRef is None:
                         # this ref set is empty, choose another
                         # the base set should never be empty (__builtin__ etc.)
@@ -540,8 +560,7 @@ class FindContainers(Job):
         except Exception, e:
             print 'FindContainers job caught exception: %s' % e
             if __dev__:
-                #raise e
-                pass
+                raise
         yield Job.Done
 
 class CheckContainers(Job):
@@ -680,8 +699,7 @@ class CheckContainers(Job):
         except Exception, e:
             print 'CheckContainers job caught exception: %s' % e
             if __dev__:
-                #raise e
-                pass
+                raise
         yield Job.Done
 
 class PruneContainerRefs(Job):
@@ -736,8 +754,7 @@ class PruneContainerRefs(Job):
         except Exception, e:
             print 'PruneContainerRefs job caught exception: %s' % e
             if __dev__:
-                #raise e
-                pass
+                raise
         yield Job.Done
 
 class ContainerLeakDetector(Job):

+ 20 - 2
direct/src/showbase/LeakDetectors.py

@@ -1,8 +1,21 @@
 # objects that report different types of leaks to the ContainerLeakDetector
 
-class SceneGraphLeakDetector:
+import __builtin__
+
+class LeakDetector:
+    def __init__(self):
+        # put this object just under __builtins__ where the
+        # ContainerLeakDetector will find it quickly
+        if not hasattr(__builtin__, "leakDetectors"):
+            __builtin__.leakDetectors = {}
+        leakDetectors[id(self)] = self
+    def destroy(self):
+        del leakDetectors[id(self)]
+
+class SceneGraphLeakDetector(LeakDetector):
     # is a scene graph leaking nodes?
     def __init__(self, render):
+        LeakDetector.__init__(self)
         self._render = render
         if config.GetBool('leak-scene-graph', 0):
             self._leakTaskName = 'leakNodes-%s' % serialNum()
@@ -11,8 +24,13 @@ class SceneGraphLeakDetector:
         if hasattr(self, '_leakTaskName'):
             taskMgr.remove(self._leakTaskName)
         del self._render
+        LeakDetector.destroy(self)
     def __len__(self):
-        return self._render.getNumDescendants()
+        try:
+            # this will be available when the build server finishes
+            return self._render.countNumDescendants()
+        except:
+            return self._render.getNumDescendants()
     def __repr__(self):
         return 'SceneGraphLeakDetector(%s)' % self._render
     def _leakNode(self, task=None):