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

Side by Side Diff: build/android/pylib/symbols/elf_symbolizer.py

Issue 1948363002: [Android] Remove dedicated presubmit for build/andorid/pylib/symbols/. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Created 4 years, 7 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
OLDNEW
1 # Copyright 2014 The Chromium Authors. All rights reserved. 1 # Copyright 2014 The Chromium Authors. All rights reserved.
2 # Use of this source code is governed by a BSD-style license that can be 2 # Use of this source code is governed by a BSD-style license that can be
3 # found in the LICENSE file. 3 # found in the LICENSE file.
4 4
5 import collections 5 import collections
6 import datetime 6 import datetime
7 import logging 7 import logging
8 import multiprocessing 8 import multiprocessing
9 import os 9 import os
10 import posixpath 10 import posixpath
(...skipping 104 matching lines...) Expand 10 before | Expand all | Expand 10 after
115 min(multiprocessing.cpu_count(), 4)) 115 min(multiprocessing.cpu_count(), 4))
116 self.max_queue_size = max_queue_size 116 self.max_queue_size = max_queue_size
117 self.addr2line_timeout = addr2line_timeout 117 self.addr2line_timeout = addr2line_timeout
118 self.requests_counter = 0 # For generating monotonic request IDs. 118 self.requests_counter = 0 # For generating monotonic request IDs.
119 self._a2l_instances = [] # Up to |max_concurrent_jobs| _Addr2Line inst. 119 self._a2l_instances = [] # Up to |max_concurrent_jobs| _Addr2Line inst.
120 120
121 # If necessary, create disambiguation lookup table 121 # If necessary, create disambiguation lookup table
122 self.disambiguate = source_root_path is not None 122 self.disambiguate = source_root_path is not None
123 self.disambiguation_table = {} 123 self.disambiguation_table = {}
124 self.strip_base_path = strip_base_path 124 self.strip_base_path = strip_base_path
125 if(self.disambiguate): 125 if self.disambiguate:
126 self.source_root_path = os.path.abspath(source_root_path) 126 self.source_root_path = os.path.abspath(source_root_path)
127 self._CreateDisambiguationTable() 127 self._CreateDisambiguationTable()
128 128
129 # Create one addr2line instance. More instances will be created on demand 129 # Create one addr2line instance. More instances will be created on demand
130 # (up to |max_concurrent_jobs|) depending on the rate of the requests. 130 # (up to |max_concurrent_jobs|) depending on the rate of the requests.
131 self._CreateNewA2LInstance() 131 self._CreateNewA2LInstance()
132 132
133 def SymbolizeAsync(self, addr, callback_arg=None): 133 def SymbolizeAsync(self, addr, callback_arg=None):
134 """Requests symbolization of a given address. 134 """Requests symbolization of a given address.
135 135
136 This method is not guaranteed to return immediately. It generally does, but 136 This method is not guaranteed to return immediately. It generally does, but
137 in some scenarios (e.g. all addr2line instances have full queues) it can 137 in some scenarios (e.g. all addr2line instances have full queues) it can
138 block to create back-pressure. 138 block to create back-pressure.
139 139
140 Args: 140 Args:
141 addr: address to symbolize. 141 addr: address to symbolize.
142 callback_arg: optional argument which will be passed to the |callback|.""" 142 callback_arg: optional argument which will be passed to the |callback|."""
143 assert(isinstance(addr, int)) 143 assert isinstance(addr, int)
144 144
145 # Process all the symbols that have been resolved in the meanwhile. 145 # Process all the symbols that have been resolved in the meanwhile.
146 # Essentially, this drains all the addr2line(s) out queues. 146 # Essentially, this drains all the addr2line(s) out queues.
147 for a2l_to_purge in self._a2l_instances: 147 for a2l_to_purge in self._a2l_instances:
148 a2l_to_purge.ProcessAllResolvedSymbolsInQueue() 148 a2l_to_purge.ProcessAllResolvedSymbolsInQueue()
149 a2l_to_purge.RecycleIfNecessary() 149 a2l_to_purge.RecycleIfNecessary()
150 150
151 # Find the best instance according to this logic: 151 # Find the best instance according to this logic:
152 # 1. Find an existing instance with the shortest queue. 152 # 1. Find an existing instance with the shortest queue.
153 # 2. If all of instances' queues are full, but there is room in the pool, 153 # 2. If all of instances' queues are full, but there is room in the pool,
(...skipping 17 matching lines...) Expand all
171 171
172 a2l.EnqueueRequest(addr, callback_arg) 172 a2l.EnqueueRequest(addr, callback_arg)
173 173
174 def Join(self): 174 def Join(self):
175 """Waits for all the outstanding requests to complete and terminates.""" 175 """Waits for all the outstanding requests to complete and terminates."""
176 for a2l in self._a2l_instances: 176 for a2l in self._a2l_instances:
177 a2l.WaitForIdle() 177 a2l.WaitForIdle()
178 a2l.Terminate() 178 a2l.Terminate()
179 179
180 def _CreateNewA2LInstance(self): 180 def _CreateNewA2LInstance(self):
181 assert(len(self._a2l_instances) < self.max_concurrent_jobs) 181 assert len(self._a2l_instances) < self.max_concurrent_jobs
182 a2l = ELFSymbolizer.Addr2Line(self) 182 a2l = ELFSymbolizer.Addr2Line(self)
183 self._a2l_instances.append(a2l) 183 self._a2l_instances.append(a2l)
184 return a2l 184 return a2l
185 185
186 def _CreateDisambiguationTable(self): 186 def _CreateDisambiguationTable(self):
187 """ Non-unique file names will result in None entries""" 187 """ Non-unique file names will result in None entries"""
188 start_time = time.time() 188 start_time = time.time()
189 logging.info('Collecting information about available source files...') 189 logging.info('Collecting information about available source files...')
190 self.disambiguation_table = {} 190 self.disambiguation_table = {}
191 191
(...skipping 63 matching lines...) Expand 10 before | Expand all | Expand 10 after
255 """Waits for the next pending request to be symbolized.""" 255 """Waits for the next pending request to be symbolized."""
256 if not self.queue_size: 256 if not self.queue_size:
257 return 257 return
258 258
259 # This outer loop guards against a2l hanging (detecting stdout timeout). 259 # This outer loop guards against a2l hanging (detecting stdout timeout).
260 while True: 260 while True:
261 start_time = datetime.datetime.now() 261 start_time = datetime.datetime.now()
262 timeout = datetime.timedelta(seconds=self._symbolizer.addr2line_timeout) 262 timeout = datetime.timedelta(seconds=self._symbolizer.addr2line_timeout)
263 263
264 # The inner loop guards against a2l crashing (checking if it exited). 264 # The inner loop guards against a2l crashing (checking if it exited).
265 while (datetime.datetime.now() - start_time < timeout): 265 while datetime.datetime.now() - start_time < timeout:
266 # poll() returns !None if the process exited. a2l should never exit. 266 # poll() returns !None if the process exited. a2l should never exit.
267 if self._proc.poll(): 267 if self._proc.poll():
268 logging.warning('addr2line crashed, respawning (lib: %s).' % 268 logging.warning('addr2line crashed, respawning (lib: %s).',
269 self._lib_file_name) 269 self._lib_file_name)
270 self._RestartAddr2LineProcess() 270 self._RestartAddr2LineProcess()
271 # TODO(primiano): the best thing to do in this case would be 271 # TODO(primiano): the best thing to do in this case would be
272 # shrinking the pool size as, very likely, addr2line is crashed 272 # shrinking the pool size as, very likely, addr2line is crashed
273 # due to low memory (and the respawned one will die again soon). 273 # due to low memory (and the respawned one will die again soon).
274 274
275 try: 275 try:
276 lines = self._out_queue.get(block=True, timeout=0.25) 276 lines = self._out_queue.get(block=True, timeout=0.25)
277 except Queue.Empty: 277 except Queue.Empty:
278 # On timeout (1/4 s.) repeat the inner loop and check if either the 278 # On timeout (1/4 s.) repeat the inner loop and check if either the
279 # addr2line process did crash or we waited its output for too long. 279 # addr2line process did crash or we waited its output for too long.
280 continue 280 continue
281 281
282 # In nominal conditions, we get straight to this point. 282 # In nominal conditions, we get straight to this point.
283 self._ProcessSymbolOutput(lines) 283 self._ProcessSymbolOutput(lines)
284 return 284 return
285 285
286 # If this point is reached, we waited more than |addr2line_timeout|. 286 # If this point is reached, we waited more than |addr2line_timeout|.
287 logging.warning('Hung addr2line process, respawning (lib: %s).' % 287 logging.warning('Hung addr2line process, respawning (lib: %s).',
288 self._lib_file_name) 288 self._lib_file_name)
289 self._RestartAddr2LineProcess() 289 self._RestartAddr2LineProcess()
290 290
291 def ProcessAllResolvedSymbolsInQueue(self): 291 def ProcessAllResolvedSymbolsInQueue(self):
292 """Consumes all the addr2line output lines produced (without blocking).""" 292 """Consumes all the addr2line output lines produced (without blocking)."""
293 if not self.queue_size: 293 if not self.queue_size:
294 return 294 return
295 while True: 295 while True:
296 try: 296 try:
297 lines = self._out_queue.get_nowait() 297 lines = self._out_queue.get_nowait()
(...skipping 10 matching lines...) Expand all
308 self._RestartAddr2LineProcess() 308 self._RestartAddr2LineProcess()
309 309
310 310
311 def Terminate(self): 311 def Terminate(self):
312 """Kills the underlying addr2line process. 312 """Kills the underlying addr2line process.
313 313
314 The poller |_thread| will terminate as well due to the broken pipe.""" 314 The poller |_thread| will terminate as well due to the broken pipe."""
315 try: 315 try:
316 self._proc.kill() 316 self._proc.kill()
317 self._proc.communicate() # Essentially wait() without risking deadlock. 317 self._proc.communicate() # Essentially wait() without risking deadlock.
318 except Exception: # An exception while terminating? How interesting. 318 except Exception: # pylint: disable=broad-except
319 # An exception while terminating? How interesting.
319 pass 320 pass
320 self._proc = None 321 self._proc = None
321 322
322 def _WriteToA2lStdin(self, addr): 323 def _WriteToA2lStdin(self, addr):
323 self._proc.stdin.write('%s\n' % hex(addr)) 324 self._proc.stdin.write('%s\n' % hex(addr))
324 if self._symbolizer.inlines: 325 if self._symbolizer.inlines:
325 # In the case of inlines we output an extra blank line, which causes 326 # In the case of inlines we output an extra blank line, which causes
326 # addr2line to emit a (??,??:0) tuple that we use as a boundary marker. 327 # addr2line to emit a (??,??:0) tuple that we use as a boundary marker.
327 self._proc.stdin.write('\n') 328 self._proc.stdin.write('\n')
328 self._proc.stdin.flush() 329 self._proc.stdin.flush()
(...skipping 10 matching lines...) Expand all
339 name = line1 if not line1.startswith('?') else None 340 name = line1 if not line1.startswith('?') else None
340 source_path = None 341 source_path = None
341 source_line = None 342 source_line = None
342 m = ELFSymbolizer.Addr2Line.SYM_ADDR_RE.match(line2) 343 m = ELFSymbolizer.Addr2Line.SYM_ADDR_RE.match(line2)
343 if m: 344 if m:
344 if not m.group(1).startswith('?'): 345 if not m.group(1).startswith('?'):
345 source_path = m.group(1) 346 source_path = m.group(1)
346 if not m.group(2).startswith('?'): 347 if not m.group(2).startswith('?'):
347 source_line = int(m.group(2)) 348 source_line = int(m.group(2))
348 else: 349 else:
349 logging.warning('Got invalid symbol path from addr2line: %s' % line2) 350 logging.warning('Got invalid symbol path from addr2line: %s', line2)
350 351
351 # In case disambiguation is on, and needed 352 # In case disambiguation is on, and needed
352 was_ambiguous = False 353 was_ambiguous = False
353 disambiguated = False 354 disambiguated = False
354 if self._symbolizer.disambiguate: 355 if self._symbolizer.disambiguate:
355 if source_path and not posixpath.isabs(source_path): 356 if source_path and not posixpath.isabs(source_path):
356 path = self._symbolizer.disambiguation_table.get(source_path) 357 path = self._symbolizer.disambiguation_table.get(source_path)
357 was_ambiguous = True 358 was_ambiguous = True
358 disambiguated = path is not None 359 disambiguated = path is not None
359 source_path = path if disambiguated else source_path 360 source_path = path if disambiguated else source_path
(...skipping 98 matching lines...) Expand 10 before | Expand all | Expand 10 after
458 self.source_line = source_line 459 self.source_line = source_line
459 # In the case of |inlines|=True, the |inlined_by| points to the outer 460 # In the case of |inlines|=True, the |inlined_by| points to the outer
460 # function inlining the current one (and so on, to form a chain). 461 # function inlining the current one (and so on, to form a chain).
461 self.inlined_by = None 462 self.inlined_by = None
462 self.disambiguated = disambiguated 463 self.disambiguated = disambiguated
463 self.was_ambiguous = was_ambiguous 464 self.was_ambiguous = was_ambiguous
464 465
465 def __str__(self): 466 def __str__(self):
466 return '%s [%s:%d]' % ( 467 return '%s [%s:%d]' % (
467 self.name or '??', self.source_path or '??', self.source_line or 0) 468 self.name or '??', self.source_path or '??', self.source_line or 0)
OLDNEW
« no previous file with comments | « build/android/pylib/symbols/PRESUBMIT.py ('k') | build/android/pylib/symbols/elf_symbolizer_unittest.py » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698