From 47cf67e4c7a9cbb031c38c50f1ec2732d14558a2 Mon Sep 17 00:00:00 2001 From: =?utf8?q?Jos=C3=A9=20Fonseca?= Date: Sat, 17 Mar 2012 21:07:02 +0000 Subject: [PATCH] Optimize tracediff2. --- scripts/tracediff2.py | 40 +++++++++++++++++-- scripts/unpickle.py | 91 +++++++++++++++++++++++++++++-------------- 2 files changed, 97 insertions(+), 34 deletions(-) diff --git a/scripts/tracediff2.py b/scripts/tracediff2.py index 3f14d36..d6fd392 100755 --- a/scripts/tracediff2.py +++ b/scripts/tracediff2.py @@ -32,7 +32,7 @@ import os.path import subprocess import sys -from unpickle import Unpickler, Dumper +from unpickle import Unpickler, Dumper, Rebuilder from highlight import ColorHighlighter, LessHighlighter @@ -46,16 +46,45 @@ ignoredFunctionNames = set([ ]) +class Blob: + '''Data-less proxy for bytearrays, to save memory.''' + + def __init__(self, size, hash): + self.size = size + self.hash = hash + + def __repr__(self): + return 'blob(%u)' % self.size + + def __eq__(self, other): + return self.size == other.size and self.hash == other.hash + + def __hash__(self): + return self.hash + + +class BlobReplacer(Rebuilder): + '''Replace blobs with proxys.''' + + def visitByteArray(self, obj): + return Blob(len(obj), hash(str(obj))) + + def visitCall(self, call): + call.args = map(self.visit, call.args) + call.ret = self.visit(call.ret) + + class Loader(Unpickler): def __init__(self, stream): Unpickler.__init__(self, stream) self.calls = [] + self.rebuilder = BlobReplacer() def handleCall(self, call): if call.functionName not in ignoredFunctionNames: + self.rebuilder.visitCall(call) self.calls.append(call) - hash(call) def readtrace(trace, calls): @@ -258,7 +287,7 @@ def main(): help='apitrace command [default: %default]') optparser.add_option( '-c', '--calls', metavar='CALLSET', - type="string", dest="calls", default='1-10000', + type="string", dest="calls", default='*', help="calls to compare [default: %default]") optparser.add_option( '--ref-calls', metavar='CALLSET', @@ -292,7 +321,10 @@ def main(): highlighter = ColorHighlighter() differ = SDiffer(ref_calls, src_calls, highlighter, options.call_nos) - differ.diff() + try: + differ.diff() + except IOError: + pass if __name__ == '__main__': diff --git a/scripts/unpickle.py b/scripts/unpickle.py index 3f0bc42..ab2dc4d 100755 --- a/scripts/unpickle.py +++ b/scripts/unpickle.py @@ -56,40 +56,44 @@ class Visitor: self.dispatch[dict] = self.visitDict self.dispatch[bytearray] = self.visitByteArray - def visit(self, obj, *args, **kwargs): - return self.dispatch[type(obj)](obj, *args, **kwargs) + def visit(self, obj): + method = self.dispatch.get(type(obj), self.visitObj) + return method(obj) - def visitAtom(self, obj, *args, **kwargs): + def visitObj(self, obj): raise NotImplementedError - def visitNone(self, obj, *args, **kwargs): - return self.visitAtom(obj, *args, **kwargs) + def visitAtom(self, obj): + return self.visitObj(obj) - def visitBool(self, obj, *args, **kwargs): - return self.visitAtom(obj, *args, **kwargs) + def visitNone(self, obj): + return self.visitAtom(obj) - def visitInt(self, obj, *args, **kwargs): - return self.visitAtom(obj, *args, **kwargs) + def visitBool(self, obj): + return self.visitAtom(obj) - def visitFloat(self, obj, *args, **kwargs): - return self.visitAtom(obj, *args, **kwargs) + def visitInt(self, obj): + return self.visitAtom(obj) - def visitStr(self, obj, *args, **kwargs): - return self.visitAtom(obj, *args, **kwargs) + def visitFloat(self, obj): + return self.visitAtom(obj) - def visitIterable(self, obj, *args, **kwargs): - raise NotImplementedError + def visitStr(self, obj): + return self.visitAtom(obj) + + def visitIterable(self, obj): + return self.visitObj(obj) - def visitTuple(self, obj, *args, **kwargs): - return self.visitIterable(obj, *args, **kwargs) + def visitTuple(self, obj): + return self.visitIterable(obj) - def visitList(self, obj, *args, **kwargs): - return self.visitIterable(obj, *args, **kwargs) + def visitList(self, obj): + return self.visitIterable(obj) - def visitDict(self, obj, *args, **kwargs): + def visitDict(self, obj): raise NotImplementedError - def visitByteArray(self, obj, *args, **kwargs): + def visitByteArray(self, obj): raise NotImplementedError @@ -97,38 +101,65 @@ class Dumper(Visitor): id_re = re.compile('^[_A-Za-z][_A-Za-z0-9]*$') - def visitAtom(self, obj, *args, **kwargs): + def visitObj(self, obj): return repr(obj) - def visitStr(self, obj, *args, **kwargs): + def visitStr(self, obj): if self.id_re.match(obj): return obj else: return repr(obj) - def visitTuple(self, obj, *args, **kwargs): + def visitTuple(self, obj): return '[' + ', '.join(itertools.imap(self.visit, obj)) + ']' - def visitList(self, obj, *args, **kwargs): + def visitList(self, obj): return '(' + ', '.join(itertools.imap(self.visit, obj)) + ')' - def visitByteArray(self, obj, *args, **kwargs): + def visitByteArray(self, obj): return 'blob(%u)' % len(obj) class Hasher(Visitor): '''Returns a hashable version of the objtree.''' - def visitAtom(self, obj, *args, **kwargs): + def visitObj(self, obj): + return obj + + def visitAtom(self, obj): return obj - def visitIterable(self, obj, *args, **kwargs): + def visitIterable(self, obj): return tuple(itertools.imap(self.visit, obj)) - def visitByteArray(self, obj, *args, **kwargs): + def visitByteArray(self, obj): return str(obj) +class Rebuilder(Visitor): + '''Returns a hashable version of the objtree.''' + + def visitAtom(self, obj): + return obj + + def visitIterable(self, obj): + changed = False + newItems = [] + for oldItem in obj: + newItem = self.visit(oldItem) + if newItem is not oldItem: + changed = True + newItems.append(newItem) + if changed: + klass = type(obj) + return klass(changed) + else: + return obj + + def visitByteArray(self, obj): + return obj + + class Call: def __init__(self, callTuple): @@ -203,7 +234,7 @@ def main(): optparser = optparse.OptionParser( usage="\n\tapitrace pickle trace. %prog [options]") optparser.add_option( - '--quiet', + '-q', '--quiet', action="store_true", dest="quiet", default=False, help="don't dump calls to stdout") -- 2.43.0