ソースを参照

added GarbageReportScheduler

Darren Ranalli 18 年 前
コミット
4ac6f8c885

+ 1 - 3
direct/src/showbase/ContainerLeakDetector.py

@@ -820,6 +820,7 @@ class ContainerLeakDetector(Job):
         ContainerLeakDetector.addPrivateObj(ContainerLeakDetector.PrivateIds)
         ContainerLeakDetector.addPrivateObj(self.__dict__)
 
+        self.setPriority(Job.Priorities.Min)
         jobMgr.add(self)
 
     def destroy(self):
@@ -840,9 +841,6 @@ class ContainerLeakDetector(Job):
         # passes description string as argument
         return 'containerLeakDetected-%s' % self._serialNum
 
-    def getPriority(self):
-        return Job.Priorities.Min
-
     @classmethod
     def addPrivateObj(cls, obj):
         cls.PrivateIds.add(id(obj))

+ 9 - 4
direct/src/showbase/GarbageReport.py

@@ -26,7 +26,7 @@ class GarbageReport(Job):
     NotGarbage = 'NG'
 
     def __init__(self, name, log=True, verbose=False, fullReport=False, findCycles=True,
-                 threaded=False, doneCallback=None, autoDestroy=False):
+                 threaded=False, doneCallback=None, autoDestroy=False, priority=None):
         # if autoDestroy is True, GarbageReport will self-destroy after logging
         # if false, caller is responsible for calling destroy()
         # if threaded is True, processing will be performed over multiple frames
@@ -35,6 +35,8 @@ class GarbageReport(Job):
         self._args = ScratchPad(name=name, log=log, verbose=verbose, fullReport=fullReport,
                                 findCycles=findCycles, doneCallback=doneCallback,
                                 autoDestroy=autoDestroy)
+        if priority is not None:
+            self.setPriority(priority)
         jobMgr.add(self)
         if not threaded:
             jobMgr.finish(self)
@@ -114,8 +116,12 @@ class GarbageReport(Job):
                         yield None
                         self.cycleIds.update(set(cycle))
 
-        s = ['===== GarbageReport: \'%s\' (%s items) =====' % (
-            self._args.name, self.numGarbage)]
+        if self._args.findCycles:
+            s = ['===== GarbageReport: \'%s\' (%s items, %s cycles) =====' % (
+                self._args.name, self.numGarbage, len(self.cycles))]
+        else:
+            s = ['===== GarbageReport: \'%s\' (%s items) =====' % (
+                self._args.name, self.numGarbage)]
         if self.numGarbage > 0:
             # make a list of the ids we will actually be printing
             if self._args.fullReport:
@@ -265,7 +271,6 @@ class GarbageReport(Job):
         yield byNum, byRef
 
     def _getCycles(self, index, cycleSets=None):
-        # TODO: make this a generator
         # detect garbage cycles for a particular item of garbage
         assert self.notify.debugCall()
         # returns list of lists, sublists are garbage reference cycles

+ 40 - 0
direct/src/showbase/GarbageReportScheduler.py

@@ -0,0 +1,40 @@
+from direct.showbase.GarbageReport import GarbageReport
+
+class GarbageReportScheduler:
+    # runs a garbage report every once in a while and logs the results
+    def __init__(self, waitBetween=None, waitScale=None):
+        # waitBetween is in seconds
+        # waitScale is a multiplier for the waitBetween every time around
+        if waitBetween is None:
+            waitBetween = 30*60
+        if waitScale is None:
+            waitScale = 1.5
+        self._waitBetween = waitBetween
+        self._waitScale = waitScale
+        self._taskName = 'startScheduledGarbageReport-%s' % serialNum()
+        self._garbageReport = None
+        self._scheduleNextGarbageReport()
+
+    def getTaskName(self):
+        return self._taskName
+
+    def _scheduleNextGarbageReport(self, garbageReport=None):
+        if garbageReport:
+            # this report finished, wait a bit then start another
+            assert garbageReport is self._garbageReport
+            # garbagereport will clean itself up
+            self._garbageReport = None
+        # run another garbagereport after a delay
+        taskMgr.doMethodLater(self._waitBetween,
+                              self._runGarbageReport,
+                              self._taskName)
+        # and increase the delay every time around
+        self._waitBetween = self._waitBetween * self._waitScale
+    def _runGarbageReport(self, task):
+        # run a garbage report and schedule the next one after this one finishes
+        # give this job 3 times as many timeslices as normal-priority jobs
+        self._garbageReport = GarbageReport('ScheduledGarbageReport', threaded=True,
+                                            doneCallback=self._scheduleNextGarbageReport,
+                                            autoDestroy=True,
+                                            priority=GarbageReport.Priorities.Normal * 3)
+        return task.done

+ 4 - 2
direct/src/showbase/Job.py

@@ -23,6 +23,7 @@ class Job(DirectObject):
         self._generator = None
         self._id = Job._SerialGen.next()
         self._printing = False
+        self._priority = Job.Priorities.Normal
         if __debug__:
             self._pstats = PStatCollector("App:Show code:jobManager:%s" % self._name)
 
@@ -45,8 +46,9 @@ class Job(DirectObject):
         raise "don't call down"
 
     def getPriority(self):
-        # override if you want a different priority
-        return Job.Priorities.Normal
+        return self._priority
+    def setPriority(self, priority):
+        self._priority = priority
 
     def printingBegin(self):
         self._printing = True