mirror of
https://github.com/panda3d/panda3d.git
synced 2025-10-02 09:52:27 -04:00
prevent Job generator leak, added JobManager.finish(job), logging GarbageReports auto-destroy
This commit is contained in:
parent
e2ac31938f
commit
78b10c41ba
@ -4,7 +4,6 @@ __all__ = ['FakeObject', '_createGarbage', 'GarbageReport', 'GarbageLogger']
|
|||||||
|
|
||||||
from direct.directnotify.DirectNotifyGlobal import directNotify
|
from direct.directnotify.DirectNotifyGlobal import directNotify
|
||||||
from direct.showbase.PythonUtil import gcDebugOn, safeRepr, fastRepr
|
from direct.showbase.PythonUtil import gcDebugOn, safeRepr, fastRepr
|
||||||
#from direct.showbase.TaskThreaded import TaskThreaded, TaskThread
|
|
||||||
from direct.showbase.Job import Job
|
from direct.showbase.Job import Job
|
||||||
import gc
|
import gc
|
||||||
|
|
||||||
@ -26,18 +25,18 @@ class GarbageReport(Job):
|
|||||||
NotGarbage = 'NG'
|
NotGarbage = 'NG'
|
||||||
|
|
||||||
def __init__(self, name, log=True, verbose=False, fullReport=False, findCycles=True,
|
def __init__(self, name, log=True, verbose=False, fullReport=False, findCycles=True,
|
||||||
threaded=False, timeslice=None, doneCallback=None):
|
threaded=False, doneCallback=None):
|
||||||
# if log is True, GarbageReport will self-destroy after logging
|
# if log is True, GarbageReport will self-destroy after logging
|
||||||
# if false, caller is responsible for calling destroy()
|
# if false, caller is responsible for calling destroy()
|
||||||
# if threaded is True, processing will be performed over multiple frames
|
# if threaded is True, processing will be performed over multiple frames
|
||||||
Job.__init__(self, name)
|
Job.__init__(self, name)
|
||||||
# stick the arguments onto a ScratchPad so we can access them from the thread
|
# stick the arguments onto a ScratchPad so we can delete them all at once
|
||||||
# functions and delete them all at once
|
|
||||||
self._args = ScratchPad(name=name, log=log, verbose=verbose, fullReport=fullReport,
|
self._args = ScratchPad(name=name, log=log, verbose=verbose, fullReport=fullReport,
|
||||||
findCycles=findCycles, doneCallback=doneCallback)
|
findCycles=findCycles, doneCallback=doneCallback)
|
||||||
self._printing = False
|
self._printing = False
|
||||||
jobMgr.add(self)
|
jobMgr.add(self)
|
||||||
self.numGarbage = 0
|
if threaded == False:
|
||||||
|
jobMgr.finish(self)
|
||||||
|
|
||||||
def run(self):
|
def run(self):
|
||||||
# do the garbage collection
|
# do the garbage collection
|
||||||
@ -183,10 +182,20 @@ class GarbageReport(Job):
|
|||||||
yield None
|
yield None
|
||||||
self._printing = False
|
self._printing = False
|
||||||
|
|
||||||
|
yield Job.Done
|
||||||
|
|
||||||
|
def suspend(self):
|
||||||
|
if self._printing:
|
||||||
|
self.notify.info('SUSPEND')
|
||||||
|
def resume(self):
|
||||||
|
if self._printing:
|
||||||
|
self.notify.info('RESUME')
|
||||||
|
|
||||||
|
def finished(self):
|
||||||
if self._args.doneCallback:
|
if self._args.doneCallback:
|
||||||
self._args.doneCallback(self)
|
self._args.doneCallback(self)
|
||||||
|
if self._args.log:
|
||||||
yield Job.Done
|
self.destroy()
|
||||||
|
|
||||||
def destroy(self):
|
def destroy(self):
|
||||||
#print 'GarbageReport.destroy'
|
#print 'GarbageReport.destroy'
|
||||||
@ -204,13 +213,6 @@ class GarbageReport(Job):
|
|||||||
del self._reportStr
|
del self._reportStr
|
||||||
Job.destroy(self)
|
Job.destroy(self)
|
||||||
|
|
||||||
def suspend(self):
|
|
||||||
if self._printing:
|
|
||||||
self.notify.info('SUSPEND')
|
|
||||||
def resume(self):
|
|
||||||
if self._printing:
|
|
||||||
self.notify.info('RESUME')
|
|
||||||
|
|
||||||
def getNumItems(self):
|
def getNumItems(self):
|
||||||
return self.numGarbage
|
return self.numGarbage
|
||||||
|
|
||||||
|
@ -6,6 +6,7 @@ class Job:
|
|||||||
Done = object()
|
Done = object()
|
||||||
Continue = None # 'yield None' is acceptable in place of 'yield Job.Continue'
|
Continue = None # 'yield None' is acceptable in place of 'yield Job.Continue'
|
||||||
|
|
||||||
|
# these priorities are reference points, you can use whatever numbers you want
|
||||||
Priorities = ScratchPad(Low=-100, Normal=0, High=100)
|
Priorities = ScratchPad(Low=-100, Normal=0, High=100)
|
||||||
_SerialGen = SerialNumGen()
|
_SerialGen = SerialNumGen()
|
||||||
|
|
||||||
@ -27,18 +28,21 @@ class Job:
|
|||||||
|
|
||||||
def getPriority(self):
|
def getPriority(self):
|
||||||
# override if you want a different priority
|
# override if you want a different priority
|
||||||
# you can use numbers other than those in Job.Priorities
|
|
||||||
return Job.Priorities.Normal
|
return Job.Priorities.Normal
|
||||||
|
|
||||||
def suspend(self):
|
def suspend(self):
|
||||||
# called when JobManager is going to stop running this job for a while
|
# called when JobManager is going to stop running this job for a while
|
||||||
# most jobs don't need to override this
|
|
||||||
pass
|
pass
|
||||||
def resume(self):
|
def resume(self):
|
||||||
# called when JobManager is going to start running this job again
|
# called when JobManager is going to start running this job again
|
||||||
# most jobs don't need to override this
|
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
def finished(self):
|
||||||
|
# called when the job finishes and has been removed from the JobManager
|
||||||
|
pass
|
||||||
|
|
||||||
|
def getJobName(self):
|
||||||
|
return self._name
|
||||||
def _getJobId(self):
|
def _getJobId(self):
|
||||||
return self._id
|
return self._id
|
||||||
|
|
||||||
@ -46,6 +50,9 @@ class Job:
|
|||||||
if self._generator is None:
|
if self._generator is None:
|
||||||
self._generator = self.run()
|
self._generator = self.run()
|
||||||
return self._generator
|
return self._generator
|
||||||
|
def _cleanupGenerator(self):
|
||||||
|
if self._generator is not None:
|
||||||
|
self._generator = None
|
||||||
|
|
||||||
if __debug__: # __dev__ not yet available at this point
|
if __debug__: # __dev__ not yet available at this point
|
||||||
from direct.showbase.Job import Job
|
from direct.showbase.Job import Job
|
||||||
|
@ -59,6 +59,8 @@ class JobManager:
|
|||||||
self._pri2jobIds[pri].remove(jobId)
|
self._pri2jobIds[pri].remove(jobId)
|
||||||
# remove the job from the main table
|
# remove the job from the main table
|
||||||
del self._pri2jobId2job[pri][jobId]
|
del self._pri2jobId2job[pri][jobId]
|
||||||
|
# clean up the job's generator, if any
|
||||||
|
job._cleanupGenerator()
|
||||||
if len(self._pri2jobId2job[pri]) == 0:
|
if len(self._pri2jobId2job[pri]) == 0:
|
||||||
del self._pri2jobId2job[pri]
|
del self._pri2jobId2job[pri]
|
||||||
if pri == self._highestPriority:
|
if pri == self._highestPriority:
|
||||||
@ -72,6 +74,31 @@ class JobManager:
|
|||||||
taskMgr.remove(JobManager.TaskName)
|
taskMgr.remove(JobManager.TaskName)
|
||||||
self._highestPriority = 0
|
self._highestPriority = 0
|
||||||
|
|
||||||
|
def finish(self, job):
|
||||||
|
# run this job, right now, until it finishes
|
||||||
|
assert self.notify.debugCall()
|
||||||
|
jobId = job._getJobId()
|
||||||
|
# look up the job's priority
|
||||||
|
pri = self._jobId2pri[jobId]
|
||||||
|
# grab the job
|
||||||
|
job = self._pri2jobId2job[pri][jobId]
|
||||||
|
gen = job._getGenerator()
|
||||||
|
job.resume()
|
||||||
|
while True:
|
||||||
|
try:
|
||||||
|
result = gen.next()
|
||||||
|
except StopIteration:
|
||||||
|
# Job didn't yield Job.Done, it ran off the end and returned
|
||||||
|
# treat it as if it returned Job.Done
|
||||||
|
self.notify.warning('job %s never yielded Job.Done' % job)
|
||||||
|
result = Job.Done
|
||||||
|
if result is Job.Done:
|
||||||
|
job.suspend()
|
||||||
|
self.remove(job)
|
||||||
|
job.finished()
|
||||||
|
# job is done.
|
||||||
|
break
|
||||||
|
|
||||||
# how long should we run per frame?
|
# how long should we run per frame?
|
||||||
def getTimeslice(self):
|
def getTimeslice(self):
|
||||||
return self._timeslice
|
return self._timeslice
|
||||||
@ -104,6 +131,7 @@ class JobManager:
|
|||||||
if result is Job.Done:
|
if result is Job.Done:
|
||||||
job.suspend()
|
job.suspend()
|
||||||
self.remove(job)
|
self.remove(job)
|
||||||
|
job.finished()
|
||||||
# highest-priority job is done.
|
# highest-priority job is done.
|
||||||
# grab the next one if there's time left
|
# grab the next one if there's time left
|
||||||
break
|
break
|
||||||
|
Loading…
x
Reference in New Issue
Block a user