Flutter Engine
The Flutter Engine
Public Member Functions | Static Public Member Functions | Public Attributes | Static Public Attributes | List of all members
elf_symbolizer.ELFSymbolizer.Addr2Line Class Reference
Inheritance diagram for elf_symbolizer.ELFSymbolizer.Addr2Line:

Public Member Functions

def __init__ (self, symbolizer)
 
def EnqueueRequest (self, addr, callback_arg)
 
def WaitForIdle (self)
 
def WaitForNextSymbolInQueue (self)
 
def ProcessAllResolvedSymbolsInQueue (self)
 
def RecycleIfNecessary (self)
 
def Terminate (self)
 
def first_request_id (self)
 

Static Public Member Functions

def StdoutReaderThread (process_pipe, queue, inlines)
 

Public Attributes

 queue_size
 

Static Public Attributes

 SYM_ADDR_RE = re.compile(r'([^:]+):(\?|\d+).*')
 

Detailed Description

A python wrapper around an addr2line instance.

The communication with the addr2line process looks as follows:
[STDIN]         [STDOUT]  (from addr2line's viewpoint)
> f001111
> f002222
            < Symbol::Name(foo, bar) for f001111
            < /path/to/source/file.c:line_number
> f003333
            < Symbol::Name2() for f002222
            < /path/to/source/file.c:line_number
            < Symbol::Name3() for f003333
            < /path/to/source/file.c:line_number

Definition at line 207 of file elf_symbolizer.py.

Constructor & Destructor Documentation

◆ __init__()

def elf_symbolizer.ELFSymbolizer.Addr2Line.__init__ (   self,
  symbolizer 
)

Definition at line 225 of file elf_symbolizer.py.

225 def __init__(self, symbolizer):
226 self._symbolizer = symbolizer
227 self._lib_file_name = posixpath.basename(symbolizer.elf_file_path)
228
229 # The request queue (i.e. addresses pushed to addr2line's stdin and not
230 # yet retrieved on stdout)
231 self._request_queue = collections.deque()
232
233 # This is essentially len(self._request_queue). It has been optimized to a
234 # separate field because turned out to be a perf hot-spot.
235 self.queue_size = 0
236
237 # Keep track of the number of symbols a process has processed to
238 # avoid a single process growing too big and using all the memory.
239 self._processed_symbols_count = 0
240
241 # Objects required to handle the addr2line subprocess.
242 self._proc = None # Subprocess.Popen(...) instance.
243 self._thread = None # Threading.thread instance.
244 self._out_queue = None # queue.Queue instance (for buffering a2l stdout).
245 self._RestartAddr2LineProcess()
246

Member Function Documentation

◆ EnqueueRequest()

def elf_symbolizer.ELFSymbolizer.Addr2Line.EnqueueRequest (   self,
  addr,
  callback_arg 
)
Pushes an address to addr2line's stdin (and keeps track of it).

Definition at line 247 of file elf_symbolizer.py.

247 def EnqueueRequest(self, addr, callback_arg):
248 """Pushes an address to addr2line's stdin (and keeps track of it)."""
249 self._symbolizer.requests_counter += 1 # For global "age" of requests.
250 req_idx = self._symbolizer.requests_counter
251 self._request_queue.append((addr, callback_arg, req_idx))
252 self.queue_size += 1
253 self._WriteToA2lStdin(addr)
254
static void append(char **dst, size_t *count, const char *src, size_t n)
Definition: editor.cpp:211

◆ first_request_id()

def elf_symbolizer.ELFSymbolizer.Addr2Line.first_request_id (   self)
Returns the request_id of the oldest pending request in the queue.

Definition at line 464 of file elf_symbolizer.py.

464 def first_request_id(self):
465 """Returns the request_id of the oldest pending request in the queue."""
466 return self._request_queue[0][2] if self._request_queue else 0
467
468

◆ ProcessAllResolvedSymbolsInQueue()

def elf_symbolizer.ELFSymbolizer.Addr2Line.ProcessAllResolvedSymbolsInQueue (   self)
Consumes all the addr2line output lines produced (without blocking).

Definition at line 299 of file elf_symbolizer.py.

299 def ProcessAllResolvedSymbolsInQueue(self):
300 """Consumes all the addr2line output lines produced (without blocking)."""
301 if not self.queue_size:
302 return
303 while True:
304 try:
305 lines = self._out_queue.get_nowait()
306 except queue.Empty:
307 break
308 self._ProcessSymbolOutput(lines)
309

◆ RecycleIfNecessary()

def elf_symbolizer.ELFSymbolizer.Addr2Line.RecycleIfNecessary (   self)
Restarts the process if it has been used for too long.

A long running addr2line process will consume excessive amounts
of memory without any gain in performance.

Definition at line 310 of file elf_symbolizer.py.

310 def RecycleIfNecessary(self):
311 """Restarts the process if it has been used for too long.
312
313 A long running addr2line process will consume excessive amounts
314 of memory without any gain in performance."""
315 if self._processed_symbols_count >= ADDR2LINE_RECYCLE_LIMIT:
316 self._RestartAddr2LineProcess()
317

◆ StdoutReaderThread()

def elf_symbolizer.ELFSymbolizer.Addr2Line.StdoutReaderThread (   process_pipe,
  queue,
  inlines 
)
static
The poller thread fn, which moves the addr2line stdout to the |queue|.

This is the only piece of code not running on the main thread. It merely
writes to a Queue, which is thread-safe. In the case of inlines, it
detects the ??,??:0 marker and sends the lines atomically, such that the
main thread always receives all the lines corresponding to one symbol in
one shot.

Definition at line 433 of file elf_symbolizer.py.

433 def StdoutReaderThread(process_pipe, queue, inlines):
434 """The poller thread fn, which moves the addr2line stdout to the |queue|.
435
436 This is the only piece of code not running on the main thread. It merely
437 writes to a Queue, which is thread-safe. In the case of inlines, it
438 detects the ??,??:0 marker and sends the lines atomically, such that the
439 main thread always receives all the lines corresponding to one symbol in
440 one shot."""
441 try:
442 lines_for_one_symbol = []
443 while True:
444 line1 = process_pipe.readline().decode().rstrip('\r\n')
445 line2 = process_pipe.readline().decode().rstrip('\r\n')
446 if not line1 or not line2:
447 break
448 inline_has_more_lines = inlines and (
449 len(lines_for_one_symbol) == 0 or
450 (line1 != '??' and line2 != '??:0'))
451 if not inlines or inline_has_more_lines:
452 lines_for_one_symbol += [(line1, line2)]
453 if inline_has_more_lines:
454 continue
455 queue.put(lines_for_one_symbol)
456 lines_for_one_symbol = []
457 process_pipe.close()
458
459 # Every addr2line processes will die at some point, please die silently.
460 except (IOError, OSError):
461 pass
462
static DecodeResult decode(std::string path)
Definition: png_codec.cpp:124

◆ Terminate()

def elf_symbolizer.ELFSymbolizer.Addr2Line.Terminate (   self)
Kills the underlying addr2line process.

The poller |_thread| will terminate as well due to the broken pipe.

Definition at line 318 of file elf_symbolizer.py.

318 def Terminate(self):
319 """Kills the underlying addr2line process.
320
321 The poller |_thread| will terminate as well due to the broken pipe."""
322 try:
323 self._proc.kill()
324 self._proc.communicate(
325 ) # Essentially wait() without risking deadlock.
326 except Exception: # An exception while terminating? How interesting.
327 pass
328 self._proc = None
329

◆ WaitForIdle()

def elf_symbolizer.ELFSymbolizer.Addr2Line.WaitForIdle (   self)
Waits until all the pending requests have been symbolized.

Definition at line 255 of file elf_symbolizer.py.

255 def WaitForIdle(self):
256 """Waits until all the pending requests have been symbolized."""
257 while self.queue_size > 0:
258 self.WaitForNextSymbolInQueue()
259

◆ WaitForNextSymbolInQueue()

def elf_symbolizer.ELFSymbolizer.Addr2Line.WaitForNextSymbolInQueue (   self)
Waits for the next pending request to be symbolized.

Definition at line 260 of file elf_symbolizer.py.

260 def WaitForNextSymbolInQueue(self):
261 """Waits for the next pending request to be symbolized."""
262 if not self.queue_size:
263 return
264
265 # This outer loop guards against a2l hanging (detecting stdout timeout).
266 while True:
267 start_time = datetime.datetime.now()
268 timeout = datetime.timedelta(
269 seconds=self._symbolizer.addr2line_timeout)
270
271 # The inner loop guards against a2l crashing (checking if it exited).
272 while (datetime.datetime.now() - start_time < timeout):
273 # poll() returns !None if the process exited. a2l should never exit.
274 if self._proc.poll():
275 logging.warning(
276 'addr2line crashed, respawning (lib: %s).' %
277 self._lib_file_name)
278 self._RestartAddr2LineProcess()
279 # TODO(primiano): the best thing to do in this case would be
280 # shrinking the pool size as, very likely, addr2line is crashed
281 # due to low memory (and the respawned one will die again soon).
282
283 try:
284 lines = self._out_queue.get(block=True, timeout=0.25)
285 except queue.Empty:
286 # On timeout (1/4 s.) repeat the inner loop and check if either the
287 # addr2line process did crash or we waited its output for too long.
288 continue
289
290 # In nominal conditions, we get straight to this point.
291 self._ProcessSymbolOutput(lines)
292 return
293
294 # If this point is reached, we waited more than |addr2line_timeout|.
295 logging.warning('Hung addr2line process, respawning (lib: %s).'
296 % self._lib_file_name)
297 self._RestartAddr2LineProcess()
298
const myers::Point & get(const myers::Segment &)

Member Data Documentation

◆ queue_size

elf_symbolizer.ELFSymbolizer.Addr2Line.queue_size

Definition at line 235 of file elf_symbolizer.py.

◆ SYM_ADDR_RE

elf_symbolizer.ELFSymbolizer.Addr2Line.SYM_ADDR_RE = re.compile(r'([^:]+):(\?|\d+).*')
static

Definition at line 223 of file elf_symbolizer.py.


The documentation for this class was generated from the following file: