]> git.cworth.org Git - apitrace/commitdiff
Merge branch 'master' into compression
authorZack Rusin <zack@kde.org>
Wed, 24 Aug 2011 03:02:10 +0000 (23:02 -0400)
committerZack Rusin <zack@kde.org>
Wed, 24 Aug 2011 03:02:10 +0000 (23:02 -0400)
Conflicts:
trace_writer.cpp

13 files changed:
README.markdown
formatter.hpp
gui/argumentseditor.cpp
scripts/format.py [deleted file]
scripts/trace.py [deleted file]
scripts/tracediff.py [deleted file]
scripts/tracediff.sh
trace.py
trace_model.cpp
trace_model.hpp
trace_writer.cpp
trace_writer.hpp
tracedump.cpp

index e57d0b7ff69bbd98dfd7062e1153e3409fb8f53c..5b34dec786cb67c10a104e7435f37963977d2519 100644 (file)
@@ -172,6 +172,8 @@ Links
 
 About **apitrace**:
 
+* [Official mailing list](http://lists.freedesktop.org/mailman/listinfo/apitrace)
+
 * [Zack Rusin's blog introducing the GUI](http://zrusin.blogspot.com/2011/04/apitrace.html)
 
 * [Jose's Fonseca blog introducing the tool](http://jrfonseca.blogspot.com/2008/07/tracing-d3d-applications.html)
index 040d06d49084feafa191c8232ad708dea3d1e3bb..181e2d1539d5c14bc14e070db1325a31d2593ad4 100644 (file)
@@ -155,12 +155,16 @@ public:
 #endif
 
 
-inline Formatter *defaultFormatter(void) {
+inline Formatter *defaultFormatter(bool color = true) {
+    if (color) {
 #ifdef _WIN32
-    return new WindowsFormatter;
+        return new WindowsFormatter;
 #else
-    return new AnsiFormatter;
+        return new AnsiFormatter;
 #endif
+    } else {
+        return new Formatter;
+    }
 }
 
 
index 0aeafeb4081e8cbe264c8237a05070f3e2399dd9..8848122b60089479c3343eb69a6c7010ca060483 100644 (file)
 static bool
 isVariantEditable(const QVariant &var)
 {
+    if (var.canConvert<ApiArray>()) {
+        ApiArray array = var.value<ApiArray>();
+        QList<QVariant> vals = array.values();
+        if (vals.isEmpty())
+            return false;
+        else
+            return isVariantEditable(vals.first());
+    }
     switch (var.userType()) {
     case QVariant::Bool:
     case QVariant::Int:
@@ -339,6 +347,7 @@ void ArgumentsEditor::accept()
         QString argName = argNames[i];
         QVariant argValue = originalValues[i];
         QVariant editorValue = valueForName(argName, argValue, &valChanged);
+
         newValues.append(editorValue);
 #if 0
         qDebug()<<"Arg = "<<argName;
@@ -368,6 +377,10 @@ QVariant ArgumentsEditor::valueForName(const QString &name,
         return arrayFromEditor(array, changed);
     }
 
+    if (!isVariantEditable(originalValue)) {
+        return originalValue;
+    }
+
     for (int topRow = 0; topRow < m_model->rowCount(); ++topRow) {
         QModelIndex nameIdx = m_model->index(topRow, 0, QModelIndex());
         QString argName = nameIdx.data().toString();
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()
index 77d844873a6d4cb6f649f1ea7da61be9b2089189..4449d758ebdc62a0ceebccf1fa2d8f081ff8c123 100755 (executable)
@@ -31,10 +31,8 @@ TRACEDUMP=${TRACEDUMP:-`dirname "$0"`/../tracedump}
 $TRACEDUMP
 
 stripdump () {
-    # http://www.theeggeadventure.com/wikimedia/index.php/Linux_Tips#Use_sed_to_remove_ANSI_colors
-    $TRACEDUMP "$1" \
+    $TRACEDUMP --no-color "$1" \
     | sed \
-        -e 's/\x1b\[[0-9]\{1,2\}\(;[0-9]\{1,2\}\)\{0,2\}m//g' \
         -e 's/\r$//g' \
         -e 's/^[0-9]\+ //' \
         -e 's/hdc = \w\+/hdc/g' \
@@ -52,6 +50,10 @@ mkfifo "$FIFO2"
 stripdump "$1" "$FIFO1" &
 stripdump "$2" "$FIFO2" &
 
-sdiff --width=`tput cols` --speed-large-files "$FIFO1" "$FIFO2" | less -R
+sdiff \
+    --width=`tput cols` \
+    --speed-large-files \
+    "$FIFO1" "$FIFO2" \
+| less -R
 
 rm -rf "$FIFODIR"
index d9d50acfcf096034443502f2c24740366b2c5f2e..90cc426cd7688d8a7014c3ca5e74b911734f5418 100644 (file)
--- a/trace.py
+++ b/trace.py
@@ -309,7 +309,7 @@ class Tracer:
         self.footer(api)
 
     def header(self, api):
-        print 'Trace::Writer __writer;'
+        print 'Trace::LocalWriter __writer;'
         print
 
     def footer(self, api):
index 5651f64b506b842bf0033aa6a454f8cae2971fb5..79bb7575801b4842c2bb23be04deacc9986a5c9d 100644 (file)
@@ -177,8 +177,8 @@ protected:
     Formatter::Attribute *literal;
 
 public:
-    Dumper(std::ostream &_os) : os(_os) {
-        formatter = Formatter::defaultFormatter();
+    Dumper(std::ostream &_os, bool color) : os(_os) {
+        formatter = Formatter::defaultFormatter(color);
         normal = formatter->normal();
         bold = formatter->bold();
         italic = formatter->italic();
@@ -334,12 +334,9 @@ public:
 };
 
 
-std::ostream & operator <<(std::ostream &os, Value *value) {
-    Dumper d(os);
-    if (value) {
-        value->visit(d);
-    }
-    return os;
+void Value::dump(std::ostream &os, bool color) {
+    Dumper d(os, color);
+    visit(d);
 }
 
 
@@ -355,11 +352,10 @@ const Value & Value::operator[](size_t index) const {
     return null;
 }
 
-std::ostream & operator <<(std::ostream &os, Call &call) {
-    Dumper d(os);
-    os << call.no << " ";
-    d.visit(&call);
-    return os;
+void Call::dump(std::ostream &os, bool color) {
+    Dumper d(os, color);
+    os << no << " ";
+    d.visit(this);
 }
 
 
index ddbcabd2993e357687588f7d3c0c549b609e715a..5c51bba7d06c345a541b8dca59cebe1291d546f6 100644 (file)
@@ -100,6 +100,8 @@ public:
     virtual const char *toString(void) const;
 
     const Value & operator[](size_t index) const;
+
+    void dump(std::ostream &os, bool color=true);
 };
 
 
@@ -305,7 +307,12 @@ protected:
 };
 
 
-std::ostream & operator <<(std::ostream &os, Value *value);
+inline std::ostream & operator <<(std::ostream &os, Value *value) {
+    if (value) {
+        value->dump(os);
+    }
+    return os;
+}
 
 
 class Call
@@ -327,10 +334,15 @@ public:
         assert(index < args.size());
         return *(args[index]);
     }
+
+    void dump(std::ostream &os, bool color=true);
 };
 
 
-std::ostream & operator <<(std::ostream &os, Call &call);
+inline std::ostream & operator <<(std::ostream &os, Call &call) {
+    call.dump(os);
+    return os;
+}
 
 
 } /* namespace Trace */
index 7511d3192420db31f65ee2e74dd5203db3ec201a..057e3957be289a63b9598c3c4344ae75171cb71e 100644 (file)
@@ -77,48 +77,6 @@ Writer::open(const char *filename) {
     return true;
 }
 
-void
-Writer::open(void) {
-
-    static unsigned dwCounter = 0;
-
-    const char *szExtension = "trace";
-    char szFileName[PATH_MAX];
-    const char *lpFileName;
-
-    lpFileName = getenv("TRACE_FILE");
-    if (lpFileName) {
-        strncpy(szFileName, lpFileName, PATH_MAX);
-    }
-    else {
-        char szProcessName[PATH_MAX];
-        char szCurrentDir[PATH_MAX];
-        OS::GetProcessName(szProcessName, PATH_MAX);
-        OS::GetCurrentDir(szCurrentDir, PATH_MAX);
-
-        for (;;) {
-            FILE *file;
-
-            if (dwCounter)
-                snprintf(szFileName, PATH_MAX, "%s%c%s.%u.%s", szCurrentDir, PATH_SEP, szProcessName, dwCounter, szExtension);
-            else
-                snprintf(szFileName, PATH_MAX, "%s%c%s.%s", szCurrentDir, PATH_SEP, szProcessName, szExtension);
-
-            file = fopen(szFileName, "rb");
-            if (file == NULL)
-                break;
-
-            fclose(file);
-
-            ++dwCounter;
-        }
-    }
-
-    OS::DebugMessage("apitrace: tracing to %s\n", szFileName);
-
-    open(szFileName);
-}
-
 void inline
 Writer::_write(const void *sBuffer, size_t dwBytesToWrite) {
     m_file->write(sBuffer, dwBytesToWrite);
@@ -177,12 +135,6 @@ inline bool lookup(std::vector<bool> &map, size_t index) {
 }
 
 unsigned Writer::beginEnter(const FunctionSig *sig) {
-    OS::AcquireMutex();
-
-    if (!m_file->isOpened()) {
-        open();
-    }
-
     _writeByte(Trace::EVENT_ENTER);
     _writeUInt(sig->id);
     if (!lookup(functions, sig->id)) {
@@ -199,19 +151,15 @@ unsigned Writer::beginEnter(const FunctionSig *sig) {
 
 void Writer::endEnter(void) {
     _writeByte(Trace::CALL_END);
-    OS::ReleaseMutex();
 }
 
 void Writer::beginLeave(unsigned call) {
-    OS::AcquireMutex();
     _writeByte(Trace::EVENT_LEAVE);
     _writeUInt(call);
 }
 
 void Writer::endLeave(void) {
     _writeByte(Trace::CALL_END);
-    m_file->flush();
-    OS::ReleaseMutex();
 }
 
 void Writer::beginArg(unsigned index) {
@@ -350,5 +298,75 @@ void Writer::writeOpaque(const void *addr) {
     _writeUInt((size_t)addr);
 }
 
+
+void
+LocalWriter::open(void) {
+
+    static unsigned dwCounter = 0;
+
+    const char *szExtension = "trace";
+    char szFileName[PATH_MAX];
+    const char *lpFileName;
+
+    lpFileName = getenv("TRACE_FILE");
+    if (lpFileName) {
+        strncpy(szFileName, lpFileName, PATH_MAX);
+    }
+    else {
+        char szProcessName[PATH_MAX];
+        char szCurrentDir[PATH_MAX];
+        OS::GetProcessName(szProcessName, PATH_MAX);
+        OS::GetCurrentDir(szCurrentDir, PATH_MAX);
+
+        for (;;) {
+            FILE *file;
+
+            if (dwCounter)
+                snprintf(szFileName, PATH_MAX, "%s%c%s.%u.%s", szCurrentDir, PATH_SEP, szProcessName, dwCounter, szExtension);
+            else
+                snprintf(szFileName, PATH_MAX, "%s%c%s.%s", szCurrentDir, PATH_SEP, szProcessName, szExtension);
+
+            file = fopen(szFileName, "rb");
+            if (file == NULL)
+                break;
+
+            fclose(file);
+
+            ++dwCounter;
+        }
+    }
+
+    OS::DebugMessage("apitrace: tracing to %s\n", szFileName);
+
+    Writer::open(szFileName);
+}
+
+unsigned LocalWriter::beginEnter(const FunctionSig *sig) {
+    OS::AcquireMutex();
+
+    if (!m_file->isOpened()) {
+        open();
+    }
+
+    return Writer::beginEnter(sig);
+}
+
+void LocalWriter::endEnter(void) {
+    Writer::endEnter();
+    OS::ReleaseMutex();
+}
+
+void LocalWriter::beginLeave(unsigned call) {
+    OS::AcquireMutex();
+    Writer::beginLeave(call);
+}
+
+void LocalWriter::endLeave(void) {
+    Writer::endLeave();
+    m_file->flush();
+    OS::ReleaseMutex();
+}
+
+
 } /* namespace Trace */
 
index eb81f233f604bef706d1149d867d13ef1748e2fc..4d46f739f8f231fcdee4e39de053b21949193448 100644 (file)
@@ -55,7 +55,6 @@ namespace Trace {
         Writer();
         ~Writer();
 
-        void open(void);
         bool open(const char *filename);
         void close(void);
 
@@ -105,6 +104,27 @@ namespace Trace {
         void inline _writeString(const char *str);
 
     };
+
+    /**
+     * A specialized Writer class, mean to trace the current process.
+     *
+     * In particular:
+     * - it creates a trace file based on the current process name
+     * - uses mutexes to allow tracing from multiple threades
+     * - flushes the output to ensure the last call is traced in event of
+     *   abnormal termination
+     */
+    class LocalWriter : public Writer {
+    protected:
+    public:
+        void open(void);
+
+        unsigned beginEnter(const FunctionSig *sig);
+        void endEnter(void);
+
+        void beginLeave(unsigned call);
+        void endLeave(void);
+    };
 }
 
 #endif /* _TRACE_WRITER_HPP_ */
index 1548880fd916be9d076f98818b5e19b085cefa0f..c210a0c9dd097119076f38642398c2673087283b 100644 (file)
  */
 
 
+#include <string.h>
+
 #include "trace_parser.hpp"
 
 
+static bool color = true;
+
+
+static void usage(void) {
+    std::cout <<
+        "Usage: tracedump [OPTION] [TRACE...]\n"
+        "Dump TRACE to standard output.\n"
+        "\n"
+        "  --no-color   no colored syntax highlightint\n"
+        "  --no-colour  alias for --no-color\n"
+    ;
+}
+
+
 int main(int argc, char **argv)
 {
-    for (int i = 1; i < argc; ++i) {
+    int i;
+
+    for (i = 1; i < argc; ++i) {
+        const char *arg = argv[i];
+
+        if (arg[0] != '-') {
+            break;
+        }
+
+        if (!strcmp(arg, "--")) {
+            break;
+        } else if (!strcmp(arg, "--no-color") ||
+                   !strcmp(arg, "--no-colour")) {
+            color = false;
+        } else {
+            std::cerr << "error: unknown option " << arg << "\n";
+            usage();
+            return 1;
+        }
+    }
+
+    for (; i < argc; ++i) {
         Trace::Parser p;
 
         if (!p.open(argv[i])) {
@@ -44,9 +81,10 @@ int main(int argc, char **argv)
 
         Trace::Call *call;
         while ((call = p.parse_call())) {
-            std::cout << *call;
+            call->dump(std::cout, color);
             delete call;
         }
     }
+
     return 0;
 }