Statistics
| Branch: | Revision:

root / scripts / simpletrace.py @ 85938981

History | View | Annotate | Download (5.8 kB)

1 26f7227b Stefan Hajnoczi
#!/usr/bin/env python
2 26f7227b Stefan Hajnoczi
#
3 26f7227b Stefan Hajnoczi
# Pretty-printer for simple trace backend binary trace files
4 26f7227b Stefan Hajnoczi
#
5 26f7227b Stefan Hajnoczi
# Copyright IBM, Corp. 2010
6 26f7227b Stefan Hajnoczi
#
7 26f7227b Stefan Hajnoczi
# This work is licensed under the terms of the GNU GPL, version 2.  See
8 26f7227b Stefan Hajnoczi
# the COPYING file in the top-level directory.
9 26f7227b Stefan Hajnoczi
#
10 26f7227b Stefan Hajnoczi
# For help see docs/tracing.txt
11 26f7227b Stefan Hajnoczi
12 26f7227b Stefan Hajnoczi
import struct
13 26f7227b Stefan Hajnoczi
import re
14 59da6684 Stefan Hajnoczi
import inspect
15 90a147a2 Harsh Prateek Bora
from tracetool import _read_events, Event
16 90a147a2 Harsh Prateek Bora
from tracetool.backend.simple import is_string
17 26f7227b Stefan Hajnoczi
18 26f7227b Stefan Hajnoczi
header_event_id = 0xffffffffffffffff
19 26f7227b Stefan Hajnoczi
header_magic    = 0xf2b177cb0aa429b4
20 0b5538c3 Stefan Hajnoczi
dropped_event_id = 0xfffffffffffffffe
21 26f7227b Stefan Hajnoczi
22 90a147a2 Harsh Prateek Bora
log_header_fmt = '=QQQ'
23 90a147a2 Harsh Prateek Bora
rec_header_fmt = '=QQII'
24 26f7227b Stefan Hajnoczi
25 90a147a2 Harsh Prateek Bora
def read_header(fobj, hfmt):
26 90a147a2 Harsh Prateek Bora
    '''Read a trace record header'''
27 90a147a2 Harsh Prateek Bora
    hlen = struct.calcsize(hfmt)
28 90a147a2 Harsh Prateek Bora
    hdr = fobj.read(hlen)
29 90a147a2 Harsh Prateek Bora
    if len(hdr) != hlen:
30 90a147a2 Harsh Prateek Bora
        return None
31 90a147a2 Harsh Prateek Bora
    return struct.unpack(hfmt, hdr)
32 26f7227b Stefan Hajnoczi
33 90a147a2 Harsh Prateek Bora
def get_record(edict, rechdr, fobj):
34 59da6684 Stefan Hajnoczi
    """Deserialize a trace record from a file into a tuple (event_num, timestamp, arg1, ..., arg6)."""
35 90a147a2 Harsh Prateek Bora
    if rechdr is None:
36 26f7227b Stefan Hajnoczi
        return None
37 90a147a2 Harsh Prateek Bora
    rec = (rechdr[0], rechdr[1])
38 90a147a2 Harsh Prateek Bora
    if rechdr[0] != dropped_event_id:
39 90a147a2 Harsh Prateek Bora
        event_id = rechdr[0]
40 90a147a2 Harsh Prateek Bora
        event = edict[event_id]
41 90a147a2 Harsh Prateek Bora
        for type, name in event.args:
42 90a147a2 Harsh Prateek Bora
            if is_string(type):
43 90a147a2 Harsh Prateek Bora
                l = fobj.read(4)
44 90a147a2 Harsh Prateek Bora
                (len,) = struct.unpack('=L', l)
45 90a147a2 Harsh Prateek Bora
                s = fobj.read(len)
46 90a147a2 Harsh Prateek Bora
                rec = rec + (s,)
47 90a147a2 Harsh Prateek Bora
            else:
48 90a147a2 Harsh Prateek Bora
                (value,) = struct.unpack('=Q', fobj.read(8))
49 90a147a2 Harsh Prateek Bora
                rec = rec + (value,)
50 90a147a2 Harsh Prateek Bora
    else:
51 90a147a2 Harsh Prateek Bora
        (value,) = struct.unpack('=Q', fobj.read(8))
52 90a147a2 Harsh Prateek Bora
        rec = rec + (value,)
53 90a147a2 Harsh Prateek Bora
    return rec
54 90a147a2 Harsh Prateek Bora
55 90a147a2 Harsh Prateek Bora
56 90a147a2 Harsh Prateek Bora
def read_record(edict, fobj):
57 90a147a2 Harsh Prateek Bora
    """Deserialize a trace record from a file into a tuple (event_num, timestamp, arg1, ..., arg6)."""
58 90a147a2 Harsh Prateek Bora
    rechdr = read_header(fobj, rec_header_fmt)
59 90a147a2 Harsh Prateek Bora
    return get_record(edict, rechdr, fobj) # return tuple of record elements
