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