Update NDK prebuilts to build 3839284.
Taken from branch aosp-master.
Change-Id: Ie3f4c61dc9cbd710347b3911082dad38693cfbc5
diff --git a/annotate.py b/annotate.py
index b49942f..d25a6cd 100644
--- a/annotate.py
+++ b/annotate.py
@@ -29,6 +29,25 @@
from simpleperf_report_lib import *
from utils import *
+class SourceLine(object):
+ def __init__(self, file, function, line):
+ self.file = file
+ self.function = function
+ self.line = line
+
+ @property
+ def file_key(self):
+ return self.file
+
+ @property
+ def function_key(self):
+ return (self.file, self.function)
+
+ @property
+ def line_key(self):
+ return (self.file, self.line)
+
+
# TODO: using addr2line can't convert from function_start_address to
# source_file:line very well for java code. Because in .debug_line section,
# there is some distance between function_start_address and the address
@@ -36,10 +55,10 @@
class Addr2Line(object):
"""collect information of how to map [dso_name,vaddr] to [source_file:line].
"""
- def __init__(self, annotator, addr2line_path):
+ def __init__(self, addr2line_path, symfs_dir=None):
self.dso_dict = dict()
- self.annotator = annotator
self.addr2line_path = addr2line_path
+ self.symfs_dir = symfs_dir
def add_addr(self, dso_name, addr):
@@ -55,6 +74,8 @@
self.file_list = []
# map from file to id with file_list[id] == file
self.file_dict = {}
+ self.file_list.append('')
+ self.file_dict[''] = 0
for dso_name in self.dso_dict.keys():
self._convert_addrs_to_lines(dso_name, self.dso_dict[dso_name])
@@ -62,43 +83,60 @@
def _convert_addrs_to_lines(self, dso_name, dso):
- dso_path = self.annotator.find_dso_path(dso_name)
+ dso_path = self._find_dso_path(dso_name)
if dso_path is None:
log_warning("can't find dso '%s'" % dso_name)
dso.clear()
return
- addrs = sorted(dso.keys());
+ addrs = sorted(dso.keys())
addr_str = []
for addr in addrs:
addr_str.append('0x%x' % addr)
addr_str = '\n'.join(addr_str)
- subproc = subprocess.Popen([self.addr2line_path, '-e', dso_path],
+ subproc = subprocess.Popen([self.addr2line_path, '-e', dso_path, '-aifC'],
stdin=subprocess.PIPE, stdout=subprocess.PIPE)
(stdoutdata, _) = subproc.communicate(addr_str)
- stdoutdata = stdoutdata.split('\n')
+ stdoutdata = stdoutdata.strip().split('\n')
if len(stdoutdata) < len(addrs):
log_fatal("addr2line didn't output enough lines")
- for i in range(len(addrs)):
- strs = stdoutdata[i].split(':')
- if len(strs) == 2 and strs[0].find('?') == -1:
- file = strs[0].strip()
- if strs[1].find('?') == -1:
- line = 0
- for c in strs[1]:
- if c.isdigit():
- line = line * 10 + ord(c) - ord('0')
- else:
- break
+ addr_pos = 0
+ out_pos = 0
+ while addr_pos < len(addrs) and out_pos < len(stdoutdata):
+ addr_line = stdoutdata[out_pos]
+ out_pos += 1
+ assert addr_line[:2] == "0x"
+ assert out_pos < len(stdoutdata)
+ assert addrs[addr_pos] == int(addr_line, 16)
+ source_lines = []
+ while out_pos < len(stdoutdata) and stdoutdata[out_pos][:2] != "0x":
+ function = stdoutdata[out_pos]
+ out_pos += 1
+ assert out_pos < len(stdoutdata)
+ file, line = stdoutdata[out_pos].split(':')
+ line = line.split()[0] # Remove comments after line number
+ out_pos += 1
+ if file.find('?') != -1:
+ file = 0
else:
- line = None
- id = self.file_dict.get(file)
- if id is None:
- id = len(self.file_list)
- self.file_list.append(file)
- self.file_dict[file] = id
- dso[addrs[i]] = (id, line)
+ file = self._get_file_id(file)
+ if line.find('?') != -1:
+ line = 0
+ else:
+ line = int(line)
+ source_lines.append(SourceLine(file, function, line))
+ dso[addrs[addr_pos]] = source_lines
+ addr_pos += 1
+ assert addr_pos == len(addrs)
+ def _get_file_id(self, file):
+ id = self.file_dict.get(file)
+ if id is None:
+ id = len(self.file_list)
+ self.file_list.append(file)
+ self.file_dict[file] = id
+ return id
+
def _combine_source_files(self):
"""It is possible that addr2line gives us different names for the same
file, like:
@@ -135,14 +173,28 @@
self.file_list[from_id] = self.file_list[to_id]
- def get_source(self, dso_name, addr):
+ def get_sources(self, dso_name, addr):
dso = self.dso_dict.get(dso_name)
if dso is None:
- return (None, None)
- item = dso.get(addr)
- if item is None:
- return (None, None)
- return (self.file_list[item[0]], item[1])
+ return []
+ item = dso.get(addr, [])
+ source_lines = []
+ for source in item:
+ source_lines.append(SourceLine(self.file_list[source.file],
+ source.function, source.line))
+ return source_lines
+
+
+ def _find_dso_path(self, dso):
+ if dso[0] != '/' or dso == '//anon':
+ return None
+ if self.symfs_dir:
+ dso_path = os.path.join(self.symfs_dir, dso[1:])
+ if os.path.isfile(dso_path):
+ return dso_path
+ if os.path.isfile(dso):
+ return dso
+ return None
class Period(object):
@@ -200,7 +252,7 @@
def add_function_period(self, function_name, function_start_line, period):
a = self.function_dict.get(function_name)
- if a is None:
+ if not a:
if function_start_line is None:
function_start_line = -1
self.function_dict[function_name] = a = [function_start_line, Period()]
@@ -230,41 +282,25 @@
# init member variables
self.config = config
- self.symfs_dir = None
- self.kallsyms = None
- self.comm_filter = None
- self.pid_filter = None
- self.tid_filter = None
- self.dso_filter = None
- symfs_dir = config['symfs_dir']
- if symfs_dir:
- self.symfs_dir = symfs_dir
- kallsyms = config['kallsyms']
- if kallsyms:
- self.kallsyms = kallsyms
- comm_filter = config['comm_filters']
- if comm_filter:
- self.comm_filter = set(comm_filter)
- pid_filter = config['pid_filters']
- if pid_filter:
- self.pid_filter = set()
- for pid in pid_filter:
- self.pid_filter.add(int(pid))
- tid_filter = config['tid_filters']
- if tid_filter:
- self.tid_filter = set()
- for tid in tid_filter:
- self.tid_filter.add(int(tid))
- dso_filter = config['dso_filters']
- if dso_filter:
- self.dso_filter = set(dso_filter)
+ self.symfs_dir = config.get('symfs_dir')
+ self.kallsyms = config.get('kallsyms')
+ self.comm_filter = set(config['comm_filters']) if config.get('comm_filters') else None
+ if config.get('pid_filters'):
+ self.pid_filter = {int(x) for x in config['pid_filters']}
+ else:
+ self.pid_filter = None
+ if config.get('tid_filters'):
+ self.tid_filter = {int(x) for x in config['tid_filters']}
+ else:
+ self.tid_filter = None
+ self.dso_filter = set(config['dso_filters']) if config.get('dso_filters') else None
output_dir = config['annotate_dest_dir']
if os.path.isdir(output_dir):
shutil.rmtree(output_dir)
os.makedirs(output_dir)
- self.addr2line = Addr2Line(self, self.config['addr2line_path'])
+ self.addr2line = Addr2Line(self.config['addr2line_path'], symfs_dir)
def annotate(self):
@@ -282,9 +318,10 @@
"""
for perf_data in self.config['perf_data_list']:
lib = ReportLib()
- if self.symfs_dir is not None:
+ lib.SetRecordFile(perf_data)
+ if self.symfs_dir:
lib.SetSymfs(self.symfs_dir)
- if self.kallsyms is not None:
+ if self.kallsyms:
lib.SetKallsymsFile(self.kallsyms)
while True:
sample = lib.GetNextSample()
@@ -306,20 +343,20 @@
def _filter_sample(self, sample):
"""Return true if the sample can be used."""
- if self.comm_filter is not None:
+ if self.comm_filter:
if sample.thread_comm not in self.comm_filter:
return False
- if self.pid_filter is not None:
+ if self.pid_filter:
if sample.pid not in self.pid_filter:
return False
- if self.tid_filter is not None:
+ if self.tid_filter:
if sample.tid not in self.tid_filter:
return False
return True
def _filter_symbol(self, symbol):
- if self.dso_filter is None or symbol.dso_name in self.dso_filter:
+ if not self.dso_filter or symbol.dso_name in self.dso_filter:
return True
return False
@@ -328,18 +365,6 @@
self.addr2line.convert_addrs_to_lines()
- def find_dso_path(self, dso):
- if dso[0] != '/' or dso == '//anon':
- return None
- if self.symfs_dir is not None:
- dso_path = os.path.join(self.symfs_dir, dso[1:])
- if os.path.isfile(dso_path):
- return dso_path
- if os.path.isfile(dso):
- return dso
- return None
-
-
def _generate_periods(self):
"""read perf.data, collect Period for all types:
binaries, source files, functions, lines.
@@ -349,9 +374,10 @@
self.file_periods = dict()
for perf_data in self.config['perf_data_list']:
lib = ReportLib()
- if self.symfs_dir is not None:
+ lib.SetRecordFile(perf_data)
+ if self.symfs_dir:
lib.SetSymfs(self.symfs_dir)
- if self.kallsyms is not None:
+ if self.kallsyms:
lib.SetKallsymsFile(self.kallsyms)
while True:
sample = lib.GetNextSample()
@@ -386,18 +412,20 @@
# Add period to dso.
self._add_dso_period(symbol.dso_name, period, used_dso_dict)
# Add period to source file.
- source = self.addr2line.get_source(symbol.dso_name, symbol.vaddr_in_file)
- if source[0] is not None:
- self._add_file_period(source[0], period, used_file_dict)
- # Add period to line.
- if source[1] is not None:
- self._add_line_period(source, period, used_line_dict)
+ sources = self.addr2line.get_sources(symbol.dso_name, symbol.vaddr_in_file)
+ for source in sources:
+ if source.file:
+ self._add_file_period(source, period, used_file_dict)
+ # Add period to line.
+ if source.line:
+ self._add_line_period(source, period, used_line_dict)
# Add period to function.
- source = self.addr2line.get_source(symbol.dso_name, symbol.symbol_addr)
- if source[0] is not None:
- self._add_file_period(source[0], period, used_file_dict)
- self._add_function_period(source, symbol.symbol_name, period,
- used_function_dict)
+ sources = self.addr2line.get_sources(symbol.dso_name, symbol.symbol_addr)
+ for source in sources:
+ if source.file:
+ self._add_file_period(source, period, used_file_dict)
+ if source.function:
+ self._add_function_period(source, period, used_function_dict)
if is_sample_used:
self.period += sample.period
@@ -412,27 +440,27 @@
dso_period.add_period(period)
- def _add_file_period(self, file, period, used_file_dict):
- if not used_file_dict.has_key(file):
- used_file_dict[file] = True
- file_period = self.file_periods.get(file)
+ def _add_file_period(self, source, period, used_file_dict):
+ if not used_file_dict.has_key(source.file_key):
+ used_file_dict[source.file_key] = True
+ file_period = self.file_periods.get(source.file)
if file_period is None:
- file_period = self.file_periods[file] = FilePeriod(file)
+ file_period = self.file_periods[source.file] = FilePeriod(source.file)
file_period.add_period(period)
def _add_line_period(self, source, period, used_line_dict):
- if not used_line_dict.has_key(source):
- used_line_dict[source] = True
- file_period = self.file_periods[source[0]]
- file_period.add_line_period(source[1], period)
+ if not used_line_dict.has_key(source.line_key):
+ used_line_dict[source.line_key] = True
+ file_period = self.file_periods[source.file]
+ file_period.add_line_period(source.line, period)
- def _add_function_period(self, source, function_name, period, used_function_dict):
- if not used_function_dict.has_key((source[0], function_name)):
- used_function_dict[(source[0], function_name)] = True
- file_period = self.file_periods[source[0]]
- file_period.add_function_period(function_name, source[1], period)
+ def _add_function_period(self, source, period, used_function_dict):
+ if not used_function_dict.has_key(source.function_key):
+ used_function_dict[source.function_key] = True
+ file_period = self.file_periods[source.file]
+ file_period.add_function_period(source.function, source.line, period)
def _write_summary(self):
@@ -461,7 +489,6 @@
values = sorted(values,
cmp=lambda x, y: cmp(y[2].acc_period, x[2].acc_period))
for value in values:
- func = file_period.function_dict[func_name]
f.write('\tfunction (%s): line %d, %s\n' % (
value[0], value[1], self._get_percentage_str(value[2])))
f.write('\n')
@@ -596,4 +623,4 @@
args = parser.parse_args()
config = load_config(args.config)
annotator = SourceFileAnnotator(config)
- annotator.annotate()
\ No newline at end of file
+ annotator.annotate()