Blame src/gallium/tools/trace/parse.py

Packit Service 5cb53b
#! /usr/libexec/platform-python
Packit 8f2243
##########################################################################
Packit 8f2243
# 
Packit 8f2243
# Copyright 2008 VMware, Inc.
Packit 8f2243
# All Rights Reserved.
Packit 8f2243
# 
Packit 8f2243
# Permission is hereby granted, free of charge, to any person obtaining a
Packit 8f2243
# copy of this software and associated documentation files (the
Packit 8f2243
# "Software"), to deal in the Software without restriction, including
Packit 8f2243
# without limitation the rights to use, copy, modify, merge, publish,
Packit 8f2243
# distribute, sub license, and/or sell copies of the Software, and to
Packit 8f2243
# permit persons to whom the Software is furnished to do so, subject to
Packit 8f2243
# the following conditions:
Packit 8f2243
# 
Packit 8f2243
# The above copyright notice and this permission notice (including the
Packit 8f2243
# next paragraph) shall be included in all copies or substantial portions
Packit 8f2243
# of the Software.
Packit 8f2243
# 
Packit 8f2243
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
Packit 8f2243
# OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
Packit 8f2243
# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.
Packit 8f2243
# IN NO EVENT SHALL VMWARE AND/OR ITS SUPPLIERS BE LIABLE FOR
Packit 8f2243
# ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
Packit 8f2243
# TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
Packit 8f2243
# SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
Packit 8f2243
# 
Packit 8f2243
##########################################################################
Packit 8f2243
Packit 8f2243
Packit 8f2243
import sys
Packit 8f2243
import xml.parsers.expat
Packit 8f2243
import optparse
Packit 8f2243
Packit 8f2243
from model import *
Packit 8f2243
Packit 8f2243
Packit 8f2243
ELEMENT_START, ELEMENT_END, CHARACTER_DATA, EOF = range(4)
Packit 8f2243
Packit 8f2243
Packit 8f2243
class XmlToken:
Packit 8f2243
Packit 8f2243
    def __init__(self, type, name_or_data, attrs = None, line = None, column = None):
Packit 8f2243
        assert type in (ELEMENT_START, ELEMENT_END, CHARACTER_DATA, EOF)
Packit 8f2243
        self.type = type
Packit 8f2243
        self.name_or_data = name_or_data
Packit 8f2243
        self.attrs = attrs
Packit 8f2243
        self.line = line
Packit 8f2243
        self.column = column
Packit 8f2243
Packit 8f2243
    def __str__(self):
Packit 8f2243
        if self.type == ELEMENT_START:
Packit 8f2243
            return '<' + self.name_or_data + ' ...>'
Packit 8f2243
        if self.type == ELEMENT_END:
Packit 8f2243
            return '</' + self.name_or_data + '>'
Packit 8f2243
        if self.type == CHARACTER_DATA:
Packit 8f2243
            return self.name_or_data
Packit 8f2243
        if self.type == EOF:
Packit 8f2243
            return 'end of file'
Packit 8f2243
        assert 0
Packit 8f2243
Packit 8f2243
Packit 8f2243
class XmlTokenizer:
Packit 8f2243
    """Expat based XML tokenizer."""
Packit 8f2243
Packit 8f2243
    def __init__(self, fp, skip_ws = True):
Packit 8f2243
        self.fp = fp
Packit 8f2243
        self.tokens = []
Packit 8f2243
        self.index = 0
Packit 8f2243
        self.final = False
Packit 8f2243
        self.skip_ws = skip_ws
Packit 8f2243
        
Packit 8f2243
        self.character_pos = 0, 0
Packit 8f2243
        self.character_data = ''
Packit 8f2243
        
Packit 8f2243
        self.parser = xml.parsers.expat.ParserCreate()
Packit 8f2243
        self.parser.StartElementHandler  = self.handle_element_start
Packit 8f2243
        self.parser.EndElementHandler    = self.handle_element_end
Packit 8f2243
        self.parser.CharacterDataHandler = self.handle_character_data
