Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(32)

Unified Diff: tools/deep_memory_profiler/lib/symbol.py

Issue 19346002: Refactor dmprof: Split dmprof.py into modules. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Created 7 years, 5 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « tools/deep_memory_profiler/lib/subcommand.py ('k') | tools/deep_memory_profiler/range_dict.py » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: tools/deep_memory_profiler/lib/symbol.py
diff --git a/tools/deep_memory_profiler/lib/symbol.py b/tools/deep_memory_profiler/lib/symbol.py
new file mode 100644
index 0000000000000000000000000000000000000000..897d4098d5687630215f3bbc78a0095e3add5ed5
--- /dev/null
+++ b/tools/deep_memory_profiler/lib/symbol.py
@@ -0,0 +1,189 @@
+# Copyright 2013 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+import logging
+import os
+import sys
+
+_BASE_PATH = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
+_FIND_RUNTIME_SYMBOLS_PATH = os.path.join(_BASE_PATH,
+ os.pardir,
+ 'find_runtime_symbols')
+sys.path.append(_FIND_RUNTIME_SYMBOLS_PATH)
+
+import find_runtime_symbols
+import prepare_symbol_info
+import proc_maps # pylint: disable=W0611
+
+LOGGER = logging.getLogger('dmprof')
+
+FUNCTION_SYMBOLS = find_runtime_symbols.FUNCTION_SYMBOLS
+SOURCEFILE_SYMBOLS = find_runtime_symbols.SOURCEFILE_SYMBOLS
+TYPEINFO_SYMBOLS = find_runtime_symbols.TYPEINFO_SYMBOLS
+
+
+class SymbolDataSources(object):
+ """Manages symbol data sources in a process.
+
+ The symbol data sources consist of maps (/proc/<pid>/maps), nm, readelf and
+ so on. They are collected into a directory '|prefix|.symmap' from the binary
+ files by 'prepare()' with tools/find_runtime_symbols/prepare_symbol_info.py.
+
+ Binaries are not mandatory to profile. The prepared data sources work in
+ place of the binary even if the binary has been overwritten with another
+ binary.
+
+ Note that loading the symbol data sources takes a long time. They are often
+ very big. So, the 'dmprof' profiler is designed to use 'SymbolMappingCache'
+ which caches actually used symbols.
+ """
+ def __init__(self, prefix, alternative_dirs=None):
+ self._prefix = prefix
+ self._prepared_symbol_data_sources_path = None
+ self._loaded_symbol_data_sources = None
+ self._alternative_dirs = alternative_dirs or {}
+
+ def prepare(self):
+ """Prepares symbol data sources by extracting mapping from a binary.
+
+ The prepared symbol data sources are stored in a directory. The directory
+ name is stored in |self._prepared_symbol_data_sources_path|.
+
+ Returns:
+ True if succeeded.
+ """
+ LOGGER.info('Preparing symbol mapping...')
+ self._prepared_symbol_data_sources_path, used_tempdir = (
+ prepare_symbol_info.prepare_symbol_info(
+ self._prefix + '.maps',
+ output_dir_path=self._prefix + '.symmap',
+ alternative_dirs=self._alternative_dirs,
+ use_tempdir=True,
+ use_source_file_name=True))
+ if self._prepared_symbol_data_sources_path:
+ LOGGER.info(' Prepared symbol mapping.')
+ if used_tempdir:
+ LOGGER.warn(' Using a temporary directory for symbol mapping.')
+ LOGGER.warn(' Delete it by yourself.')
+ LOGGER.warn(' Or, move the directory by yourself to use it later.')
+ return True
+ else:
+ LOGGER.warn(' Failed to prepare symbol mapping.')
+ return False
+
+ def get(self):
+ """Returns the prepared symbol data sources.
+
+ Returns:
+ The prepared symbol data sources. None if failed.
+ """
+ if not self._prepared_symbol_data_sources_path and not self.prepare():
+ return None
+ if not self._loaded_symbol_data_sources:
+ LOGGER.info('Loading symbol mapping...')
+ self._loaded_symbol_data_sources = (
+ find_runtime_symbols.RuntimeSymbolsInProcess.load(
+ self._prepared_symbol_data_sources_path))
+ return self._loaded_symbol_data_sources
+
+ def path(self):
+ """Returns the path of the prepared symbol data sources if possible."""
+ if not self._prepared_symbol_data_sources_path and not self.prepare():
+ return None
+ return self._prepared_symbol_data_sources_path
+
+
+class SymbolFinder(object):
+ """Finds corresponding symbols from addresses.
+
+ This class does only 'find()' symbols from a specified |address_list|.
+ It is introduced to make a finder mockable.
+ """
+ def __init__(self, symbol_type, symbol_data_sources):
+ self._symbol_type = symbol_type
+ self._symbol_data_sources = symbol_data_sources
+
+ def find(self, address_list):
+ return find_runtime_symbols.find_runtime_symbols(
+ self._symbol_type, self._symbol_data_sources.get(), address_list)
+
+
+class SymbolMappingCache(object):
+ """Caches mapping from actually used addresses to symbols.
+
+ 'update()' updates the cache from the original symbol data sources via
+ 'SymbolFinder'. Symbols can be looked up by the method 'lookup()'.
+ """
+ def __init__(self):
+ self._symbol_mapping_caches = {
+ FUNCTION_SYMBOLS: {},
+ SOURCEFILE_SYMBOLS: {},
+ TYPEINFO_SYMBOLS: {},
+ }
+
+ def update(self, symbol_type, bucket_set, symbol_finder, cache_f):
+ """Updates symbol mapping cache on memory and in a symbol cache file.
+
+ It reads cached symbol mapping from a symbol cache file |cache_f| if it
+ exists. Unresolved addresses are then resolved and added to the cache
+ both on memory and in the symbol cache file with using 'SymbolFinder'.
+
+ A cache file is formatted as follows:
+ <Address> <Symbol>
+ <Address> <Symbol>
+ <Address> <Symbol>
+ ...
+
+ Args:
+ symbol_type: A type of symbols to update. It should be one of
+ FUNCTION_SYMBOLS, SOURCEFILE_SYMBOLS and TYPEINFO_SYMBOLS.
+ bucket_set: A BucketSet object.
+ symbol_finder: A SymbolFinder object to find symbols.
+ cache_f: A readable and writable IO object of the symbol cache file.
+ """
+ cache_f.seek(0, os.SEEK_SET)
+ self._load(cache_f, symbol_type)
+
+ unresolved_addresses = sorted(
+ address for address in bucket_set.iter_addresses(symbol_type)
+ if address not in self._symbol_mapping_caches[symbol_type])
+
+ if not unresolved_addresses:
+ LOGGER.info('No need to resolve any more addresses.')
+ return
+
+ cache_f.seek(0, os.SEEK_END)
+ LOGGER.info('Loading %d unresolved addresses.' %
+ len(unresolved_addresses))
+ symbol_dict = symbol_finder.find(unresolved_addresses)
+
+ for address, symbol in symbol_dict.iteritems():
+ stripped_symbol = symbol.strip() or '?'
+ self._symbol_mapping_caches[symbol_type][address] = stripped_symbol
+ cache_f.write('%x %s\n' % (address, stripped_symbol))
+
+ def lookup(self, symbol_type, address):
+ """Looks up a symbol for a given |address|.
+
+ Args:
+ symbol_type: A type of symbols to update. It should be one of
+ FUNCTION_SYMBOLS, SOURCEFILE_SYMBOLS and TYPEINFO_SYMBOLS.
+ address: An integer that represents an address.
+
+ Returns:
+ A string that represents a symbol.
+ """
+ return self._symbol_mapping_caches[symbol_type].get(address)
+
+ def _load(self, cache_f, symbol_type):
+ try:
+ for line in cache_f:
+ items = line.rstrip().split(None, 1)
+ if len(items) == 1:
+ items.append('??')
+ self._symbol_mapping_caches[symbol_type][int(items[0], 16)] = items[1]
+ LOGGER.info('Loaded %d entries from symbol cache.' %
+ len(self._symbol_mapping_caches[symbol_type]))
+ except IOError as e:
+ LOGGER.info('The symbol cache file is invalid: %s' % e)
« no previous file with comments | « tools/deep_memory_profiler/lib/subcommand.py ('k') | tools/deep_memory_profiler/range_dict.py » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698