diff options
author | Jose Fonseca <jfonseca@vmware.com> | 2016-01-19 14:41:55 +0000 |
---|---|---|
committer | Jose Fonseca <jfonseca@vmware.com> | 2016-01-22 22:37:46 +0000 |
commit | 771c34f3caba89becd97cb819a2241538571966b (patch) | |
tree | 2d2d124ea57c9f7382281161df5dd765c9ffda5b /scripts | |
parent | a20a795cb585b75d4d03d671a9a235ca67d3418d (diff) |
scripts: Generalize leak detection to other object kinds.
Basically port comicfans's 7a77d4a29a2e16e56fc149ac5fb0c681340c3968
logic to Python.
Issue #416.
Diffstat (limited to 'scripts')
-rwxr-xr-x | scripts/leaks.py | 67 |
1 files changed, 45 insertions, 22 deletions
diff --git a/scripts/leaks.py b/scripts/leaks.py index 6349f84b..1115bfb1 100755 --- a/scripts/leaks.py +++ b/scripts/leaks.py @@ -29,6 +29,7 @@ import subprocess import sys import os.path import optparse +import re import unpickle @@ -36,7 +37,8 @@ import unpickle class ContextState: def __init__(self): - self.textures = {} + # a map of maps + self.objectDicts = {} class LeakDetector(unpickle.Unpickler): @@ -56,33 +58,34 @@ class LeakDetector(unpickle.Unpickler): # Reached the end of the trace -- dump any live objects self.dumpLeaks("<EOF>", self.context) + genDelRegExp = re.compile('^gl(Gen|Delete)(Buffers|Textures|FrameBuffers|RenderBuffers)[A-Z]*$') + def handleCall(self, call): # Ignore calls without side effects if call.flags & unpickle.CALL_FLAG_NO_SIDE_EFFECTS: return # Dump call for debugging: - if False: - sys.stderr.write(str(call)) + if 0: + sys.stderr.write('%s\n' % call) # FIXME: keep track of current context on each thread (*MakeCurrent) context = self.context - if call.functionName == 'glGenTextures': - n, textures = call.argValues() - for i in range(n): - texture = textures[i] - context.textures[texture] = call.no - - if call.functionName == 'glDeleteTextures': - n, textures = call.argValues() - for i in range(n): - texture = textures[i] - try: - del context.textures[texture] - except KeyError: - # Ignore if texture name was never generated - pass + mo = self.genDelRegExp.match(call.functionName) + if mo: + verb = mo.group(1) + subject = mo.group(2) + + subject = subject.lower().rstrip('s') + objectDict = context.objectDicts.setdefault(subject, {}) + + if verb == 'Gen': + self.handleGenerate(call, objectDict) + elif verb == 'Delete': + self.handleDelete(call, objectDict) + else: + assert 0 if call.functionName in [ 'glXDestroyContext', @@ -91,10 +94,30 @@ class LeakDetector(unpickle.Unpickler): ]: self.dumpLeaks(call.no, context) - def dumpLeaks(self, callNo, context): - for textureName, textureCallNo in context.textures.iteritems(): - sys.stderr.write('%u: error: texture %u was not destroyed until %s\n' % (textureCallNo, textureName, callNo)) - context.textures.clear() + def handleGenerate(self, call, objectDict): + n, names = call.argValues() + for i in range(n): + name = names[i] + objectDict[name] = call.no + + def handleDelete(self, call, objectDict): + n, names = call.argValues() + for i in range(n): + name = names[i] + try: + del objectDict[name] + except KeyError: + # Ignore if texture name was never generated + pass + + def dumpLeaks(self, currentCallNo, context): + for kind, objectDict in context.objectDicts.iteritems(): + self.dumpNamespaceLeaks(currentCallNo, objectDict, kind) + + def dumpNamespaceLeaks(self, currentCallNo, objectDict, kind): + for name, creationCallNo in objectDict.iteritems(): + sys.stderr.write('%u: error: %s %u was not destroyed until %s\n' % (creationCallNo, kind, name, currentCallNo)) + objectDict.clear() def main(): |