initial revision

This commit is contained in:
Darren Ranalli 2008-09-16 22:07:59 +00:00
parent 66d112fbe5
commit d3389a556e

96
direct/src/task/TaskProfiler.py Executable file
View File

@ -0,0 +1,96 @@
from direct.directnotify.DirectNotifyGlobal import directNotify
from direct.fsm.StatePush import FunctionCall
from direct.showbase.PythonUtil import getProfileResultString, Averager
class TaskTracker:
def __init__(self, namePattern):
self._namePattern = namePattern
self._durationAverager = Averager('%s-durationAverager' % namePattern)
self._avgData = None
self._avgDataDur = None
def destroy(self):
del self._namePattern
del self._durationAverager
def getNamePattern(self, namePattern):
return self._namePattern
def addDuration(self, duration, data):
self._durationAverager.addValue(duration)
storeAvgData = True
if self._avgDataDur is not None:
avgDur = self.getAvgDuration()
if abs(self._avgDataDur - avgDur) < abs(duration - avgDur):
# current avg data is more average than this new sample, keep the data we've
# already got stored
storeAvgData = False
if storeAvgData:
self._avgData = data
self._avgDataDur = duration
def getAvgDuration(self):
return self._durationAverager.getAverage()
def getNumDurationSamples(self):
return self._durationAverager.getCount()
def getAvgData(self):
# returns duration, data for closest-to-average sample
return self._avgDataDur, self._avgData
class TaskProfiler:
# this does intermittent profiling of tasks running on the system
# if a task has a spike in execution time, the profile of the spike is logged
notify = directNotify.newCategory("TaskProfiler")
def __init__(self):
self._enableFC = FunctionCall(self._setEnabled, taskMgr.getProfileTasksSV())
# table of task name pattern to TaskTracker
self._namePattern2tracker = {}
self._task = None
# number of samples required before spikes start getting identified
self._minSamples = config.GetInt('profile-task-spike-min-samples', 30)
# defines spike as longer than this multiple of avg task duration
self._spikeThreshold = config.GetFloat('profile-task-spike-threshold', 5.)
# assign getProfileResultString to the taskMgr here, since Task.py can't import PythonUtil
taskMgr._getProfileResultString = getProfileResultString
def destroy(self):
if taskMgr.getProfileTasks():
self._setEnabled(False)
self._enableFC.destroy()
for tracker in self._namePattern2tracker.itervalues():
tracker.destroy()
del self._namePattern2tracker
del self._task
def _setEnabled(self, enabled):
if enabled:
self._taskName = 'profile-tasks-%s' % id(self)
taskMgr.add(self._doProfileTasks, self._taskName, priority=-200)
else:
taskMgr.remove(self._taskName)
del self._taskName
def _doProfileTasks(self, task=None):
# gather data from the previous frame
# set up for the next frame
profileDt = taskMgr._getTaskProfileDt()
if (self._task is not None) and (profileDt is not None):
lastProfileResult = taskMgr._getLastProfileResultString()
if lastProfileResult:
namePattern = self._task.getNamePattern()
if namePattern not in self._namePattern2tracker:
self._namePattern2tracker[namePattern] = TaskTracker(namePattern)
tracker = self._namePattern2tracker[namePattern]
# do we have enough samples?
if tracker.getNumDurationSamples() > self._minSamples:
# was this a spike?
if profileDt > (tracker.getAvgDuration() * self._spikeThreshold):
avgDur, avgResult = tracker.getAvgData()
self.notify.info('task CPU spike profile (%s):\n'
'AVERAGE PROFILE (%s wall-clock seconds)\n%s\n'
'SPIKE PROFILE (%s wall-clock seconds)\n%s' % (
namePattern, avgDur, avgResult, profileDt, lastProfileResult))
tracker.addDuration(profileDt, lastProfileResult)
# set up the next task
self._task = taskMgr._getRandomTask()
taskMgr._setProfileTask(self._task)
return task.cont