60 26f7227b Stefan Hajnoczi
61 90a147a2 Harsh Prateek Bora
def read_trace_file(edict, fobj):
62 59da6684 Stefan Hajnoczi
    """Deserialize trace records from a file, yielding record tuples (event_num, timestamp, arg1, ..., arg6)."""
63 90a147a2 Harsh Prateek Bora
    header = read_header(fobj, log_header_fmt)
64 26f7227b Stefan Hajnoczi
    if header is None or \
65 26f7227b Stefan Hajnoczi
       header[0] != header_event_id or \
66 90a147a2 Harsh Prateek Bora
       header[1] != header_magic:
67 90a147a2 Harsh Prateek Bora
        raise ValueError('Not a valid trace file!')
68 90a147a2 Harsh Prateek Bora
    if header[2] != 0 and \
69 90a147a2 Harsh Prateek Bora
       header[2] != 2:
70 90a147a2 Harsh Prateek Bora
        raise ValueError('Unknown version of tracelog format!')
71 90a147a2 Harsh Prateek Bora
72 90a147a2 Harsh Prateek Bora
    log_version = header[2]
73 90a147a2 Harsh Prateek Bora
    if log_version == 0:
74 eda5edd1 Stefan Weil
        raise ValueError('Older log format, not supported with this QEMU release!')
75 26f7227b Stefan Hajnoczi
76 26f7227b Stefan Hajnoczi
    while True:
77 90a147a2 Harsh Prateek Bora
        rec = read_record(edict, fobj)
78 26f7227b Stefan Hajnoczi
        if rec is None:
79 26f7227b Stefan Hajnoczi
            break
80 26f7227b Stefan Hajnoczi
81 26f7227b Stefan Hajnoczi
        yield rec
82 26f7227b Stefan Hajnoczi
83 59da6684 Stefan Hajnoczi
class Analyzer(object):
84 59da6684 Stefan Hajnoczi
    """A trace file analyzer which processes trace records.
85 59da6684 Stefan Hajnoczi

86 59da6684 Stefan Hajnoczi
    An analyzer can be passed to run() or process().  The begin() method is
87 59da6684 Stefan Hajnoczi
    invoked, then each trace record is processed, and finally the end() method
88 59da6684 Stefan Hajnoczi
    is invoked.
89 59da6684 Stefan Hajnoczi

90 59da6684 Stefan Hajnoczi
    If a method matching a trace event name exists, it is invoked to process
91 59da6684 Stefan Hajnoczi
    that trace record.  Otherwise the catchall() method is invoked."""
92 59da6684 Stefan Hajnoczi
93 59da6684 Stefan Hajnoczi
    def begin(self):
94 59da6684 Stefan Hajnoczi
        """Called at the start of the trace."""
95 59da6684 Stefan Hajnoczi
        pass
96 59da6684 Stefan Hajnoczi
97 59da6684 Stefan Hajnoczi
    def catchall(self, event, rec):
98 59da6684 Stefan Hajnoczi
        """Called if no specific method for processing a trace event has been found."""
99 59da6684 Stefan Hajnoczi
        pass
100 59da6684 Stefan Hajnoczi
101 59da6684 Stefan Hajnoczi
    def end(self):
102 59da6684 Stefan Hajnoczi
        """Called at the end of the trace."""
103 59da6684 Stefan Hajnoczi
        pass
104 59da6684 Stefan Hajnoczi
105 59da6684 Stefan Hajnoczi
def process(events, log, analyzer):
106 59da6684 Stefan Hajnoczi
    """Invoke an analyzer on each event in a log."""
107 59da6684 Stefan Hajnoczi
    if isinstance(events, str):
108 90a147a2 Harsh Prateek Bora
        events = _read_events(open(events, 'r'))
109 59da6684 Stefan Hajnoczi
    if isinstance(log, str):
110 59da6684 Stefan Hajnoczi
        log = open(log, 'rb')
111 59da6684 Stefan Hajnoczi
112 90a147a2 Harsh Prateek Bora
    enabled_events = []
113 90a147a2 Harsh Prateek Bora
    dropped_event = Event.build("Dropped_Event(uint64_t num_events_dropped)")
114 90a147a2 Harsh Prateek Bora
    edict = {dropped_event_id: dropped_event}
115 90a147a2 Harsh Prateek Bora
116 90a147a2 Harsh Prateek Bora
    for e in events:
117 90a147a2 Harsh Prateek Bora
        if 'disable' not in e.properties:
118 90a147a2 Harsh Prateek Bora
            enabled_events.append(e)
119 90a147a2 Harsh Prateek Bora
    for num, event in enumerate(enabled_events):
120 90a147a2 Harsh Prateek Bora
        edict[num] = event
121 90a147a2 Harsh Prateek Bora
122 59da6684 Stefan Hajnoczi
    def build_fn(analyzer, event):
123 90a147a2 Harsh Prateek Bora
        if isinstance(event, str):
124 90a147a2 Harsh Prateek Bora
            return analyzer.catchall
