| 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() |
|---|