Packit 8f2243
    
Packit 8f2243
    def handle_element_start(self, name, attributes):
Packit 8f2243
        self.finish_character_data()
Packit 8f2243
        line, column = self.pos()
Packit 8f2243
        token = XmlToken(ELEMENT_START, name, attributes, line, column)
Packit 8f2243
        self.tokens.append(token)
Packit 8f2243
    
Packit 8f2243
    def handle_element_end(self, name):
Packit 8f2243
        self.finish_character_data()
Packit 8f2243
        line, column = self.pos()
Packit 8f2243
        token = XmlToken(ELEMENT_END, name, None, line, column)
Packit 8f2243
        self.tokens.append(token)
Packit 8f2243
Packit 8f2243
    def handle_character_data(self, data):
Packit 8f2243
        if not self.character_data:
Packit 8f2243
            self.character_pos = self.pos()
Packit 8f2243
        self.character_data += data
Packit 8f2243
    
Packit 8f2243
    def finish_character_data(self):
Packit 8f2243
        if self.character_data:
Packit 8f2243
            if not self.skip_ws or not self.character_data.isspace(): 
Packit 8f2243
                line, column = self.character_pos
Packit 8f2243
                token = XmlToken(CHARACTER_DATA, self.character_data, None, line, column)
Packit 8f2243
                self.tokens.append(token)
Packit 8f2243
            self.character_data = ''
Packit 8f2243
    
Packit 8f2243
    def next(self):
Packit 8f2243
        size = 16*1024
Packit 8f2243
        while self.index >= len(self.tokens) and not self.final:
Packit 8f2243
            self.tokens = []
Packit 8f2243
            self.index = 0
Packit 8f2243
            data = self.fp.read(size)
Packit 8f2243
            self.final = len(data) < size
Packit 8f2243
            data = data.rstrip('\0')
Packit 8f2243
            try:
Packit 8f2243
                self.parser.Parse(data, self.final)
Packit 8f2243
            except xml.parsers.expat.ExpatError, e:
Packit 8f2243
                #if e.code == xml.parsers.expat.errors.XML_ERROR_NO_ELEMENTS:
Packit 8f2243
                if e.code == 3:
Packit 8f2243
                    pass
Packit 8f2243
                else:
Packit 8f2243
                    raise e
Packit 8f2243
        if self.index >= len(self.tokens):
Packit 8f2243
            line, column = self.pos()
Packit 8f2243
            token = XmlToken(EOF, None, None, line, column)
Packit 8f2243
        else:
Packit 8f2243
            token = self.tokens[self.index]
Packit 8f2243
            self.index += 1
Packit 8f2243
        return token
Packit 8f2243
Packit 8f2243
    def pos(self):
Packit 8f2243
        return self.parser.CurrentLineNumber, self.parser.CurrentColumnNumber
Packit 8f2243
Packit 8f2243
Packit 8f2243
class TokenMismatch(Exception):
Packit 8f2243
Packit 8f2243
    def __init__(self, expected, found):
Packit 8f2243
        self.expected = expected
Packit 8f2243
        self.found = found
Packit 8f2243
Packit 8f2243
    def __str__(self):
Packit 8f2243
        return '%u:%u: %s expected, %s found' % (self.found.line, self.found.column, str(self.expected), str(self.found))
Packit 8f2243
Packit 8f2243
Packit 8f2243
Packit 8f2243
class XmlParser:
Packit 8f2243
    """Base XML document parser."""
Packit 8f2243
Packit 8f2243
    def __init__(self, fp):
Packit 8f2243
        self.tokenizer = XmlTokenizer(fp)
Packit 8f2243
        self.consume()
Packit 8f2243
    
Packit 8f2243
    def consume(self):
Packit 8f2243
        self.token = self.tokenizer.next()
Packit 8f2243
Packit 8f2243
    def match_element_start(self, name):
Packit 8f2243
        return self.token.type == ELEMENT_START and self.token.name_or_data == name
Packit 8f2243
    
