1#!/usr/bin/python3
2# -*- coding: UTF-8 -*-
3
4import os
5import re
6import sys
7import string
8import signal
9import struct
10import getopt
11
12def usage():
13    print >> sys.stderr, \
14          """
15    Usage:
16          acrntrace_format.py [options] [formats] [trace_data]
17
18          [options]
19          -h: print this message
20
21          Parses trace_data in binary format generated by acrntrace and
22          reformats it according to the rules in the [formats] file.
23          The rules in formats should have the format ({ and } show grouping
24          and are not part of the syntax):
25
26          {event_id}{whitespace}{text format string}
27
28          The textual format string may include format specifiers, such as
29          %(cpu)d, %(tsc)d, %(event)d, %(1)d, %(2)d, ....
30          The 'd' format specifier outputs in decimal, alternatively 'x' will
31          output in hexadecimal and 'o' will output in octal.
32
33          These respectively correspond to the CPU number (cpu), timestamp
34          counter (tsc), event ID (event) and the data logged in the trace file.
35          There can be only one such rule for each type of event.
36          """
37
38def read_format(format_file):
39    formats = {}
40
41    fd = open(format_file)
42
43    reg = re.compile('(\S+)\s+(\S.*)')
44
45    while True:
46        line = fd.readline()
47        if not line:
48            break
49
50        if line[0] == '#' or line[0] == '\n':
51            continue
52
53        m = reg.match(line)
54
55        if not m: print >> sys.stderr, "Wrong format file"; sys.exit(1)
56
57        formats[str(eval(m.group(1)))] = m.group(2)
58
59    return formats
60
61exit = 0
62
63# structure of trace data (as output by acrntrace)
64# TSC(Q) HDR(Q) D1 D2 ...
65# HDR consists of event:48:, n_data:8:, cpu:8:
66# event means Event ID
67# n_data means number of data in trace entry (like D1, D2, ...)
68# cpu means cpu id this trace entry belong to
69TSCREC = "Q"
70HDRREC = "Q"
71D2REC  = "QQ"
72D4REC = "IIII"
73D8REC = "BBBBBBBBBBBBBBBB"
74D16REC = "bbbbbbbbbbbbbbbb"
75
76def main_loop(formats, fd):
77    global exit
78    i = 0
79
80
81    while not exit:
82        try:
83            i = i + 1
84
85            line = fd.read(struct.calcsize(TSCREC))
86            if not line:
87                break
88            tsc = struct.unpack(TSCREC, line)[0]
89
90            line = fd.read(struct.calcsize(HDRREC))
91            if not line:
92                break
93            event = struct.unpack(HDRREC, line)[0]
94            n_data = event >> 48 & 0xff
95            cpu = event >> 56
96            event = event & 0xffffffffffff
97
98            d1 = 0
99            d2 = 0
100            d3 = 0
101            d4 = 0
102            d5 = 0
103            d6 = 0
104            d7 = 0
105            d8 = 0
106            d9 = 0
107            d10 = 0
108            d11 = 0
109            d12 = 0
110            d13 = 0
111            d14 = 0
112            d15 = 0
113            d16 = 0
114
115            if n_data == 2:
116                line = fd.read(struct.calcsize(D2REC))
117                if not line:
118                    break
119                (d1, d2) = struct.unpack(D2REC, line)
120
121            if n_data == 4:
122                line = fd.read(struct.calcsize(D4REC))
123                if not line:
124                    break
125                (d1, d2, d3, d4) = struct.unpack(D4REC, line)
126
127            if n_data == 8:
128                line = fd.read(struct.calcsize(D8REC))
129                if not line:
130                    break
131                # TRACE_6C using the first 6 data of fields_8. Actaully we have
132                # 16 data in every trace entry.
133                (d1, d2, d3, d4, d5, d6, d7, d8,
134                 d9, d10, d11, d12, d13, d14, d15, d16) = struct.unpack(D8REC, line)
135
136            if n_data == 16:
137                line = fd.read(struct.calcsize(D16REC))
138                if not line:
139                    break
140
141                (d1, d2, d3, d4, d5, d6, d7, d8,
142                 d9, d10, d11, d12, d13, d14, d15, d16) = struct.unpack(D16REC, line)
143
144            args = {'cpu'   : cpu,
145                    'tsc'   : tsc,
146                    'event' : event,
147                    '1'     : d1,
148                    '2'     : d2,
149                    '3'     : d3,
150                    '4'     : d4,
151                    '5'     : d5,
152                    '6'     : d6,
153                    '7'     : d7,
154                    '8'     : d8,
155                    '9'     : d9,
156                    '10'    : d10,
157                    '11'    : d11,
158                    '12'    : d12,
159                    '13'    : d13,
160                    '14'    : d14,
161                    '15'    : d15,
162                    '16'    : d16      }
163
164            try:
165                if str(event) in formats.keys():
166                    print (formats[str(event)] % args)
167            except TypeError:
168                if str(event) in formats.key():
169                    print (formats[str(event)])
170                    print (args)
171
172        except struct.error:
173            sys.exit()
174
175def main(argv):
176    try:
177        opts, arg = getopt.getopt(sys.argv[1:], "h")
178
179        for opt in opts:
180            if opt[0] == '-h':
181                usage()
182                sys.exit()
183
184    except getopt.GetoptError:
185        usage()
186        sys.exit(1)
187
188    try:
189        formats = read_format(arg[0])
190        fd = open(arg[1], 'rb')
191    except IOError:
192        sys.exit(1)
193
194    main_loop(formats, fd)
195
196if __name__ == "__main__":
197    main(sys.argv[1:])
198