Chromium Code Reviews| Index: tools/deep_memory_profiler/dmprof.py |
| diff --git a/tools/deep_memory_profiler/dmprof.py b/tools/deep_memory_profiler/dmprof.py |
| index 0ac3bf486f05f73ec4f49a3bc73e8c8dbbeaca81..cb445c875823d60a9054859d13e4c9e7f89c6b9d 100644 |
| --- a/tools/deep_memory_profiler/dmprof.py |
| +++ b/tools/deep_memory_profiler/dmprof.py |
| @@ -41,6 +41,7 @@ NULL_REGEX = re.compile('') |
| LOGGER = logging.getLogger('dmprof') |
| POLICIES_JSON_PATH = os.path.join(BASE_PATH, 'policies.json') |
| +CHROME_SRC_PATH = os.path.join(BASE_PATH, os.pardir, os.pardir) |
| # Heap Profile Dump versions |
| @@ -220,11 +221,11 @@ class SymbolDataSources(object): |
| very big. So, the 'dmprof' profiler is designed to use 'SymbolMappingCache' |
| which caches actually used symbols. |
| """ |
| - def __init__(self, prefix, fake_directories=None): |
| + def __init__(self, prefix, alternative_dirs=None): |
| self._prefix = prefix |
| self._prepared_symbol_data_sources_path = None |
| self._loaded_symbol_data_sources = None |
| - self._fake_directories = fake_directories or {} |
| + self._alternative_dirs = alternative_dirs or {} |
| def prepare(self): |
| """Prepares symbol data sources by extracting mapping from a binary. |
| @@ -240,7 +241,7 @@ class SymbolDataSources(object): |
| prepare_symbol_info.prepare_symbol_info( |
| self._prefix + '.maps', |
| output_dir_path=self._prefix + '.symmap', |
| - fake_directories=self._fake_directories, |
| + alternative_dirs=self._alternative_dirs, |
| use_tempdir=True, |
| use_source_file_name=True)) |
| if self._prepared_symbol_data_sources_path: |
| @@ -1050,14 +1051,25 @@ class Command(object): |
| See COMMANDS in main(). |
| """ |
| + _DEVICE_LIB_PATTERN = re.compile(r'(/data/app-lib/.*-[0-9])/.*') |
| + |
| def __init__(self, usage): |
| self._parser = optparse.OptionParser(usage) |
| @staticmethod |
| def load_basic_files( |
| - dump_path, multiple, no_dump=False, fake_directories=None): |
| + dump_path, multiple, no_dump=False, alternative_dirs=None): |
| prefix = Command._find_prefix(dump_path) |
| - symbol_data_sources = SymbolDataSources(prefix, fake_directories or {}) |
| + # Translate the symbol information from the Android device to the |
|
peria
2013/05/15 17:03:21
I'm not sure, but does this method work only for A
Dai Mikurube (NOT FULLTIME)
2013/05/15 22:44:38
This method is called even for Linux (not Android)
|
| + # corresponding files in the host. The location of the files in the host |
| + # is estimated from the binary path on the device. Use --alternative-dirs |
| + # to specify the location manually. |
| + if not alternative_dirs: |
| + alternative_dirs = Command._estimate_alternative_dirs(prefix) |
| + if alternative_dirs: |
| + for device, host in alternative_dirs.iteritems(): |
| + LOGGER.info('Assuming %s on device as %s on host' % (device, host)) |
| + symbol_data_sources = SymbolDataSources(prefix, alternative_dirs) |
| symbol_data_sources.prepare() |
| bucket_set = BucketSet() |
| bucket_set.load(prefix) |
| @@ -1092,6 +1104,35 @@ class Command(object): |
| return re.sub('\.[0-9][0-9][0-9][0-9]\.heap', '', path) |
| @staticmethod |
| + def _estimate_alternative_dirs(prefix): |
| + """Estimates a corresponding host directory for a device-local directory. |
| + |
| + For Android, dmprof.py should find symbol information from the binary in |
| + the host, not in the Android device, because dmprof.py doesn't run on |
| + Android devices. This method estimates the lib directory in the host |
| + corresponding to the directory in the Android device. |
| + |
| + Returns: |
| + A dict that maps a path in the Android device to a path in host. |
| + If a file in "/data/app-lib" found in /proc/maps, it assumes the |
| + process was running on Android. An empty dict unless Android. |
| + """ |
| + device_lib_path_candidates = set() |
| + |
| + with open(prefix + '.maps') as maps_f: |
| + maps = proc_maps.ProcMaps.load(maps_f) |
| + for entry in maps: |
| + matched = Command._DEVICE_LIB_PATTERN.match(entry.as_dict()['name']) |
| + if matched: |
| + device_lib_path_candidates.add(matched.group(1)) |
| + |
| + if len(device_lib_path_candidates) == 1: |
| + return {device_lib_path_candidates.pop(): os.path.join( |
| + CHROME_SRC_PATH, 'out', 'Debug', 'lib')} |
| + else: |
| + return {} |
| + |
| + @staticmethod |
| def _find_all_dumps(dump_path): |
| prefix = Command._find_prefix(dump_path) |
| dump_path_list = [dump_path] |
| @@ -1204,7 +1245,7 @@ class PolicyCommands(Command): |
| 'Usage: %%prog %s [-p POLICY] <first-dump>' % command) |
| self._parser.add_option('-p', '--policy', type='string', dest='policy', |
| help='profile with POLICY', metavar='POLICY') |
| - self._parser.add_option('--fake-directories', dest='fake_directories', |
| + self._parser.add_option('--alternative-dirs', dest='alternative_dirs', |
| metavar='/path/on/target@/path/on/host[:...]', |
| help='Read files in /path/on/host/ instead of ' |
| 'files in /path/on/target/.') |
| @@ -1212,13 +1253,13 @@ class PolicyCommands(Command): |
| def _set_up(self, sys_argv): |
| options, args = self._parse_args(sys_argv, 1) |
| dump_path = args[1] |
| - fake_directories_dict = {} |
| - if options.fake_directories: |
| - for fake_directory_pair in options.fake_directories.split(':'): |
| - target_path, host_path = fake_directory_pair.split('@', 1) |
| - fake_directories_dict[target_path] = host_path |
| + alternative_dirs_dict = {} |
| + if options.alternative_dirs: |
| + for alternative_dir_pair in options.alternative_dirs.split(':'): |
| + target_path, host_path = alternative_dir_pair.split('@', 1) |
| + alternative_dirs_dict[target_path] = host_path |
| (bucket_set, dumps) = Command.load_basic_files( |
| - dump_path, True, fake_directories=fake_directories_dict) |
| + dump_path, True, alternative_dirs=alternative_dirs_dict) |
| policy_set = PolicySet.load(Command._parse_policy_list(options.policy)) |
| return policy_set, dumps, bucket_set |