Packit 8f2243
    def match_element_end(self, name):
Packit 8f2243
        return self.token.type == ELEMENT_END and self.token.name_or_data == name
Packit 8f2243
Packit 8f2243
    def element_start(self, name):
Packit 8f2243
        while self.token.type == CHARACTER_DATA:
Packit 8f2243
            self.consume()
Packit 8f2243
        if self.token.type != ELEMENT_START:
Packit 8f2243
            raise TokenMismatch(XmlToken(ELEMENT_START, name), self.token)
Packit 8f2243
        if self.token.name_or_data != name:
Packit 8f2243
            raise TokenMismatch(XmlToken(ELEMENT_START, name), self.token)
Packit 8f2243
        attrs = self.token.attrs
Packit 8f2243
        self.consume()
Packit 8f2243
        return attrs
Packit 8f2243
    
Packit 8f2243
    def element_end(self, name):
Packit 8f2243
        while self.token.type == CHARACTER_DATA:
Packit 8f2243
            self.consume()
Packit 8f2243
        if self.token.type != ELEMENT_END:
Packit 8f2243
            raise TokenMismatch(XmlToken(ELEMENT_END, name), self.token)
Packit 8f2243
        if self.token.name_or_data != name:
Packit 8f2243
            raise TokenMismatch(XmlToken(ELEMENT_END, name), self.token)
Packit 8f2243
        self.consume()
Packit 8f2243
Packit 8f2243
    def character_data(self, strip = True):
Packit 8f2243
        data = ''
Packit 8f2243
        while self.token.type == CHARACTER_DATA:
Packit 8f2243
            data += self.token.name_or_data
Packit 8f2243
            self.consume()
Packit 8f2243
        if strip:
Packit 8f2243
            data = data.strip()
Packit 8f2243
        return data
Packit 8f2243
Packit 8f2243
Packit 8f2243
class TraceParser(XmlParser):
Packit 8f2243
Packit 8f2243
    def __init__(self, fp):
Packit 8f2243
        XmlParser.__init__(self, fp)
Packit 8f2243
        self.last_call_no = 0
Packit 8f2243
    
Packit 8f2243
    def parse(self):
Packit 8f2243
        self.element_start('trace')
Packit 8f2243
        while self.token.type not in (ELEMENT_END, EOF):
Packit 8f2243
            call = self.parse_call()
Packit 8f2243
            self.handle_call(call)
Packit 8f2243
        if self.token.type != EOF:
Packit 8f2243
            self.element_end('trace')
Packit 8f2243
Packit 8f2243
    def parse_call(self):
Packit 8f2243
        attrs = self.element_start('call')
Packit 8f2243
        try:
Packit 8f2243
            no = int(attrs['no'])
Packit 8f2243
        except KeyError:
Packit 8f2243
            self.last_call_no += 1
Packit 8f2243
            no = self.last_call_no
Packit 8f2243
        else:
Packit 8f2243
            self.last_call_no = no
Packit 8f2243
        klass = attrs['class']
Packit 8f2243
        method = attrs['method']
Packit 8f2243
        args = []
Packit 8f2243
        ret = None
Packit 8f2243
        time = None
Packit 8f2243
        while self.token.type == ELEMENT_START:
Packit 8f2243
            if self.token.name_or_data == 'arg':
Packit 8f2243
                arg = self.parse_arg()
Packit 8f2243
                args.append(arg)
Packit 8f2243
            elif self.token.name_or_data == 'ret':
Packit 8f2243
                ret = self.parse_ret()
Packit 8f2243
            elif self.token.name_or_data == 'call':
Packit 8f2243
                # ignore nested function calls
Packit 8f2243
                self.parse_call()
Packit 8f2243
            elif self.token.name_or_data == 'time':
Packit 8f2243
                time = self.parse_time()
Packit 8f2243
            else:
Packit 8f2243
                raise TokenMismatch("<arg ...> or <ret ...>", self.token)
Packit 8f2243
        self.element_end('call')
