]> Git Repo - qemu.git/blame - scripts/simpletrace.py
MAINTAINERS: add LatticeMico32 maintainer
[qemu.git] / scripts / simpletrace.py
CommitLineData
26f7227b
SH
1#!/usr/bin/env python
2#
3# Pretty-printer for simple trace backend binary trace files
4#
5# Copyright IBM, Corp. 2010
6#
7# This work is licensed under the terms of the GNU GPL, version 2. See
8# the COPYING file in the top-level directory.
9#
10# For help see docs/tracing.txt
11
26f7227b
SH
12import struct
13import re
59da6684 14import inspect
26f7227b
SH
15
16header_event_id = 0xffffffffffffffff
17header_magic = 0xf2b177cb0aa429b4
18header_version = 0
19
20trace_fmt = '=QQQQQQQQ'
21trace_len = struct.calcsize(trace_fmt)
6df40080 22event_re = re.compile(r'(disable\s+)?([a-zA-Z0-9_]+)\(([^)]*)\).*')
26f7227b 23
26f7227b 24def parse_events(fobj):
59da6684 25 """Parse a trace-events file into {event_num: (name, arg1, ...)}."""
26f7227b
SH
26
27 def get_argnames(args):
28 """Extract argument names from a parameter list."""
29 return tuple(arg.split()[-1].lstrip('*') for arg in args.split(','))
30
31 events = {}
32 event_num = 0
33 for line in fobj:
34 m = event_re.match(line.strip())
35 if m is None:
36 continue
37
6df40080 38 disable, name, args = m.groups()
26f7227b
SH
39 events[event_num] = (name,) + get_argnames(args)
40 event_num += 1
41 return events
42
43def read_record(fobj):
59da6684 44 """Deserialize a trace record from a file into a tuple (event_num, timestamp, arg1, ..., arg6)."""
26f7227b
SH
45 s = fobj.read(trace_len)
46 if len(s) != trace_len:
47 return None
48 return struct.unpack(trace_fmt, s)
49
50def read_trace_file(fobj):
59da6684 51 """Deserialize trace records from a file, yielding record tuples (event_num, timestamp, arg1, ..., arg6)."""
26f7227b
SH
52 header = read_record(fobj)
53 if header is None or \
54 header[0] != header_event_id or \
55 header[1] != header_magic or \
56 header[2] != header_version:
59da6684 57 raise ValueError('not a trace file or incompatible version')
26f7227b
SH
58
59 while True:
60 rec = read_record(fobj)
61 if rec is None:
62 break
63
64 yield rec
65
59da6684
SH
66class Analyzer(object):
67 """A trace file analyzer which processes trace records.
68
69 An analyzer can be passed to run() or process(). The begin() method is
70 invoked, then each trace record is processed, and finally the end() method
71 is invoked.
72
73 If a method matching a trace event name exists, it is invoked to process
74 that trace record. Otherwise the catchall() method is invoked."""
75
76 def begin(self):
77 """Called at the start of the trace."""
78 pass
79
80 def catchall(self, event, rec):
81 """Called if no specific method for processing a trace event has been found."""
82 pass
83
84 def end(self):
85 """Called at the end of the trace."""
86 pass
87
88def process(events, log, analyzer):
89 """Invoke an analyzer on each event in a log."""
90 if isinstance(events, str):
91 events = parse_events(open(events, 'r'))
92 if isinstance(log, str):
93 log = open(log, 'rb')
94
95 def build_fn(analyzer, event):
96 fn = getattr(analyzer, event[0], None)
97 if fn is None:
98 return analyzer.catchall
99
100 event_argcount = len(event) - 1
101 fn_argcount = len(inspect.getargspec(fn)[0]) - 1
102 if fn_argcount == event_argcount + 1:
103 # Include timestamp as first argument
104 return lambda _, rec: fn(*rec[1:2 + fn_argcount])
105 else:
106 # Just arguments, no timestamp
107 return lambda _, rec: fn(*rec[2:2 + fn_argcount])
108
109 analyzer.begin()
110 fn_cache = {}
111 for rec in read_trace_file(log):
112 event_num = rec[0]
113 event = events[event_num]
114 if event_num not in fn_cache:
115 fn_cache[event_num] = build_fn(analyzer, event)
116 fn_cache[event_num](event, rec)
117 analyzer.end()
118
119def run(analyzer):
120 """Execute an analyzer on a trace file given on the command-line.
121
122 This function is useful as a driver for simple analysis scripts. More
123 advanced scripts will want to call process() instead."""
124 import sys
125
126 if len(sys.argv) != 3:
127 sys.stderr.write('usage: %s <trace-events> <trace-file>\n' % sys.argv[0])
128 sys.exit(1)
129
130 events = parse_events(open(sys.argv[1], 'r'))
131 process(events, sys.argv[2], analyzer)
132
133if __name__ == '__main__':
134 class Formatter(Analyzer):
135 def __init__(self):
136 self.last_timestamp = None
137
138 def catchall(self, event, rec):
139 timestamp = rec[1]
140 if self.last_timestamp is None:
141 self.last_timestamp = timestamp
142 delta_ns = timestamp - self.last_timestamp
143 self.last_timestamp = timestamp
144
145 fields = [event[0], '%0.3f' % (delta_ns / 1000.0)]
146 for i in xrange(1, len(event)):
147 fields.append('%s=0x%x' % (event[i], rec[i + 1]))
148 print ' '.join(fields)
149
150 run(Formatter())
This page took 0.127439 seconds and 4 git commands to generate.