125 90a147a2 Harsh Prateek Bora
126 90a147a2 Harsh Prateek Bora
        fn = getattr(analyzer, event.name, None)
127 59da6684 Stefan Hajnoczi
        if fn is None:
128 59da6684 Stefan Hajnoczi
            return analyzer.catchall
129 59da6684 Stefan Hajnoczi
130 90a147a2 Harsh Prateek Bora
        event_argcount = len(event.args)
131 59da6684 Stefan Hajnoczi
        fn_argcount = len(inspect.getargspec(fn)[0]) - 1
132 59da6684 Stefan Hajnoczi
        if fn_argcount == event_argcount + 1:
133 59da6684 Stefan Hajnoczi
            # Include timestamp as first argument
134 d8e8ef4e Stefan Hajnoczi
            return lambda _, rec: fn(*rec[1:2 + event_argcount])
135 59da6684 Stefan Hajnoczi
        else:
136 59da6684 Stefan Hajnoczi
            # Just arguments, no timestamp
137 d8e8ef4e Stefan Hajnoczi
            return lambda _, rec: fn(*rec[2:2 + event_argcount])
138 59da6684 Stefan Hajnoczi
139 59da6684 Stefan Hajnoczi
    analyzer.begin()
140 59da6684 Stefan Hajnoczi
    fn_cache = {}
141 90a147a2 Harsh Prateek Bora
    for rec in read_trace_file(edict, log):
142 59da6684 Stefan Hajnoczi
        event_num = rec[0]
143 90a147a2 Harsh Prateek Bora
        event = edict[event_num]
144 59da6684 Stefan Hajnoczi
        if event_num not in fn_cache:
145 59da6684 Stefan Hajnoczi
            fn_cache[event_num] = build_fn(analyzer, event)
146 59da6684 Stefan Hajnoczi
        fn_cache[event_num](event, rec)
147 59da6684 Stefan Hajnoczi
    analyzer.end()
148 59da6684 Stefan Hajnoczi
149 59da6684 Stefan Hajnoczi
def run(analyzer):
150 59da6684 Stefan Hajnoczi
    """Execute an analyzer on a trace file given on the command-line.
151 59da6684 Stefan Hajnoczi

152 59da6684 Stefan Hajnoczi
    This function is useful as a driver for simple analysis scripts.  More
153 59da6684 Stefan Hajnoczi
    advanced scripts will want to call process() instead."""
154 59da6684 Stefan Hajnoczi
    import sys
155 59da6684 Stefan Hajnoczi
156 59da6684 Stefan Hajnoczi
    if len(sys.argv) != 3:
157 59da6684 Stefan Hajnoczi
        sys.stderr.write('usage: %s <trace-events> <trace-file>\n' % sys.argv[0])
158 59da6684 Stefan Hajnoczi
        sys.exit(1)
159 59da6684 Stefan Hajnoczi
160 90a147a2 Harsh Prateek Bora
    events = _read_events(open(sys.argv[1], 'r'))
161 59da6684 Stefan Hajnoczi
    process(events, sys.argv[2], analyzer)
162 59da6684 Stefan Hajnoczi
163 59da6684 Stefan Hajnoczi
if __name__ == '__main__':
164 59da6684 Stefan Hajnoczi
    class Formatter(Analyzer):
165 59da6684 Stefan Hajnoczi
        def __init__(self):
166 59da6684 Stefan Hajnoczi
            self.last_timestamp = None
167 59da6684 Stefan Hajnoczi
168 59da6684 Stefan Hajnoczi
        def catchall(self, event, rec):
169 90a147a2 Harsh Prateek Bora
            i = 1
170 59da6684 Stefan Hajnoczi
            timestamp = rec[1]
171 59da6684 Stefan Hajnoczi
            if self.last_timestamp is None:
172 59da6684 Stefan Hajnoczi
                self.last_timestamp = timestamp
173 59da6684 Stefan Hajnoczi
            delta_ns = timestamp - self.last_timestamp
174 59da6684 Stefan Hajnoczi
            self.last_timestamp = timestamp
175 59da6684 Stefan Hajnoczi
176 90a147a2 Harsh Prateek Bora
            fields = [event.name, '%0.3f' % (delta_ns / 1000.0)]
177 90a147a2 Harsh Prateek Bora
            for type, name in event.args:
178 90a147a2 Harsh Prateek Bora
                if is_string(type):
179 90a147a2 Harsh Prateek Bora
                    fields.append('%s=%s' % (name, rec[i + 1]))
180 90a147a2 Harsh Prateek Bora
                else:
181 90a147a2 Harsh Prateek Bora
                    fields.append('%s=0x%x' % (name, rec[i + 1]))
182 90a147a2 Harsh Prateek Bora
                i += 1
183 59da6684 Stefan Hajnoczi
            print ' '.join(fields)
184 59da6684 Stefan Hajnoczi
185 59da6684 Stefan Hajnoczi
    run(Formatter())