Packit 8f2243
        
Packit 8f2243
        return Call(no, klass, method, args, ret, time)
Packit 8f2243
Packit 8f2243
    def parse_arg(self):
Packit 8f2243
        attrs = self.element_start('arg')
Packit 8f2243
        name = attrs['name']
Packit 8f2243
        value = self.parse_value()
Packit 8f2243
        self.element_end('arg')
Packit 8f2243
Packit 8f2243
        return name, value
Packit 8f2243
Packit 8f2243
    def parse_ret(self):
Packit 8f2243
        attrs = self.element_start('ret')
Packit 8f2243
        value = self.parse_value()
Packit 8f2243
        self.element_end('ret')
Packit 8f2243
Packit 8f2243
        return value
Packit 8f2243
Packit 8f2243
    def parse_time(self):
Packit 8f2243
        attrs = self.element_start('time')
Packit 8f2243
        time = self.parse_value();
Packit 8f2243
        self.element_end('time')
Packit 8f2243
        return time
Packit 8f2243
Packit 8f2243
    def parse_value(self):
Packit 8f2243
        expected_tokens = ('null', 'bool', 'int', 'uint', 'float', 'string', 'enum', 'array', 'struct', 'ptr', 'bytes')
Packit 8f2243
        if self.token.type == ELEMENT_START:
Packit 8f2243
            if self.token.name_or_data in expected_tokens:
Packit 8f2243
                method = getattr(self, 'parse_' +  self.token.name_or_data)
Packit 8f2243
                return method()
Packit 8f2243
        raise TokenMismatch(" or " .join(expected_tokens), self.token)
Packit 8f2243
Packit 8f2243
    def parse_null(self):
Packit 8f2243
        self.element_start('null')
Packit 8f2243
        self.element_end('null')
Packit 8f2243
        return Literal(None)
Packit 8f2243
        
Packit 8f2243
    def parse_bool(self):
Packit 8f2243
        self.element_start('bool')
Packit 8f2243
        value = int(self.character_data())
Packit 8f2243
        self.element_end('bool')
Packit 8f2243
        return Literal(value)
Packit 8f2243
        
Packit 8f2243
    def parse_int(self):
Packit 8f2243
        self.element_start('int')
Packit 8f2243
        value = int(self.character_data())
Packit 8f2243
        self.element_end('int')
Packit 8f2243
        return Literal(value)
Packit 8f2243
        
Packit 8f2243
    def parse_uint(self):
Packit 8f2243
        self.element_start('uint')
Packit 8f2243
        value = int(self.character_data())
Packit 8f2243
        self.element_end('uint')
Packit 8f2243
        return Literal(value)
Packit 8f2243
        
Packit 8f2243
    def parse_float(self):
Packit 8f2243
        self.element_start('float')
Packit 8f2243
        value = float(self.character_data())
Packit 8f2243
        self.element_end('float')
Packit 8f2243
        return Literal(value)
Packit 8f2243
        
Packit 8f2243
    def parse_enum(self):
Packit 8f2243
        self.element_start('enum')
Packit 8f2243
        name = self.character_data()
Packit 8f2243
        self.element_end('enum')
Packit 8f2243
        return NamedConstant(name)
Packit 8f2243
        
Packit 8f2243
    def parse_string(self):
Packit 8f2243
        self.element_start('string')
Packit 8f2243
        value = self.character_data()
Packit 8f2243
        self.element_end('string')
Packit 8f2243
        return Literal(value)
Packit 8f2243
        
Packit 8f2243
    def parse_bytes(self):
Packit 8f2243
        self.element_start('bytes')
Packit 8f2243
        value = self.character_data()
Packit 8f2243
        self.element_end('bytes')
Packit 8f2243
        return Blob(value)
Packit 8f2243
        
Packit 8f2243
    def parse_array(self):
Packit 8f2243
        self.element_start('array')
Packit 8f2243
        elems = []
Packit 8f2243
        while self.token.type != ELEMENT_END:
Packit 8f2243
            elems.append(self.parse_elem())
