]> git.cworth.org Git - apitrace/commitdiff
Drop python trace parsing code.
authorJosé Fonseca <jose.r.fonseca@gmail.com>
Sat, 20 Aug 2011 12:47:18 +0000 (13:47 +0100)
committerJosé Fonseca <jose.r.fonseca@gmail.com>
Sat, 20 Aug 2011 12:53:51 +0000 (13:53 +0100)
It's too troublesome to maintain two different implementations of the
same thing.

scripts/format.py [deleted file]
scripts/trace.py [deleted file]
scripts/tracediff.py [deleted file]

diff --git a/scripts/format.py b/scripts/format.py
deleted file mode 100644 (file)
index 6a799c2..0000000
+++ /dev/null
@@ -1,170 +0,0 @@
-##########################################################################
-#
-# Copyright 2008-2009 VMware, Inc.
-# All Rights Reserved.
-#
-# Permission is hereby granted, free of charge, to any person obtaining a copy
-# of this software and associated documentation files (the "Software"), to deal
-# in the Software without restriction, including without limitation the rights
-# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-# copies of the Software, and to permit persons to whom the Software is
-# furnished to do so, subject to the following conditions:
-#
-# The above copyright notice and this permission notice shall be included in
-# all copies or substantial portions of the Software.
-#
-# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
-# THE SOFTWARE.
-#
-##########################################################################/
-
-
-import sys
-
-
-class Formatter:
-    '''Plain formatter'''
-
-    def __init__(self, stream):
-        self.stream = stream
-
-    def text(self, text):
-        self.stream.write(text)
-
-    def newline(self):
-        self.text('\n')
-
-    def function(self, name):
-        self.text(name)
-
-    def variable(self, name):
-        self.text(name)
-
-    def literal(self, value):
-        self.text(str(value))
-
-    def address(self, addr):
-        self.text(str(addr))
-
-
-class AnsiFormatter(Formatter):
-    '''Formatter for plain-text files which outputs ANSI escape codes. See
-    http://en.wikipedia.org/wiki/ANSI_escape_code for more information
-    concerning ANSI escape codes.
-    '''
-
-    _csi = '\33['
-
-    _normal = '0m'
-    _bold = '1m'
-    _italic = '3m'
-    _red = '31m'
-    _green = '32m'
-    _blue = '34m'
-
-    def _escape(self, code):
-        self.text(self._csi + code)
-
-    def function(self, name):
-        self._escape(self._bold)
-        Formatter.function(self, name)
-        self._escape(self._normal)
-
-    def variable(self, name):
-        self._escape(self._italic)
-        Formatter.variable(self, name)
-        self._escape(self._normal)
-
-    def literal(self, value):
-        self._escape(self._blue)
-        Formatter.literal(self, value)
-        self._escape(self._normal)
-
-    def address(self, value):
-        self._escape(self._green)
-        Formatter.address(self, value)
-        self._escape(self._normal)
-
-
-class WindowsConsoleFormatter(Formatter):
-    '''Formatter for the Windows Console. See 
-    http://code.activestate.com/recipes/496901/ for more information.
-    '''
-
-    STD_INPUT_HANDLE  = -10
-    STD_OUTPUT_HANDLE = -11
-    STD_ERROR_HANDLE  = -12
-
-    FOREGROUND_BLUE      = 0x01
-    FOREGROUND_GREEN     = 0x02
-    FOREGROUND_RED       = 0x04
-    FOREGROUND_INTENSITY = 0x08
-    BACKGROUND_BLUE      = 0x10
-    BACKGROUND_GREEN     = 0x20
-    BACKGROUND_RED       = 0x40
-    BACKGROUND_INTENSITY = 0x80
-
-    _normal = FOREGROUND_BLUE | FOREGROUND_GREEN | FOREGROUND_RED
-    _bold = FOREGROUND_BLUE | FOREGROUND_GREEN | FOREGROUND_RED | FOREGROUND_INTENSITY
-    _italic = FOREGROUND_BLUE | FOREGROUND_GREEN | FOREGROUND_RED
-    _red = FOREGROUND_RED | FOREGROUND_INTENSITY
-    _green = FOREGROUND_GREEN | FOREGROUND_INTENSITY
-    _blue = FOREGROUND_BLUE | FOREGROUND_INTENSITY
-
-    def __init__(self, stream):
-        Formatter.__init__(self, stream)
-
-        if stream is sys.stdin:
-            nStdHandle = self.STD_INPUT_HANDLE
-        elif stream is sys.stdout:
-            nStdHandle = self.STD_OUTPUT_HANDLE
-        elif stream is sys.stderr:
-            nStdHandle = self.STD_ERROR_HANDLE
-        else:
-            nStdHandle = None
-
-        if nStdHandle:
-            import ctypes
-            self.handle = ctypes.windll.kernel32.GetStdHandle(nStdHandle)
-        else:
-            self.handle = None
-
-    def _attribute(self, attr):
-        if self.handle:
-            import ctypes
-            ctypes.windll.kernel32.SetConsoleTextAttribute(self.handle, attr)
-
-    def function(self, name):
-        self._attribute(self._bold)
-        Formatter.function(self, name)
-        self._attribute(self._normal)
-
-    def variable(self, name):
-        self._attribute(self._italic)
-        Formatter.variable(self, name)
-        self._attribute(self._normal)
-
-    def literal(self, value):
-        self._attribute(self._blue)
-        Formatter.literal(self, value)
-        self._attribute(self._normal)
-
-    def address(self, value):
-        self._attribute(self._green)
-        Formatter.address(self, value)
-        self._attribute(self._normal)
-
-
-def DefaultFormatter(stream):
-    if sys.platform in ('linux2', 'cygwin'):
-        return AnsiFormatter(stream)
-    elif sys.platform in ('win32',):
-        return WindowsConsoleFormatter(stream)
-    else:
-        return Formatter(stream)
-
diff --git a/scripts/trace.py b/scripts/trace.py
deleted file mode 100755 (executable)
index 3ab6ce2..0000000
+++ /dev/null
@@ -1,588 +0,0 @@
-#!/usr/bin/env python
-##########################################################################
-#
-# Copyright 2011 Jose Fonseca
-# All Rights Reserved.
-#
-# Permission is hereby granted, free of charge, to any person obtaining a copy
-# of this software and associated documentation files (the 'Software'), to deal
-# in the Software without restriction, including without limitation the rights
-# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-# copies of the Software, and to permit persons to whom the Software is
-# furnished to do so, subject to the following conditions:
-#
-# The above copyright notice and this permission notice shall be included in
-# all copies or substantial portions of the Software.
-#
-# THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
-# THE SOFTWARE.
-#
-##########################################################################/
-
-
-import gzip
-import string
-import struct
-import sys
-
-try:
-    from cStringIO import StringIO
-except ImportError:
-    from StringIO import StringIO
-
-import format
-
-
-class GzipFile(gzip.GzipFile):
-
-    def _read_eof(self):
-        # Ignore incomplete files
-        try:
-            gzip.GzipFile._read_eof(self)
-        except IOError:
-            pass
-
-
-TRACE_VERSION = 1
-
-EVENT_ENTER, EVENT_LEAVE = range(2)
-
-CALL_END, CALL_ARG, CALL_RET, CALL_THREAD = range(4)
-
-TYPE_NULL, TYPE_FALSE, TYPE_TRUE, TYPE_SINT, TYPE_UINT, TYPE_FLOAT, TYPE_DOUBLE, TYPE_STRING, TYPE_BLOB, TYPE_ENUM, TYPE_BITMASK, TYPE_ARRAY, TYPE_STRUCT, TYPE_OPAQUE = range(14)
-
-
-class Signature:
-    '''Dummy class for signatures.'''
-
-    pass
-
-
-class Node:
-
-    def visit(self, visitor):
-        raise NotImplementedError
-
-    def pretty_print(self, formatter):
-        pretty_printer = PrettyPrinter(formatter)
-        self.visit(pretty_printer)
-
-    def __str__(self):
-        stream = StringIO()
-        formatter = format.Formatter(stream)
-        self.pretty_print(formatter)
-        return stream.getvalue()
-
-    def __eq__(self, other):
-        raise NotImplementedError
-
-    def __hash__(self):
-        raise NotImplementedError
-
-
-class Literal(Node):
-
-    def __init__(self, value):
-        self.value = value
-
-    def visit(self, visitor):
-        visitor.visit_literal(self)
-
-    def __eq__(self, other):
-        return \
-            self.__class__ == other.__class__ and \
-            self.value == other.value
-
-    def __hash__(self):
-        return hash(self.value)
-
-
-class Enum(Node):
-
-    def __init__(self, name, value):
-        self.name = name
-        self.value = value
-
-    def visit(self, visitor):
-        visitor.visit_enum(self)
-
-    def __eq__(self, other):
-        return \
-            self.__class__ == other.__class__ and \
-            self.name == other.name and \
-            self.value == other.value
-
-    def __hash__(self):
-        return hash(self.value)
-
-
-class Array(Node):
-
-    def __init__(self, elements):
-        self.elements = tuple(elements)
-
-    def visit(self, visitor):
-        visitor.visit_array(self)
-
-    def __eq__(self, other):
-        return \
-            self.__class__ == other.__class__ and \
-            self.elements == other.elements
-
-    def __hash__(self):
-        return hash(self.elements)
-
-
-class Pointer(Node):
-
-    def __init__(self, value):
-        self.value = value
-
-    def visit(self, visitor):
-        visitor.visit_pointer(self)
-
-    def __eq__(self, other):
-        return \
-            self.__class__ == other.__class__ and \
-            self.value == other.value
-
-    def __hash__(self):
-        return hash(self.value)
-
-
-def Null():
-    return Enum("NULL", 0)
-
-def Bitmask(sig, value):
-    return Literal(value)
-
-def Blob(buf):
-    return Literal('blob(%u)' % len(buf))
-
-
-class Struct(Node):
-
-    def __init__(self, sig, members):
-        self.sig = sig
-        self.members = tuple(members)
-
-    def visit(self, visitor):
-        visitor.visit_struct(self)
-
-    def __eq__(self, other):
-        return \
-            self.__class__ == other.__class__ and \
-            self.sig.member_names == other.sig.member_names and \
-            self.members == other.members
-
-    def __hash__(self):
-        return hash(self.sig.member_names) ^ hash(self.members)
-
-
-class Call(Node):
-
-    def __init__(self, sig):
-        self.sig = sig
-        self.args = [None] * len(sig.arg_names)
-        self.ret = None
-
-    def get_name(self):
-        return self.sig.name
-
-    name = property(get_name)
-
-    def visit(self, visitor):
-        visitor.visit_call(self)
-
-    def __eq__(self, other):
-        return \
-            self.__class__ == other.__class__ and \
-            self.sig.name == other.sig.name and \
-            self.args == other.args and \
-            self.ret == other.ret
-
-    def __hash__(self):
-        return hash(self.sig.name) ^ hash(tuple(self.args)) ^ hash(self.ret)
-
-
-class Trace(Node):
-
-    def __init__(self, calls):
-        self.calls = calls
-
-    def visit(self, visitor):
-        visitor.visit_trace(self)
-
-
-class Visitor:
-
-    def visit_literal(self, node):
-        raise NotImplementedError
-
-    def visit_enum(self, node):
-        raise NotImplementedError
-
-    def visit_array(self, node):
-        raise NotImplementedError
-
-    def visit_struct(self, node):
-        raise NotImplementedError
-
-    def visit_pointer(self, node):
-        raise NotImplementedError
-
-    def visit_call(self, node):
-        raise NotImplementedError
-
-    def visit_trace(self, node):
-        raise NotImplementedError
-
-
-class PrettyPrinter:
-
-    def __init__(self, formatter):
-        self.formatter = formatter
-
-    def visit_literal(self, node):
-        if isinstance(node.value, basestring):
-            if len(node.value) >= 4096 or node.value.strip(string.printable):
-                self.formatter.text('...')
-                return
-
-            self.formatter.literal('"' + node.value + '"')
-            return
-
-        self.formatter.literal(repr(node.value))
-
-    def visit_enum(self, node):
-        self.formatter.literal(node.name)
-
-    def visit_array(self, node):
-        self.formatter.text('{')
-        sep = ''
-        for value in node.elements:
-            self.formatter.text(sep)
-            value.visit(self)
-            sep = ', '
-        self.formatter.text('}')
-
-    def visit_struct(self, node):
-        self.formatter.text('{')
-        sep = ''
-        for name, value in zip(node.sig.member_names, node.members):
-            self.formatter.text(sep)
-            self.formatter.variable(name)
-            self.formatter.text(' = ')
-            value.visit(self)
-            sep = ', '
-        self.formatter.text('}')
-
-    def visit_pointer(self, node):
-        self.formatter.address(node.value)
-
-    def visit_call(self, node):
-        #self.formatter.text('%s ' % node.no)
-        self.formatter.function(node.name)
-        self.formatter.text('(')
-        sep = ''
-        for name, value in zip(node.sig.arg_names, node.args):
-            self.formatter.text(sep)
-            self.formatter.variable(name)
-            self.formatter.text(' = ')
-            value.visit(self)
-            sep = ', '
-        self.formatter.text(')')
-        if node.ret is not None:
-            self.formatter.text(' = ')
-            node.ret.visit(self)
-
-    def visit_trace(self, node):
-        for call in node.calls:
-            call.visit(self)
-            self.formatter.newline()
-
-
-class Parser:
-
-    debug = False
-
-    def __init__(self):
-        self.file = None
-        self.next_call_no = 0
-        self.version = 0
-
-        self.functions = {}
-        self.enums = {}
-        self.bitmasks = {}
-        self.structs = {}
-
-        self.calls = []
-
-    def open(self, filename):
-        self.file = GzipFile(filename, "rb")
-        if not self.file:
-            return False
-
-        version = self.read_uint()
-        if version > TRACE_VERSION:
-            sys.stderr.write("error: unsupported trace format version %u\n" % version)
-            return False
-
-        return True
-
-    def parse_call(self):
-        if self.debug:
-            sys.stdout.flush()
-        while True:
-            c = self.read_byte()
-            if c == EVENT_ENTER:
-                self.parse_enter()
-            elif c == EVENT_LEAVE:
-                return self.parse_leave()
-            elif c == -1:
-                return None
-            else:
-                sys.stderr.write("error: unknown event %i\n" % c)
-                sys.exit(1)
-
-    def parse_enter(self):
-        id = self.read_uint()
-
-        try:
-            sig = self.functions[id]
-        except KeyError:
-            sig = Signature()
-            sig.name = self.read_string()
-            num_args = self.read_uint()
-            sig.arg_names = tuple([self.read_string() for i in range(num_args)])
-            self.functions[id] = sig
-
-        call = Call(sig)
-        call.no = self.next_call_no
-        self.next_call_no += 1
-
-        if self.parse_call_details(call):
-            self.calls.append(call)
-        else:
-            del call
-
-    def parse_leave(self):
-        call_no = self.read_uint()
-        call = None
-        for i in range(len(self.calls)):
-            if self.calls[i].no == call_no:
-                call = self.calls.pop(i)
-                break
-        if call is None:
-            return None
-
-        if self.parse_call_details(call):
-            return call
-        else:
-            del call
-            return None
-
-    def parse_call_details(self, call):
-        while True:
-            c = self.read_byte()
-            if c == CALL_END:
-                return True
-            elif c == CALL_ARG:
-                self.parse_arg(call)
-            elif c == CALL_RET:
-                call.ret = self.parse_value()
-            else:
-                sys.stderr.write("error: unknown call detail %i\n" % c)
-                sys.exit(1)
-
-    def parse_arg(self, call):
-        index = self.read_uint()
-        value = self.parse_value()
-        if index >= len(call.args):
-            call.args.resize(index + 1)
-        call.args[index] = value
-        if self.debug:
-            sys.stderr.write("\tARG %i %s\n" % (index, value))
-
-    def parse_value(self):
-        c = self.read_byte()
-        if c == TYPE_NULL:
-            value = Null()
-        elif c == TYPE_FALSE:
-            value = Literal(False)
-        elif c == TYPE_TRUE:
-            value = Literal(True)
-        elif c == TYPE_SINT:
-            value = self.parse_sint()
-        elif c == TYPE_UINT:
-            value = self.parse_uint()
-        elif c == TYPE_FLOAT:
-            value = self.parse_float()
-        elif c == TYPE_DOUBLE:
-            value = self.parse_double()
-        elif c == TYPE_STRING:
-            value = self.parse_string()
-        elif c == TYPE_ENUM:
-            value = self.parse_enum()
-        elif c == TYPE_BITMASK:
-            value = self.parse_bitmask()
-        elif c == TYPE_ARRAY:
-            value = self.parse_array()
-        elif c == TYPE_STRUCT:
-            value = self.parse_struct()
-        elif c == TYPE_BLOB:
-            value = self.parse_blob()
-        elif c == TYPE_OPAQUE:
-            value = self.parse_opaque()
-        else:
-            sys.stderr.write("error: unknown type %i\n" % c)
-            sys.exit(1)
-        if self.debug:
-            sys.stderr.write("\tVALUE %s\n" % value)
-        return value
-
-    def parse_sint(self):
-        return Literal(-self.read_uint())
-
-    def parse_uint(self):
-        return Literal(self.read_uint())
-
-    def parse_float(self):
-        value = self.file.read(4)
-        value, = struct.unpack('f', value)
-        return Literal(value)
-
-    def parse_double(self):
-        value = self.file.read(8)
-        value, = struct.unpack('d', value)
-        return Literal(value)
-
-    def parse_string(self):
-        return Literal(self.read_string())
-
-    def parse_enum(self):
-        id = self.read_uint()
-        try:
-            enum = self.enums[id]
-        except KeyError:
-            name = self.read_string()
-            value = self.parse_value()
-            enum = Enum(name, value)
-            self.enums[id] = enum
-        return enum
-
-    def parse_bitmask(self):
-        id = self.read_uint()
-        try:
-            sig = self.bitmasks[id]
-        except KeyError:
-            sig = Signature()
-            num_flags = self.read_uint()
-            sig.flags = []
-            for i in range(num_flags):
-                name = self.read_string()
-                value = self.read_uint()
-                if value == 0 and i:
-                    sys.stderr.write("warning: bitmask %s is zero but is not first flag\n" % name)
-                flag = name, value
-                sig.flags.append(flag)
-            self.bitmasks[id] = sig
-        assert sig
-
-        value = self.read_uint()
-
-        return Bitmask(sig, value)
-
-    def parse_array(self):
-        size = self.read_uint()
-        elements = [self.parse_value() for i in range(size)]
-        return Array(elements)
-
-    def parse_blob(self):
-        size = self.read_uint()
-        if size:
-            buf = self.file.read(size)
-        else:
-            buf = ""
-        return Blob(buf)
-
-    def parse_struct(self):
-        id = self.read_uint()
-
-        try:
-            sig = self.structs[id]
-        except KeyError:
-            sig = Signature()
-            sig.name = self.read_string()
-            num_members = self.read_uint()
-            sig.member_names = tuple([self.read_string() for i in range(num_members)])
-            self.structs[id] = sig
-
-        members = [self.parse_value() for i in range(len(sig.member_names))]
-        value = Struct(sig, members)
-
-        return value
-
-    def parse_opaque(self):
-        addr = self.read_uint()
-        return Pointer(addr)
-
-    def read_string(self):
-        size = self.read_uint()
-        if size:
-            value = self.file.read(size)
-        else:
-            value = ''
-        if self.debug:
-            sys.stderr.write("\tSTRING \"%s\"\n" % value)
-        return value
-
-    def read_uint(self):
-        value = 0
-        shift = 0
-        while True:
-            c = self.file.read(1)
-            if c == "":
-                return 0
-            c = ord(c)
-            value |= (c & 0x7f) << shift
-            shift += 7
-            if c & 0x80 == 0:
-                break
-        if self.debug:
-            sys.stderr.write("\tUINT %u\n" % value)
-        return value
-
-    def read_byte(self):
-        c = self.file.read(1)
-        if c == "":
-            if self.debug:
-                sys.stderr.write("\tEOF\n")
-            return -1
-        else:
-            c = ord(c)
-            if self.debug:
-                sys.stderr.write("\tBYTE 0x%x\n" % c)
-        return c
-
-
-def main():
-    formatter = format.DefaultFormatter(sys.stdout)
-    for arg in sys.argv[1:]:
-        parser = Parser()
-        parser.open(arg)
-        call = parser.parse_call()
-        while call:
-            formatter.text('%u ' % call.no)
-            call.pretty_print(formatter)
-            formatter.text('\n')
-            call = parser.parse_call()
-
-
-if __name__ == '__main__':
-    main()
diff --git a/scripts/tracediff.py b/scripts/tracediff.py
deleted file mode 100755 (executable)
index f588562..0000000
+++ /dev/null
@@ -1,189 +0,0 @@
-#!/usr/bin/env python
-##########################################################################
-#
-# Copyright 2011 Jose Fonseca
-# All Rights Reserved.
-#
-# Permission is hereby granted, free of charge, to any person obtaining a copy
-# of this software and associated documentation files (the 'Software'), to deal
-# in the Software without restriction, including without limitation the rights
-# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-# copies of the Software, and to permit persons to whom the Software is
-# furnished to do so, subject to the following conditions:
-#
-# The above copyright notice and this permission notice shall be included in
-# all copies or substantial portions of the Software.
-#
-# THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
-# THE SOFTWARE.
-#
-##########################################################################/
-
-
-import difflib
-import optparse
-import os.path
-import sys
-
-from trace import Parser
-
-try:
-    import debug
-except ImportError:
-    pass
-
-
-ignored_function_names = set([
-    'glGetString',
-    'glXGetClientString',
-    'glXGetCurrentDisplay',
-    'glXGetProcAddress',
-    'glXGetProcAddressARB',
-    'wglGetProcAddress',
-])
-
-
-def readtrace(trace, limit=sys.maxint):
-    calls = []
-    parser = Parser()
-    parser.open(trace)
-    call = parser.parse_call()
-    while call and len(calls) < limit:
-        hash(call)
-        if call.sig.name not in ignored_function_names:
-            calls.append(call)
-        call = parser.parse_call()
-    return calls
-
-
-class SDiffer:
-
-    def __init__(self, a, b):
-        self.a = a
-        self.b = b
-
-    def diff(self):
-        matcher = difflib.SequenceMatcher(None, self.a, self.b)
-        for tag, alo, ahi, blo, bhi in matcher.get_opcodes():
-            if tag == 'replace':
-                self.replace(alo, ahi, blo, bhi)
-            elif tag == 'delete':
-                self.delete(alo, ahi)
-            elif tag == 'insert':
-                self.insert(blo, bhi)
-            elif tag == 'equal':
-                self.equal(alo, ahi)
-            else:
-                raise ValueError, 'unknown tag %s' % (tag,)
-
-    def replace(self, alo, ahi, blo, bhi):
-        assert alo < ahi and blo < bhi
-        
-        a_names = [call.name for call in self.a[alo:ahi]]
-        b_names = [call.name for call in self.b[blo:bhi]]
-
-        matcher = difflib.SequenceMatcher(None, a_names, b_names)
-        for tag, _alo, _ahi, _blo, _bhi in matcher.get_opcodes():
-            _alo += alo
-            _ahi += alo
-            _blo += blo
-            _bhi += blo
-            if tag == 'replace':
-                self.replace_dissimilar(_alo, _ahi, _blo, _bhi)
-            elif tag == 'delete':
-                self.delete(_alo, _ahi)
-            elif tag == 'insert':
-                self.insert(_blo, _bhi)
-            elif tag == 'equal':
-                self.replace_similar(_alo, _ahi, _blo, _bhi)
-            else:
-                raise ValueError, 'unknown tag %s' % (tag,)
-
-    def replace_similar(self, alo, ahi, blo, bhi):
-        assert alo < ahi and blo < bhi
-        assert ahi - alo == bhi - blo
-        for i in xrange(0, bhi - blo):
-            a_call = self.a[alo + i]
-            b_call = self.b[blo + i]
-            assert a_call.name == b_call.name
-            assert len(a_call.args) == len(b_call.args)
-            sys.stdout.write(b_call.name + '(')
-            sep = ''
-            for j in xrange(len(b_call.args)):
-                sys.stdout.write(sep)
-                self.replace_value(a_call.args[j], b_call.args[j])
-                sep = ', '
-            sys.stdout.write(')')
-            if a_call.ret is not None or b_call.ret is not None:
-                sys.stdout.write(' = ')
-                self.replace_value(a_call.ret, b_call.ret)
-            sys.stdout.write('\n')
-
-    def replace_dissimilar(self, alo, ahi, blo, bhi):
-        assert alo < ahi and blo < bhi
-        if bhi - blo < ahi - alo:
-            first  = self.insert(blo, bhi)
-            second = self.delete(alo, ahi)
-        else:
-            first  = self.delete(alo, ahi)
-            second = self.insert(blo, bhi)
-
-        for g in first, second:
-            for line in g:
-                yield line
-
-    def replace_value(self, a, b):
-        if b == a:
-            sys.stdout.write(str(b))
-        else:
-            sys.stdout.write('%s -> %s' % (a, b))
-
-    escape = "\33["
-
-    def delete(self, alo, ahi):
-        self.dump('- ' + self.escape + '9m', self.a, alo, ahi, self.escape + '0m')
-
-    def insert(self, blo, bhi):
-        self.dump('+ ', self.b, blo, bhi)
-
-    def equal(self, alo, ahi):
-        self.dump('  ' + self.escape + '2m', self.a, alo, ahi, self.escape + '0m')
-
-    def dump(self, prefix, x, lo, hi, suffix=""):
-        for i in xrange(lo, hi):
-            sys.stdout.write(prefix + str(x[i]) + suffix + '\n')
-
-
-def main():
-    global options
-
-    optparser = optparse.OptionParser(
-        usage='\n\t%prog <trace> <trace>',
-        version='%%prog')
-    optparser.add_option(
-        '-d', '--tracedump', metavar='PROGRAM',
-        type='string', dest='tracedump', default='tracedump',
-        help='tracedump command [default: %default]')
-    optparser.add_option(
-        '-l', '--limit', metavar='CALLS',
-        type='int', dest='limit', default=1000,
-        help='limit the number of calls [default: %default]')
-
-    (options, args) = optparser.parse_args(sys.argv[1:])
-    if len(args) != 2:
-        optparser.error("incorrect number of arguments")
-
-    ref_calls = readtrace(args[0], options.limit)
-    src_calls = readtrace(args[1], options.limit)
-
-    differ = SDiffer(ref_calls, src_calls)
-    differ.diff()
-
-
-if __name__ == '__main__':
-    main()