python/retrace: Highlight the trace dump to help to visualize.
authorJosé Fonseca <jrfonseca@tungstengraphics.com>
Wed, 19 Nov 2008 08:17:06 +0000 (17:17 +0900)
committerJosé Fonseca <jrfonseca@tungstengraphics.com>
Wed, 19 Nov 2008 08:17:06 +0000 (17:17 +0900)
src/gallium/state_trackers/python/retrace/format.py [new file with mode: 0755]
src/gallium/state_trackers/python/retrace/interpreter.py
src/gallium/state_trackers/python/retrace/model.py
src/gallium/state_trackers/python/retrace/parser.py

diff --git a/src/gallium/state_trackers/python/retrace/format.py b/src/gallium/state_trackers/python/retrace/format.py
new file mode 100755 (executable)
index 0000000..0bf6baf
--- /dev/null
@@ -0,0 +1,100 @@
+#!/usr/bin/env python
+##########################################################################
+#
+# Copyright 2008 Tungsten Graphics, Inc., Cedar Park, Texas.
+# 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, sub license, 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 (including the
+# next paragraph) 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 NON-INFRINGEMENT.
+# IN NO EVENT SHALL TUNGSTEN GRAPHICS AND/OR ITS SUPPLIERS 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.
+#
+##########################################################################
+
+
+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)
+
+
+
+def DefaultFormatter(stream):
+    if stream.isatty():
+        return AnsiFormatter(stream)
+    else:
+        return Formatter(stream)
+
index a23f153d2fe57b048aaa3242e3488131ab08d825..61b3ef2abc2666592d58d79bc6df6efb2246abde 100755 (executable)
@@ -440,10 +440,10 @@ class Context(Object):
             show_image(self.cbufs[0])
     
 
-class Interpreter(parser.TraceParser):
+class Interpreter(parser.TraceDumper):
     
     def __init__(self, stream):
-        parser.TraceParser.__init__(self, stream)
+        parser.TraceDumper.__init__(self, stream)
         self.objects = {}
         self.result = None
         self.globl = Global(self, None)
@@ -463,7 +463,7 @@ class Interpreter(parser.TraceParser):
             self.interpret_call(call)
 
     def handle_call(self, call):
-        sys.stderr.write("%s\n" % call)
+        parser.TraceDumper.handle_call(self, call)
         
         args = [self.interpret_arg(arg) for name, arg in call.args] 
         
index 9dd928c7e2fb3385ab67afd38b2bf0087f30b99b..3889db4e72b71bf9636726f18c85ea070040077c 100755 (executable)
 '''Trace data model.'''
 
 
+import sys
+import format
+
+try:
+    from cStringIO import StringIO
+except ImportError:
+    from StringIO import StringIO
+
+
 class Node:
     
     def visit(self, visitor):
         raise NotImplementedError
 
+    def __str__(self):
+        stream = StringIO()
+        formatter = format.DefaultFormatter(stream)
+        pretty_printer = PrettyPrinter(formatter)
+        self.visit(pretty_printer)
+        return stream.getvalue()
+
 
 class Literal(Node):
     
@@ -43,12 +59,6 @@ class Literal(Node):
 
     def visit(self, visitor):
         visitor.visit_literal(self)
-        
-    def __str__(self):
-        if isinstance(self.value, str) and len(self.value) > 32:
-            return '...'
-        else: 
-            return repr(self.value)
 
 
 class NamedConstant(Node):
@@ -58,9 +68,6 @@ class NamedConstant(Node):
 
     def visit(self, visitor):
         visitor.visit_named_constant(self)
-        
-    def __str__(self):
-        return self.name
     
 
 class Array(Node):
@@ -70,9 +77,6 @@ class Array(Node):
 
     def visit(self, visitor):
         visitor.visit_array(self)
-        
-    def __str__(self):
-        return '{' + ', '.join([str(value) for value in self.elements]) + '}'
 
 
 class Struct(Node):
@@ -83,9 +87,6 @@ class Struct(Node):
 
     def visit(self, visitor):
         visitor.visit_struct(self)
-        
-    def __str__(self):
-        return '{' + ', '.join([name + ' = ' + str(value) for name, value in self.members]) + '}'
 
         
 class Pointer(Node):
@@ -95,9 +96,6 @@ class Pointer(Node):
 
     def visit(self, visitor):
         visitor.visit_pointer(self)
-        
-    def __str__(self):
-        return self.address
 
 
 class Call:
@@ -110,15 +108,6 @@ class Call:
         
     def visit(self, visitor):
         visitor.visit_call(self)
-        
-    def __str__(self):
-        s = self.method
-        if self.klass:
-            s = self.klass + '::' + s
-        s += '(' + ', '.join([name + ' = ' + str(value) for name, value in self.args]) + ')'
-        if self.ret is not None:
-            s += ' = ' + str(self.ret)
-        return s
 
 
 class Trace:
@@ -128,9 +117,6 @@ class Trace:
         
     def visit(self, visitor):
         visitor.visit_trace(self)
-        
-    def __str__(self):
-        return '\n'.join([str(call) for call in self.calls])
     
     
 class Visitor:
@@ -155,5 +141,65 @@ class Visitor:
     
     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, str) and len(node.value) > 32:
+            self.formatter.text('...')
+        else: 
+            self.formatter.literal(repr(node.value))
+    
+    def visit_named_constant(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 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.address)
+    
+    def visit_call(self, node):
+        if node.klass is not None:
+            self.formatter.function(node.klass + '::' + node.method)
+        else:
+            self.formatter.function(node.method)
+        self.formatter.text('(')
+        sep = ''
+        for name, value in node.args:
+            self.formatter.text(sep)
+            self.formatter.variable(name)
+            self.formatter.text(' = ')
+            value.visit(self) 
+            sep = ', '
+        if node.ret is not None:
+            self.formatter.text(' = ')
+            node.ret.visit(self)
+        self.formatter.text(')')
+    
+    def visit_trace(self, node):
+        for call in node.calls:
+            call.visit(self)
+            self.formatter.newline()
 
index e5e8525dfc12a5a97579eac74dbebae8937f7732..5205f2d8dd588e82b964744a39e5f4fc7b6ae690 100755 (executable)
@@ -327,15 +327,19 @@ class TraceParser(XmlParser):
         return Pointer(address)
 
     def handle_call(self, call):
-        
         pass
     
     
 class TraceDumper(TraceParser):
     
+    def __init__(self, fp):
+        TraceParser.__init__(self, fp)
+        self.formatter = format.DefaultFormatter(sys.stdout)
+        self.pretty_printer = PrettyPrinter(self.formatter)
 
     def handle_call(self, call):
-        print call
+        call.visit(self.pretty_printer)
+        self.formatter.newline()
         
 
 def main(ParserFactory):