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
7import re, sys, string, signal, struct, os, getopt
8
9def 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, ...
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 7 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
35def 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
58def sighand(x,y):
59    global interrupted
60    interrupted = 1
61
62##### Main code
63
64mhz = 0
65
66if len(sys.argv) < 2:
67    usage()
68
69try:
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
75except getopt.GetoptError:
76    usage()
77
78signal.signal(signal.SIGTERM, sighand)
79signal.signal(signal.SIGHUP,  sighand)
80signal.signal(signal.SIGINT,  sighand)
81
82interrupted = 0
83
84try:
85    defs = read_defs(arg[0])
86except IOError, exn:
87    print exn
88    sys.exit(1)
89
90# structure of trace record (as output by xentrace):
91# HDR(I) {TSC(Q)} D1(I) D2(I) D3(I) D4(I) D5(I) D6(I) D7(I)
92#
93# HDR consists of EVENT:28:, n_data:3:, tsc_in:1:
94# EVENT means Event ID
95# n_data means number of data (like D1, D2, ...)
96# tsc_in means TSC data exists(1) or not(0).
97# if tsc_in == 0, TSC(Q) does not exists.
98#
99# CPU ID exists on trace data of EVENT=0x0001f003
100#
101HDRREC = "I"
102TSCREC = "Q"
103D1REC  = "I"
104D2REC  = "II"
105D3REC  = "III"
106D4REC  = "IIII"
107D5REC  = "IIIII"
108D6REC  = "IIIIII"
109D7REC  = "IIIIIII"
110
111last_tsc = [0]
112
113TRC_TRACE_IRQ = 0x1f004
114TRC_PV_HYPERCALL_V2 = 0x20100d
115TRC_PV_HYPERCALL_SUBCALL = 0x20100e
116
117NR_VECTORS = 256
118irq_measure = [{'count':0, 'tot_cycles':0, 'max_cycles':0}] * NR_VECTORS
119
120i=0
121
122while not interrupted:
123    try:
124        i=i+1
125        line = sys.stdin.read(struct.calcsize(HDRREC))
126        if not line:
127            break
128        event = struct.unpack(HDRREC, line)[0]
129        n_data = event >> 28 & 0x7
130        tsc_in = event >> 31
131
132        d1 = 0
133        d2 = 0
134        d3 = 0
135        d4 = 0
136        d5 = 0
137        d6 = 0
138        d7 = 0
139
140        tsc = 0
141
142        if tsc_in == 1:
143            line = sys.stdin.read(struct.calcsize(TSCREC))
144            if not line:
145                break
146            tsc = struct.unpack(TSCREC, line)[0]
147
148        if n_data == 1:
149            line = sys.stdin.read(struct.calcsize(D1REC))
150            if not line:
151                break
152            d1 = struct.unpack(D1REC, line)[0]
153        if n_data == 2:
154            line = sys.stdin.read(struct.calcsize(D2REC))
155            if not line:
156                break
157            (d1, d2) = struct.unpack(D2REC, line)
158        if n_data == 3:
159            line = sys.stdin.read(struct.calcsize(D3REC))
160            if not line:
161                break
162            (d1, d2, d3) = struct.unpack(D3REC, line)
163        if n_data == 4:
164            line = sys.stdin.read(struct.calcsize(D4REC))
165            if not line:
166                break
167            (d1, d2, d3, d4) = struct.unpack(D4REC, line)
168        if n_data == 5:
169            line = sys.stdin.read(struct.calcsize(D5REC))
170            if not line:
171                break
172            (d1, d2, d3, d4, d5) = struct.unpack(D5REC, line)
173        if n_data == 6:
174            line = sys.stdin.read(struct.calcsize(D6REC))
175            if not line:
176                break
177            (d1, d2, d3, d4, d5, d6) = struct.unpack(D6REC, line)
178        if n_data == 7:
179            line = sys.stdin.read(struct.calcsize(D7REC))
180            if not line:
181                break
182            (d1, d2, d3, d4, d5, d6, d7) = struct.unpack(D7REC, line)
183
184        # Event field is 28bit of 'uint32_t' in header, not 'long'.
185        event &= 0x0fffffff
186        if event == 0x1f003:
187            cpu = d1
188
189        if event == TRC_TRACE_IRQ:
190            # IN - d1:vector, d2:tsc_in, d3:tsc_out
191            # OUT - d1:vector, d2:count, d3:tot_cycles, d4:max_cycles
192            tsc_diff = d3 - d2
193            if tsc_diff < 0:
194                break
195            irq_measure[d1]['count'] += 1
196            irq_measure[d1]['tot_cycles'] += tsc_diff
197            if irq_measure[d1]['max_cycles'] < tsc_diff:
198                irq_measure[d1]['max_cycles'] = tsc_diff
199            d2 = irq_measure[d1]['count']
200            d3 = irq_measure[d1]['tot_cycles']
201            d4 = irq_measure[d1]['max_cycles']
202
203        if event == TRC_PV_HYPERCALL_V2 or event == TRC_PV_HYPERCALL_SUBCALL:
204            # Mask off the argument present bits.
205            d1 &= 0x000fffff
206
207        #tsc = (tscH<<32) | tscL
208
209        #print i, tsc
210
211        if cpu >= len(last_tsc):
212            last_tsc += [0] * (cpu - len(last_tsc) + 1)
213        elif tsc < last_tsc[cpu] and tsc_in == 1:
214            print "TSC stepped backward cpu %d !  %d %d" % (cpu,tsc,last_tsc[cpu])
215
216        # provide relative TSC
217        if last_tsc[cpu] > 0 and tsc_in == 1:
218            reltsc = tsc - last_tsc[cpu]
219        else:
220            reltsc = 0
221
222        if tsc_in == 1:
223            last_tsc[cpu] = tsc
224
225        if mhz:
226            tsc = tsc / (mhz*1000000.0)
227
228        args = {'cpu'   : cpu,
229                'tsc'   : tsc,
230                'event' : event,
231                'reltsc': reltsc,
232                '1'     : d1,
233                '2'     : d2,
234                '3'     : d3,
235                '4'     : d4,
236                '5'     : d5,
237                '6'     : d6,
238                '7'     : d7    }
239
240        try:
241
242            if defs.has_key(str(event)):
243                print defs[str(event)] % args
244            else:
245                if defs.has_key(str(0)): print defs[str(0)] % args
246        except TypeError:
247            if defs.has_key(str(event)):
248                print defs[str(event)]
249                print args
250            else:
251                if defs.has_key(str(0)):
252                    print defs[str(0)]
253                    print args
254
255
256    except IOError, struct.error: sys.exit()
257