fixed FrameProfiler/taskMgr synchronization problem

This commit is contained in:
Darren Ranalli 2008-11-03 21:43:47 +00:00
parent d1c1c8e31f
commit 3b2a2af619
4 changed files with 66 additions and 34 deletions

View File

@ -306,6 +306,8 @@ class ProfileSession:
if statsChanged:
self._stats.strip_dirs()
# throw out any cached result strings
self._resultCache = {}
return statsChanged
@ -326,10 +328,7 @@ class ProfileSession:
if totalTime is Default:
totalTime = self._totalTime
statsChanged = self._compileStats()
if statsChanged:
# throw out any cached result strings
self._resultCache = {}
self._compileStats()
if totalTime is None:
totalTime = self._stats.total_tt

View File

@ -14,6 +14,8 @@ class FrameProfiler:
Hour = FrameProfiler.Hour
# how long to wait between frame profiles
self._period = 2 * FrameProfiler.Minute
if config.GetBool('frame-profiler-debug', 0):
self._period = 1 * FrameProfiler.Minute
# used to prevent profile from being taken exactly every 'period' seconds
self._jitterMagnitude = self._period * .75
# when to log output
@ -24,6 +26,12 @@ class FrameProfiler:
12 * FrameProfiler.Hour,
1 * FrameProfiler.Day,
] # day schedule proceeds as 1, 2, 4, 8 days, etc.
if config.GetBool('frame-profiler-debug', 0):
self._logSchedule = [ 1 * FrameProfiler.Minute,
4 * FrameProfiler.Minute,
12 * FrameProfiler.Minute,
24 * FrameProfiler.Minute,
]
for t in self._logSchedule:
assert isInteger(t)
# make sure the period is evenly divisible into each element of the log schedule
@ -47,9 +55,10 @@ class FrameProfiler:
self._profileCounter = 0
self._jitter = None
self._period2aggregateProfile = {}
self._lastSession = None
self._id2session = {}
self._id2task = {}
# don't profile process startup
self._task = taskMgr.doMethodLater(self._period, self._startProfiling,
self._task = taskMgr.doMethodLater(self._period, self._scheduleNextProfileDoLater,
'FrameProfilerStart-%s' % serialNum())
else:
self._task.remove()
@ -57,12 +66,15 @@ class FrameProfiler:
for session in self._period2aggregateProfile.itervalues:
session.release()
del self._period2aggregateProfile
if self._lastSession:
self._lastSession.release()
del self._lastSession
for task in self._id2task.itervalues():
task.remove()
del self._id2task
for session in self._id2session.itervalues():
session.release()
del self._id2session
self.notify.info('frame profiler stopped')
def _startProfiling(self, task):
def _scheduleNextProfileDoLater(self, task):
self._scheduleNextProfile()
return task.done
@ -83,30 +95,41 @@ class FrameProfiler:
jitter = None
self._jitter = jitter
self._lastSession = taskMgr.getProfileSession('FrameProfile-%s' % serialNum())
taskMgr.profileFrames(num=1, session=self._lastSession)
sessionId = serialNum()
session = taskMgr.getProfileSession('FrameProfile-%s' % sessionId)
self._id2session[sessionId] = session
taskMgr.profileFrames(num=1, session=session, callback=Functor(
self._analyzeResults, sessionId))
# schedule the next profile
delay = max(time - globalClock.getFrameTime(), 0.)
self._task = taskMgr.doMethodLater(delay, self._frameProfileTask,
self._task = taskMgr.doMethodLater(delay, self._scheduleNextProfileDoLater,
'FrameProfiler-%s' % serialNum())
def _frameProfileTask(self, task):
def _analyzeResults(self, sessionId):
# do the analysis in a task 1) to separate the processing from the profiled frame,
# and 2) to get the processing to show up in a named task instead of in the taskMgr
self._id2task[sessionId] = taskMgr.add(
Functor(self._doAnalysis, sessionId), 'FrameProfilerAnalysis-%s' % sessionId)
def _doAnalysis(self, sessionId, task):
p2ap = self._period2aggregateProfile
if self._lastSession:
if self._lastSession.profileSucceeded():
# always add this profile to the first aggregated profile
period = self._logSchedule[0]
if period not in self._period2aggregateProfile:
p2ap[period] = self._lastSession.getReference()
else:
p2ap[period].aggregate(self._lastSession)
else:
self.notify.warning('frame profile did not succeed')
self._id2task.pop(sessionId)
session = self._id2session.pop(sessionId)
# always release the last-recorded profile
self._lastSession.release()
self._lastSession = None
if session.profileSucceeded():
# always add this profile to the first aggregated profile
period = self._logSchedule[0]
if period not in self._period2aggregateProfile:
p2ap[period] = session.getReference()
else:
p2ap[period].aggregate(session)
else:
self.notify.warning('frame profile did not succeed')
session.release()
session = None
# log profiles when it's time, and aggregate them upwards into the
# next-longer profile
@ -138,5 +161,5 @@ class FrameProfiler:
# periods are multiples of this one
break
self._scheduleNextProfile()
return task.done

View File

@ -456,12 +456,15 @@ class TaskManager:
while self.running:
try:
if len(self._frameProfileQueue):
numFrames, session = self._frameProfileQueue.pop()
numFrames, session, callback = self._frameProfileQueue.pop()
def _profileFunc(numFrames=numFrames):
self._doProfiledFrames(numFrames)
session.setFunc(_profileFunc)
session.run()
_profileFunc = None
if callback:
callback()
session.release()
else:
self.step()
except KeyboardInterrupt:
@ -546,12 +549,14 @@ class TaskManager:
name = 'taskMgrFrameProfile'
return ProfileSession(name)
def profileFrames(self, num=None, session=None):
def profileFrames(self, num=None, session=None, callback=None):
if num is None:
num = 1
if session is None:
session = self.getProfileSession()
self._frameProfileQueue.push((num, session))
# make sure the profile session doesn't get destroyed before we're done with it
session.acquire()
self._frameProfileQueue.push((num, session, callback))
def _doProfiledFrames(self, numFrames):
for i in xrange(numFrames):

View File

@ -1030,12 +1030,14 @@ class TaskManager:
name = 'taskMgrFrameProfile'
return ProfileSession(name)
def profileFrames(self, num=None, session=None):
def profileFrames(self, num=None, session=None, callback=None):
if num is None:
num = 1
if session is None:
session = self.getProfileSession()
self._frameProfileQueue.push((num, session))
# make sure the profile session doesn't get destroyed before we're done with it
session.acquire()
self._frameProfileQueue.push((num, session, callback))
# in the event we want to do frame time managment.. this is the function to
@ -1241,12 +1243,15 @@ class TaskManager:
while self.running:
try:
if len(self._frameProfileQueue):
numFrames, session = self._frameProfileQueue.pop()
numFrames, session, callback = self._frameProfileQueue.pop()
def _profileFunc(numFrames=numFrames):
self._doProfiledFrames(numFrames)
session.setFunc(_profileFunc)
session.run()
_profileFunc = None
if callback:
callback()
session.release()
else:
self.step()
except KeyboardInterrupt: