Only break Profile translations on existing SrcRecs
[hiphop-php.git] / hphp / tools / perf-script-raw.py
blob2a281b040f0a13cd78c0899d399587f5d859dd60
1 #!/usr/bin/env python
3 # This script processes the output of 'perf script' and prints raw data in the
4 # the following format:
6 # BINARY_NAME EVENT NUM_IPS
7 # INSTRUCTION_PTR_1
8 # INSTRUCTION_PTR_2
9 # ...
10 # INSTRUCTION_PTR_NUM_IPS
12 # The perf data may be recorded with -g or not.
15 import string, sys
18 # Positions of various fields within a line. Assumes lines look like this:
19 # BINARY EVENT IP FUNCTION
20 # hhvm cycles: d87415 HPHP::ObjectData::destruct()
22 BINARY_NAME_FIELD = 0
23 EVENT_FIELD = 1
24 IP_FIELD = 2
25 FUNCTION_FIELD = 3
27 def remove_raw_annotation(header):
28 """For non-generic events, perf adds a 'raw' annotation before the
29 event id: remove it and return the modified header."""
30 fields = header.split(None)
31 if (fields[EVENT_FIELD] == 'raw'):
32 del fields[4]
33 return ' '.join(fields)
35 def extract_function(long_symbol):
36 short_symbol = long_symbol.split('(', 1)[0]
37 if short_symbol == "":
38 return "unknown"
39 return short_symbol
41 def process(record):
42 if state == WITH_STACKTRACES:
43 header = record[0]
44 else:
45 header = record
47 header = remove_raw_annotation(header)
49 fields = header.split(None)
50 binary_name = fields[BINARY_NAME_FIELD]
51 event = fields[EVENT_FIELD][:-1]
52 trace_entries = []
54 if state == NORMAL:
55 # perf record was called without "-g"
56 try:
57 entry = (int(fields[IP_FIELD], 16),
58 extract_function(fields[FUNCTION_FIELD]))
59 trace_entries.append(entry)
60 except ValueError:
61 # Sometimes you get weird garbage from perf script (This
62 # fix is motivated by a record that had spaces in the
63 # binary name, sigh). Ignore and move on.
64 return
65 elif state == WITH_STACKTRACES:
66 # perf record was called with "-g"
67 if len(record) == 1:
68 return
69 for line in record[1:]:
70 line_fields = line.split(None)
71 entry = (int(line_fields[0], 16),
72 extract_function(line_fields[1]))
73 trace_entries.append(entry)
75 print("%s %s %u" % (binary_name, event, len(trace_entries)))
76 for entry in trace_entries:
77 print("0x%lx %s" % (entry[0], entry[1]))
80 NORMAL = 0
81 WITH_STACKTRACES = 1
83 def records():
84 global state
86 # Skip comment lines.
87 while True:
88 line = sys.stdin.readline()
89 if (not line):
90 return
91 if (line[0] != '#'):
92 break
94 if len(line.split(None)) >= 4:
95 state = NORMAL
96 else:
97 state = WITH_STACKTRACES
99 if state == NORMAL:
100 yield line
101 for line in sys.stdin:
102 if (line[0] == "#"):
103 continue
104 yield line
105 return
107 # state == WITH_STACKTRACES
108 lines = [line]
109 for line in sys.stdin:
110 if (line[0] == "#"):
111 continue
112 if line == '\n':
113 yield lines
114 lines = []
115 else:
116 lines.append(line)
117 if (len(lines) > 0):
118 yield lines
120 if __name__ == '__main__':
121 for record in records():
122 process(record)