3 # Copyright (C) 2017 The Android Open Source Project
5 # Licensed under the Apache License, Version 2.0 (the "License");
6 # you may not use this file except in compliance with the License.
7 # You may obtain a copy of the License at
9 # http://www.apache.org/licenses/LICENSE-2.0
11 # Unless required by applicable law or agreed to in writing, software
12 # distributed under the License is distributed on an "AS IS" BASIS,
13 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 # See the License for the specific language governing permissions and
15 # limitations under the License.
17 # Super simplistic printer of a perfprofd output proto. Illustrates
18 # how to parse and traverse a perfprofd output proto in Python.
21 # aprotoc -I=system/extras/perfprofd --python_out=system/extras/perfprofd/scripts \
22 # system/extras/perfprofd/perf_profile.proto
23 import perf_profile_pb2
25 # Make sure that symbol is on the PYTHONPATH, e.g., run as
26 # PYTHONPATH=$PYTHONPATH:$ANDROID_BUILD_TOP/development/scripts python ...
29 # This is wrong. But then the symbol module is a bad quagmire.
30 symbol.SetAbi(["ABI: 'arm64'"])
31 print "Reading symbols from", symbol.SYMBOLS_DIR
33 # TODO: accept argument for parsing.
34 file = open('perf.data.encoded.0', 'rb')
37 profile = perf_profile_pb2.AndroidPerfProfile()
38 profile.ParseFromString(data)
40 print "Total samples: ", profile.total_samples
42 module_list = profile.load_modules
46 def indent(txt, stops = 1):
47 return '\n'.join(' ' * stops + line for line in txt.splitlines())
50 def print_samples(module_list, programs, counters):
52 for program in programs:
53 print indent(program.name, 1)
54 for module in program.modules:
55 if module.HasField('load_module_id'):
56 module_descr = module_list[module.load_module_id]
57 print indent(module_descr.name, 2)
58 has_build_id = module_descr.HasField('build_id')
60 print indent('Build ID: %s' % (module_descr.build_id), 3)
61 for addr in module.address_samples:
62 # TODO: Stacks vs single samples.
63 addr_rel = addr.address[0]
64 addr_rel_hex = "%x" % addr_rel
65 print indent('%d %s' % (addr.count, addr_rel_hex), 3)
66 if module_descr.name != '[kernel.kallsyms]':
68 info = symbol.SymbolInformation(module_descr.name, addr_rel_hex)
69 # As-is, only info[0] (inner-most inlined function) is recognized.
70 (source_symbol, source_location, object_symbol_with_offset) = info[0]
71 if object_symbol_with_offset is not None:
72 print indent(object_symbol_with_offset, 4)
73 if source_symbol is not None:
74 for (sym_inlined, loc_inlined, _) in info:
75 # TODO: Figure out what's going on here:
76 if sym_inlined is not None:
77 print indent(sym_inlined, 5)
79 print indent('???', 5)
80 if loc_inlined is not None:
81 print ' %s' % (indent(loc_inlined, 5))
82 elif module_descr.symbol and (addr_rel & 0x8000000000000000 != 0):
83 index = 0xffffffffffffffff - addr_rel
84 source_symbol = module_descr.symbol[index]
85 print indent(source_symbol, 4)
87 if source_symbol is not None:
88 counters_key = (module_descr.name, source_symbol)
90 counters_key = (module_descr.name, addr_rel_hex)
91 if counters_key in counters:
92 counters[counters_key] = counters[counters_key] + addr.count
94 counters[counters_key] = addr.count
96 print indent('<Missing module>', 2)
98 def print_histogram(counters, size):
99 # Create a sorted list of top samples.
101 for key, value in counters.iteritems():
103 counter_list.append(temp)
104 counter_list.sort(key=lambda counter: counter[1], reverse=True)
106 # Print top-size samples.
107 print 'Histogram top-%d:' % (size)
108 for i in xrange(0, min(len(counter_list), size)):
109 print indent('%d: %s' % (i+1, counter_list[i]), 1)
111 def print_modules(module_list):
113 for module in module_list:
114 print indent(module.name, 1)
115 if module.HasField('build_id'):
116 print indent('Build ID: %s' % (module.build_id), 2)
117 print indent('Symbols:', 2)
118 for symbol in module.symbol:
119 print indent(symbol, 3)
121 print_samples(module_list, profile.programs, counters)
122 print_modules(module_list)
123 print_histogram(counters, 100)