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()) |