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

Side by Side 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 unified diff | Download patch | Annotate | Revision Log
« 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 »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
(Empty)
1 # Copyright 2013 The Chromium Authors. All rights reserved.
2 # Use of this source code is governed by a BSD-style license that can be
3 # found in the LICENSE file.
4
5 import logging
6 import os
7 import sys
8
9 _BASE_PATH = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
10 _FIND_RUNTIME_SYMBOLS_PATH = os.path.join(_BASE_PATH,
11 os.pardir,
12 'find_runtime_symbols')
13 sys.path.append(_FIND_RUNTIME_SYMBOLS_PATH)
14
15 import find_runtime_symbols
16 import prepare_symbol_info
17 import proc_maps # pylint: disable=W0611
18
19 LOGGER = logging.getLogger('dmprof')
20
21 FUNCTION_SYMBOLS = find_runtime_symbols.FUNCTION_SYMBOLS
22 SOURCEFILE_SYMBOLS = find_runtime_symbols.SOURCEFILE_SYMBOLS
23 TYPEINFO_SYMBOLS = find_runtime_symbols.TYPEINFO_SYMBOLS
24
25
26 class SymbolDataSources(object):
27 """Manages symbol data sources in a process.
28
29 The symbol data sources consist of maps (/proc/<pid>/maps), nm, readelf and
30 so on. They are collected into a directory '|prefix|.symmap' from the binary
31 files by 'prepare()' with tools/find_runtime_symbols/prepare_symbol_info.py.
32
33 Binaries are not mandatory to profile. The prepared data sources work in
34 place of the binary even if the binary has been overwritten with another
35 binary.
36
37 Note that loading the symbol data sources takes a long time. They are often
38 very big. So, the 'dmprof' profiler is designed to use 'SymbolMappingCache'
39 which caches actually used symbols.
40 """
41 def __init__(self, prefix, alternative_dirs=None):
42 self._prefix = prefix
43 self._prepared_symbol_data_sources_path = None
44 self._loaded_symbol_data_sources = None
45 self._alternative_dirs = alternative_dirs or {}
46
47 def prepare(self):
48 """Prepares symbol data sources by extracting mapping from a binary.
49
50 The prepared symbol data sources are stored in a directory. The directory
51 name is stored in |self._prepared_symbol_data_sources_path|.
52
53 Returns:
54 True if succeeded.
55 """
56 LOGGER.info('Preparing symbol mapping...')
57 self._prepared_symbol_data_sources_path, used_tempdir = (
58 prepare_symbol_info.prepare_symbol_info(
59 self._prefix + '.maps',
60 output_dir_path=self._prefix + '.symmap',
61 alternative_dirs=self._alternative_dirs,
62 use_tempdir=True,
63 use_source_file_name=True))
64 if self._prepared_symbol_data_sources_path:
65 LOGGER.info(' Prepared symbol mapping.')
66 if used_tempdir:
67 LOGGER.warn(' Using a temporary directory for symbol mapping.')
68 LOGGER.warn(' Delete it by yourself.')
69 LOGGER.warn(' Or, move the directory by yourself to use it later.')
70 return True
71 else:
72 LOGGER.warn(' Failed to prepare symbol mapping.')
73 return False
74
75 def get(self):
76 """Returns the prepared symbol data sources.
77
78 Returns:
79 The prepared symbol data sources. None if failed.
80 """
81 if not self._prepared_symbol_data_sources_path and not self.prepare():
82 return None
83 if not self._loaded_symbol_data_sources:
84 LOGGER.info('Loading symbol mapping...')
85 self._loaded_symbol_data_sources = (
86 find_runtime_symbols.RuntimeSymbolsInProcess.load(
87 self._prepared_symbol_data_sources_path))
88 return self._loaded_symbol_data_sources
89
90 def path(self):
91 """Returns the path of the prepared symbol data sources if possible."""
92 if not self._prepared_symbol_data_sources_path and not self.prepare():
93 return None
94 return self._prepared_symbol_data_sources_path
95
96
97 class SymbolFinder(object):
98 """Finds corresponding symbols from addresses.
99
100 This class does only 'find()' symbols from a specified |address_list|.
101 It is introduced to make a finder mockable.
102 """
103 def __init__(self, symbol_type, symbol_data_sources):
104 self._symbol_type = symbol_type
105 self._symbol_data_sources = symbol_data_sources
106
107 def find(self, address_list):
108 return find_runtime_symbols.find_runtime_symbols(
109 self._symbol_type, self._symbol_data_sources.get(), address_list)
110
111
112 class SymbolMappingCache(object):
113 """Caches mapping from actually used addresses to symbols.
114
115 'update()' updates the cache from the original symbol data sources via
116 'SymbolFinder'. Symbols can be looked up by the method 'lookup()'.
117 """
118 def __init__(self):
119 self._symbol_mapping_caches = {
120 FUNCTION_SYMBOLS: {},
121 SOURCEFILE_SYMBOLS: {},
122 TYPEINFO_SYMBOLS: {},
123 }
124
125 def update(self, symbol_type, bucket_set, symbol_finder, cache_f):
126 """Updates symbol mapping cache on memory and in a symbol cache file.
127
128 It reads cached symbol mapping from a symbol cache file |cache_f| if it
129 exists. Unresolved addresses are then resolved and added to the cache
130 both on memory and in the symbol cache file with using 'SymbolFinder'.
131
132 A cache file is formatted as follows:
133 <Address> <Symbol>
134 <Address> <Symbol>
135 <Address> <Symbol>
136 ...
137
138 Args:
139 symbol_type: A type of symbols to update. It should be one of
140 FUNCTION_SYMBOLS, SOURCEFILE_SYMBOLS and TYPEINFO_SYMBOLS.
141 bucket_set: A BucketSet object.
142 symbol_finder: A SymbolFinder object to find symbols.
143 cache_f: A readable and writable IO object of the symbol cache file.
144 """
145 cache_f.seek(0, os.SEEK_SET)
146 self._load(cache_f, symbol_type)
147
148 unresolved_addresses = sorted(
149 address for address in bucket_set.iter_addresses(symbol_type)
150 if address not in self._symbol_mapping_caches[symbol_type])
151
152 if not unresolved_addresses:
153 LOGGER.info('No need to resolve any more addresses.')
154 return
155
156 cache_f.seek(0, os.SEEK_END)
157 LOGGER.info('Loading %d unresolved addresses.' %
158 len(unresolved_addresses))
159 symbol_dict = symbol_finder.find(unresolved_addresses)
160
161 for address, symbol in symbol_dict.iteritems():
162 stripped_symbol = symbol.strip() or '?'
163 self._symbol_mapping_caches[symbol_type][address] = stripped_symbol
164 cache_f.write('%x %s\n' % (address, stripped_symbol))
165
166 def lookup(self, symbol_type, address):
167 """Looks up a symbol for a given |address|.
168
169 Args:
170 symbol_type: A type of symbols to update. It should be one of
171 FUNCTION_SYMBOLS, SOURCEFILE_SYMBOLS and TYPEINFO_SYMBOLS.
172 address: An integer that represents an address.
173
174 Returns:
175 A string that represents a symbol.
176 """
177 return self._symbol_mapping_caches[symbol_type].get(address)
178
179 def _load(self, cache_f, symbol_type):
180 try:
181 for line in cache_f:
182 items = line.rstrip().split(None, 1)
183 if len(items) == 1:
184 items.append('??')
185 self._symbol_mapping_caches[symbol_type][int(items[0], 16)] = items[1]
186 LOGGER.info('Loaded %d entries from symbol cache.' %
187 len(self._symbol_mapping_caches[symbol_type]))
188 except IOError as e:
189 LOGGER.info('The symbol cache file is invalid: %s' % e)
OLDNEW
« 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