1 | #!/usr/bin/env python |
---|
2 | |
---|
3 | # by Mark Williamson, (C) 2004 Intel Research Cambridge |
---|
4 | |
---|
5 | # Program for reformatting trace buffer output according to user-supplied rules |
---|
6 | |
---|
7 | import re, sys, string, signal, struct, os, getopt |
---|
8 | |
---|
9 | def usage(): |
---|
10 | print >> sys.stderr, \ |
---|
11 | "Usage: " + sys.argv[0] + """ defs-file |
---|
12 | Parses trace data in binary format, as output by Xentrace and |
---|
13 | reformats it according to the rules in a file of definitions. The |
---|
14 | rules in this file should have the format ({ and } show grouping |
---|
15 | and are not part of the syntax): |
---|
16 | |
---|
17 | {event_id}{whitespace}{text format string} |
---|
18 | |
---|
19 | The textual format string may include format specifiers, such as: |
---|
20 | %(cpu)d, %(tsc)d, %(event)d, %(1)d, %(2)d, %(3)d, %(4)d, %(5)d |
---|
21 | [ the 'd' format specifier outputs in decimal, alternatively 'x' |
---|
22 | will output in hexadecimal and 'o' will output in octal ] |
---|
23 | |
---|
24 | Which correspond to the CPU number, event ID, timestamp counter and |
---|
25 | the 5 data fields from the trace record. There should be one such |
---|
26 | rule for each type of event. |
---|
27 | |
---|
28 | Depending on your system and the volume of trace buffer data, |
---|
29 | this script may not be able to keep up with the output of xentrace |
---|
30 | if it is piped directly. In these circumstances you should have |
---|
31 | xentrace output to a file for processing off-line. |
---|
32 | """ |
---|
33 | sys.exit(1) |
---|
34 | |
---|
35 | def read_defs(defs_file): |
---|
36 | defs = {} |
---|
37 | |
---|
38 | fd = open(defs_file) |
---|
39 | |
---|
40 | reg = re.compile('(\S+)\s+(\S.*)') |
---|
41 | |
---|
42 | while True: |
---|
43 | line = fd.readline() |
---|
44 | if not line: |
---|
45 | break |
---|
46 | |
---|
47 | if line[0] == '#' or line[0] == '\n': |
---|
48 | continue |
---|
49 | |
---|
50 | m = reg.match(line) |
---|
51 | |
---|
52 | if not m: print >> sys.stderr, "Bad format file" ; sys.exit(1) |
---|
53 | |
---|
54 | defs[str(eval(m.group(1)))] = m.group(2) |
---|
55 | |
---|
56 | return defs |
---|
57 | |
---|
58 | def sighand(x,y): |
---|
59 | global interrupted |
---|
60 | interrupted = 1 |
---|
61 | |
---|
62 | ##### Main code |
---|
63 | |
---|
64 | mhz = 0 |
---|
65 | |
---|
66 | if len(sys.argv) < 2: |
---|
67 | usage() |
---|
68 | |
---|
69 | try: |
---|
70 | opts, arg = getopt.getopt(sys.argv[1:], "c:" ) |
---|
71 | |
---|
72 | for opt in opts: |
---|
73 | if opt[0] == '-c' : mhz = int(opt[1]) |
---|
74 | |
---|
75 | except getopt.GetoptError: |
---|
76 | usage() |
---|
77 | |
---|
78 | signal.signal(signal.SIGTERM, sighand) |
---|
79 | signal.signal(signal.SIGHUP, sighand) |
---|
80 | signal.signal(signal.SIGINT, sighand) |
---|
81 | |
---|
82 | interrupted = 0 |
---|
83 | |
---|
84 | defs = read_defs(arg[0]) |
---|
85 | |
---|
86 | # structure of trace record + prepended CPU id (as output by xentrace): |
---|
87 | # CPU(I) TSC(Q) EVENT(L) D1(L) D2(L) D3(L) D4(L) D5(L) |
---|
88 | # read CPU id separately to avoid structure packing problems on 64-bit arch. |
---|
89 | CPUREC = "I" |
---|
90 | TRCREC = "QLLLLLL" |
---|
91 | |
---|
92 | last_tsc = [0] |
---|
93 | |
---|
94 | i=0 |
---|
95 | |
---|
96 | while not interrupted: |
---|
97 | try: |
---|
98 | i=i+1 |
---|
99 | line = sys.stdin.read(struct.calcsize(CPUREC)) |
---|
100 | if not line: |
---|
101 | break |
---|
102 | cpu = struct.unpack(CPUREC, line)[0] |
---|
103 | |
---|
104 | line = sys.stdin.read(struct.calcsize(TRCREC)) |
---|
105 | if not line: |
---|
106 | break |
---|
107 | |
---|
108 | (tsc, event, d1, d2, d3, d4, d5) = struct.unpack(TRCREC, line) |
---|
109 | |
---|
110 | # Event field is 'uint32_t', not 'long'. |
---|
111 | event &= 0xffffffff |
---|
112 | |
---|
113 | #tsc = (tscH<<32) | tscL |
---|
114 | |
---|
115 | #print i, tsc |
---|
116 | |
---|
117 | if cpu >= len(last_tsc): |
---|
118 | last_tsc += [0] * (cpu - len(last_tsc) + 1) |
---|
119 | elif tsc < last_tsc[cpu]: |
---|
120 | print "TSC stepped backward cpu %d ! %d %d" % (cpu,tsc,last_tsc[cpu]) |
---|
121 | |
---|
122 | # provide relative TSC |
---|
123 | if last_tsc[cpu] > 0: |
---|
124 | reltsc = tsc - last_tsc[cpu] |
---|
125 | else: |
---|
126 | reltsc = 0 |
---|
127 | |
---|
128 | last_tsc[cpu] = tsc |
---|
129 | |
---|
130 | if mhz: |
---|
131 | tsc = tsc / (mhz*1000000.0) |
---|
132 | |
---|
133 | args = {'cpu' : cpu, |
---|
134 | 'tsc' : tsc, |
---|
135 | 'event' : event, |
---|
136 | 'reltsc': reltsc, |
---|
137 | '1' : d1, |
---|
138 | '2' : d2, |
---|
139 | '3' : d3, |
---|
140 | '4' : d4, |
---|
141 | '5' : d5 } |
---|
142 | |
---|
143 | try: |
---|
144 | |
---|
145 | if defs.has_key(str(event)): |
---|
146 | print defs[str(event)] % args |
---|
147 | else: |
---|
148 | if defs.has_key(str(0)): print defs[str(0)] % args |
---|
149 | except TypeError: |
---|
150 | print defs[str(event)] |
---|
151 | print args |
---|
152 | |
---|
153 | |
---|
154 | except IOError, struct.error: sys.exit() |
---|