added task leak detection to ContainerLeakDetector

This commit is contained in:
Darren Ranalli 2008-04-29 23:50:55 +00:00
parent 532a37945f
commit ded092dc32
3 changed files with 99 additions and 3 deletions

View File

@ -27,6 +27,22 @@ def _createContainerLeak():
return task.done
leakContainer()
def _createTaskLeak():
leakTaskName = uniqueName('leakedTask')
leakDoLaterName = uniqueName('leakedDoLater')
def nullTask(task=None):
return task.cont
def nullDoLater(task=None):
return task.done
def leakTask(task=None, leakTaskName=leakTaskName):
base = getBase()
taskMgr.add(nullTask, uniqueName(leakTaskName))
taskMgr.doMethodLater(1 << 31, nullDoLater, uniqueName(leakDoLaterName))
taskMgr.doMethodLater(10, leakTask, 'doLeakTask-%s' % serialNum())
if task:
return task.done
leakTask()
class NoDictKey:
pass
@ -336,7 +352,8 @@ class FindContainers(Job):
# if it's an internal object, ignore it
if id(obj) in ContainerLeakDetector.PrivateIds:
return True
if objName in ('im_self', 'im_class'):
# prevent crashes in objects that define __cmp__ and don't handle strings
if type(objName) == types.StringType and objName in ('im_self', 'im_class'):
return True
try:
className = obj.__class__.__name__
@ -818,6 +835,8 @@ class ContainerLeakDetector(Job):
if config.GetBool('leak-container', 0):
_createContainerLeak()
if config.GetBool('leak-tasks', 0):
_createTaskLeak()
# don't check our own tables for leaks
ContainerLeakDetector.addPrivateObj(ContainerLeakDetector.PrivateIds)

View File

@ -10,9 +10,15 @@ class LeakDetector:
# ContainerLeakDetector will find it quickly
if not hasattr(__builtin__, "leakDetectors"):
__builtin__.leakDetectors = {}
leakDetectors[id(self)] = self
self._leakDetectorsKey = self.getLeakDetectorKey()
leakDetectors[self._leakDetectorsKey] = self
def destroy(self):
del leakDetectors[id(self)]
del leakDetectors[self._leakDetectorsKey]
def getLeakDetectorKey(self):
# this string will be shown to the end user and should ideally contain enough information to
# point to what is leaking
return '%s-%s' % (self.__class__.__name__, id(self))
class GarbageLeakDetector(LeakDetector):
# are we accumulating Python garbage?
@ -60,3 +66,58 @@ class CppMemoryUsage(LeakDetector):
return int(MemoryUsage.getCppSize())
else:
return 0
class TaskLeakDetectorBase:
def _getTaskNamePattern(self, taskName):
# get a generic string pattern from a task name by removing numeric characters
for i in xrange(10):
taskName = taskName.replace('%s' % i, '')
return taskName
class _TaskNamePatternLeakDetector(LeakDetector, TaskLeakDetectorBase):
# tracks the number of each individual task type
# e.g. are we leaking 'examine-<doId>' tasks
def __init__(self, taskNamePattern):
self._taskNamePattern = taskNamePattern
LeakDetector.__init__(self)
def __len__(self):
# count the number of tasks that match our task name pattern
numTasks = 0
for task in taskMgr.getTasks():
if self._getTaskNamePattern(task.name) == self._taskNamePattern:
numTasks += 1
for task in taskMgr.getDoLaters():
if self._getTaskNamePattern(task.name) == self._taskNamePattern:
numTasks += 1
return numTasks
def getLeakDetectorKey(self):
return '%s-%s' % (self._taskNamePattern, LeakDetector.getLeakDetectorKey(self))
class TaskLeakDetector(LeakDetector, TaskLeakDetectorBase):
# tracks the number task 'types' and creates leak detectors for each task type
def __init__(self):
LeakDetector.__init__(self)
self._taskName2collector = {}
def destroy(self):
for taskName, collector in self._taskName2collector.iteritems():
collector.destroy()
del self._taskName2collector
LeakDetector.destroy(self)
def _processTaskName(self, taskName):
# if this is a new task name pattern, create a leak detector for that pattern
namePattern = self._getTaskNamePattern(taskName)
if namePattern not in self._taskName2collector:
self._taskName2collector[namePattern] = _TaskNamePatternLeakDetector(namePattern)
def __len__(self):
# update our table of task leak detectors
for task in taskMgr.getTasks():
self._processTaskName(task.name)
for task in taskMgr.getDoLaters():
self._processTaskName(task.name)
# are we leaking task types?
return len(self._taskName2collector)

View File

@ -1105,6 +1105,22 @@ class TaskManager:
str += "End of taskMgr info\n"
return str
def getTasks(self):
# returns list of all tasks in arbitrary order
tasks = []
for taskPriList in self.taskList:
for task in taskPriList:
if task is not None:
tasks.append(task)
for pri, taskList in self.pendingTaskDict.iteritems():
for task in taskList:
tasks.append(task)
return tasks
def getDoLaters(self):
# returns list of all doLaters in arbitrary order
return self.__doLaterList[:]
def resetStats(self):
# WARNING: this screws up your do-later timings
if self.taskTimerVerbose: