summaryrefslogtreecommitdiff
path: root/simpleperf/scripts/binary_cache_builder.py
diff options
context:
space:
mode:
Diffstat (limited to 'simpleperf/scripts/binary_cache_builder.py')
-rwxr-xr-xsimpleperf/scripts/binary_cache_builder.py78
1 files changed, 34 insertions, 44 deletions
diff --git a/simpleperf/scripts/binary_cache_builder.py b/simpleperf/scripts/binary_cache_builder.py
index 1f4041f8..6151d16f 100755
--- a/simpleperf/scripts/binary_cache_builder.py
+++ b/simpleperf/scripts/binary_cache_builder.py
@@ -26,47 +26,36 @@ import os.path
import shutil
from simpleperf_report_lib import ReportLib
-from utils import AdbHelper, flatten_arg_list, log_info, log_warning, log_exit, ReadElf
+from utils import AdbHelper, extant_dir, extant_file, flatten_arg_list, log_info, log_warning
+from utils import ReadElf
def is_jit_symfile(dso_name):
return dso_name.split('/')[-1].startswith('TemporaryFile')
class BinaryCacheBuilder(object):
"""Collect all binaries needed by perf.data in binary_cache."""
- def __init__(self, config):
- config_names = ['perf_data_path', 'symfs_dirs', 'ndk_path']
- for name in config_names:
- if name not in config:
- log_exit('config for "%s" is missing' % name)
-
- self.perf_data_path = config.get('perf_data_path')
- if not os.path.isfile(self.perf_data_path):
- log_exit("can't find file %s" % self.perf_data_path)
- self.symfs_dirs = config.get('symfs_dirs')
- for symfs_dir in self.symfs_dirs:
- if not os.path.isdir(symfs_dir):
- log_exit("symfs_dir '%s' is not a directory" % symfs_dir)
- self.adb = AdbHelper(enable_switch_to_root=not config['disable_adb_root'])
- self.readelf = ReadElf(config.get('ndk_path'))
+ def __init__(self, ndk_path, disable_adb_root):
+ self.adb = AdbHelper(enable_switch_to_root=not disable_adb_root)
+ self.readelf = ReadElf(ndk_path)
self.binary_cache_dir = 'binary_cache'
if not os.path.isdir(self.binary_cache_dir):
os.makedirs(self.binary_cache_dir)
self.binaries = {}
- def build_binary_cache(self):
- self._collect_used_binaries()
- self._copy_binaries_from_symfs_dirs()
+ def build_binary_cache(self, perf_data_path, symfs_dirs):
+ self._collect_used_binaries(perf_data_path)
+ self.copy_binaries_from_symfs_dirs(symfs_dirs)
self._pull_binaries_from_device()
self._pull_kernel_symbols()
- def _collect_used_binaries(self):
+ def _collect_used_binaries(self, perf_data_path):
"""read perf.data, collect all used binaries and their build id (if available)."""
# A dict mapping from binary name to build_id
binaries = {}
lib = ReportLib()
- lib.SetRecordFile(self.perf_data_path)
+ lib.SetRecordFile(perf_data_path)
lib.SetLogSeverity('error')
while True:
sample = lib.GetNextSample()
@@ -87,9 +76,9 @@ class BinaryCacheBuilder(object):
self.binaries = binaries
- def _copy_binaries_from_symfs_dirs(self):
+ def copy_binaries_from_symfs_dirs(self, symfs_dirs):
"""collect all files in symfs_dirs."""
- if not self.symfs_dirs:
+ if not symfs_dirs:
return
# It is possible that the path of the binary in symfs_dirs doesn't match
@@ -110,7 +99,7 @@ class BinaryCacheBuilder(object):
paths.append(binary)
# Walk through all files in symfs_dirs, and copy matching files to build_cache.
- for symfs_dir in self.symfs_dirs:
+ for symfs_dir in symfs_dirs:
for root, _, files in os.walk(symfs_dir):
for filename in files:
paths = filename_dict.get(filename)
@@ -132,7 +121,7 @@ class BinaryCacheBuilder(object):
target_file = target_file[1:]
target_file = target_file.replace('/', os.sep)
target_file = os.path.join(self.binary_cache_dir, target_file)
- if not self._need_to_copy(target_file, expected_build_id):
+ if not self._need_to_copy(from_path, target_file, expected_build_id):
# The existing file in binary_cache can provide more information, so no need to copy.
return
target_dir = os.path.dirname(target_file)
@@ -142,14 +131,23 @@ class BinaryCacheBuilder(object):
shutil.copy(from_path, target_file)
- def _need_to_copy(self, target_file, expected_build_id):
+ def _need_to_copy(self, source_file, target_file, expected_build_id):
if not os.path.isfile(target_file):
return True
if self._read_build_id(target_file) != expected_build_id:
return True
- if not self._file_has_symbol_table(target_file):
- return True
- return False
+ return self._get_file_stripped_level(source_file) < self._get_file_stripped_level(
+ target_file)
+
+
+ def _get_file_stripped_level(self, file_path):
+ """Return stripped level of an ELF file. Larger value means more stripped."""
+ sections = self.readelf.get_sections(file_path)
+ if '.debug_line' in sections:
+ return 0
+ if '.symtab' in sections:
+ return 1
+ return 2
def _pull_binaries_from_device(self):
@@ -192,11 +190,6 @@ class BinaryCacheBuilder(object):
return self.readelf.get_build_id(file_path)
- def _file_has_symbol_table(self, file_path):
- """Test if an elf file has symbol table section."""
- return '.symtab' in self.readelf.get_sections(file_path)
-
-
def _pull_file_from_device(self, device_path, host_path):
if self.adb.run(['pull', device_path, host_path]):
return True
@@ -223,22 +216,19 @@ class BinaryCacheBuilder(object):
def main():
parser = argparse.ArgumentParser(description="""
Pull binaries needed by perf.data from device to binary_cache directory.""")
- parser.add_argument('-i', '--perf_data_path', default='perf.data', help="""
+ parser.add_argument('-i', '--perf_data_path', default='perf.data', type=extant_file, help="""
The path of profiling data.""")
- parser.add_argument('-lib', '--native_lib_dir', nargs='+', help="""
+ parser.add_argument('-lib', '--native_lib_dir', type=extant_dir, nargs='+', help="""
Path to find debug version of native shared libraries used in the app.""", action='append')
parser.add_argument('--disable_adb_root', action='store_true', help="""
Force adb to run in non root mode.""")
parser.add_argument('--ndk_path', nargs=1, help='Find tools in the ndk path.')
args = parser.parse_args()
- config = {}
- config['perf_data_path'] = args.perf_data_path
- config['symfs_dirs'] = flatten_arg_list(args.native_lib_dir)
- config['disable_adb_root'] = args.disable_adb_root
- config['ndk_path'] = None if not args.ndk_path else args.ndk_path[0]
-
- builder = BinaryCacheBuilder(config)
- builder.build_binary_cache()
+
+ ndk_path = None if not args.ndk_path else args.ndk_path[0]
+ builder = BinaryCacheBuilder(ndk_path, args.disable_adb_root)
+ symfs_dirs = flatten_arg_list(args.native_lib_dir)
+ builder.build_binary_cache(args.perf_data_path, symfs_dirs)
if __name__ == '__main__':