Skip to content

Commit

Permalink
scripts: Generalize leak detection to other object kinds.
Browse files Browse the repository at this point in the history
Basically port comicfans's 7a77d4a
logic to Python.

Issue #416.
  • Loading branch information
jrfonseca committed Jan 19, 2016
1 parent 6cfcdcf commit 6431d58
Showing 1 changed file with 45 additions and 22 deletions.
67 changes: 45 additions & 22 deletions scripts/leaks.py
Expand Up @@ -29,14 +29,16 @@
import sys
import os.path
import optparse
import re

import unpickle


class ContextState:

def __init__(self):
self.textures = {}
# a map of maps
self.objectDicts = {}


class LeakDetector(unpickle.Unpickler):
Expand All @@ -56,33 +58,34 @@ def parse(self):
# 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',
Expand All @@ -91,10 +94,30 @@ def handleCall(self, call):
]:
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():
Expand Down

0 comments on commit 6431d58

Please sign in to comment.