Packit 8f2243
        self.element_end('array')
Packit 8f2243
        return Array(elems)
Packit 8f2243
Packit 8f2243
    def parse_elem(self):
Packit 8f2243
        self.element_start('elem')
Packit 8f2243
        value = self.parse_value()
Packit 8f2243
        self.element_end('elem')
Packit 8f2243
        return value
Packit 8f2243
Packit 8f2243
    def parse_struct(self):
Packit 8f2243
        attrs = self.element_start('struct')
Packit 8f2243
        name = attrs['name']
Packit 8f2243
        members = []
Packit 8f2243
        while self.token.type != ELEMENT_END:
Packit 8f2243
            members.append(self.parse_member())
Packit 8f2243
        self.element_end('struct')
Packit 8f2243
        return Struct(name, members)
Packit 8f2243
Packit 8f2243
    def parse_member(self):
Packit 8f2243
        attrs = self.element_start('member')
Packit 8f2243
        name = attrs['name']
Packit 8f2243
        value = self.parse_value()
Packit 8f2243
        self.element_end('member')
Packit 8f2243
Packit 8f2243
        return name, value
Packit 8f2243
Packit 8f2243
    def parse_ptr(self):
Packit 8f2243
        self.element_start('ptr')
Packit 8f2243
        address = self.character_data()
Packit 8f2243
        self.element_end('ptr')
Packit 8f2243
Packit 8f2243
        return Pointer(address)
Packit 8f2243
Packit 8f2243
    def handle_call(self, call):
Packit 8f2243
        pass
Packit 8f2243
    
Packit 8f2243
    
Packit 8f2243
class TraceDumper(TraceParser):
Packit 8f2243
    
Packit 8f2243
    def __init__(self, fp, outStream = sys.stdout):
Packit 8f2243
        TraceParser.__init__(self, fp)
Packit 8f2243
        self.formatter = format.DefaultFormatter(outStream)
Packit 8f2243
        self.pretty_printer = PrettyPrinter(self.formatter)
Packit 8f2243
Packit 8f2243
    def handle_call(self, call):
Packit 8f2243
        call.visit(self.pretty_printer)
Packit 8f2243
        self.formatter.newline()
Packit 8f2243
        
Packit 8f2243
Packit 8f2243
class Main:
Packit 8f2243
    '''Common main class for all retrace command line utilities.''' 
Packit 8f2243
Packit 8f2243
    def __init__(self):
Packit 8f2243
        pass
Packit 8f2243
Packit 8f2243
    def main(self):
Packit 8f2243
        optparser = self.get_optparser()
Packit 8f2243
        (options, args) = optparser.parse_args(sys.argv[1:])
Packit 8f2243
    
Packit 8f2243
        if not args:
Packit 8f2243
            optparser.error('insufficient number of arguments')
Packit 8f2243
Packit 8f2243
        for arg in args:
Packit 8f2243
            if arg.endswith('.gz'):
Packit 8f2243
                from gzip import GzipFile
Packit 8f2243
                stream = GzipFile(arg, 'rt')
Packit 8f2243
            elif arg.endswith('.bz2'):
Packit 8f2243
                from bz2 import BZ2File
Packit 8f2243
                stream = BZ2File(arg, 'rU')
Packit 8f2243
            else:
Packit 8f2243
                stream = open(arg, 'rt')
Packit 8f2243
            self.process_arg(stream, options)
Packit 8f2243
Packit 8f2243
    def get_optparser(self):
Packit 8f2243
        optparser = optparse.OptionParser(
Packit 8f2243
            usage="\n\t%prog [options] TRACE  [...]")
Packit 8f2243
        return optparser
Packit 8f2243
Packit 8f2243
    def process_arg(self, stream, options):
Packit 8f2243
        parser = TraceDumper(stream)
Packit 8f2243
        parser.parse()
Packit 8f2243
Packit 8f2243
Packit 8f2243
if __name__ == '__main__':
Packit 8f2243
    Main().main()