summaryrefslogtreecommitdiff
path: root/scripts
diff options
context:
space:
mode:
authorJose Fonseca <jfonseca@vmware.com>2016-01-19 14:41:55 +0000
committerJose Fonseca <jfonseca@vmware.com>2016-01-22 22:37:46 +0000
commit771c34f3caba89becd97cb819a2241538571966b (patch)
tree2d2d124ea57c9f7382281161df5dd765c9ffda5b /scripts
parenta20a795cb585b75d4d03d671a9a235ca67d3418d (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-xscripts/leaks.py67
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():