| Index: build/android/pylib/symbols/elf_symbolizer.py
|
| diff --git a/build/android/pylib/symbols/elf_symbolizer.py b/build/android/pylib/symbols/elf_symbolizer.py
|
| index 90e99e5a2757770b30d8d3a89d0a34b589212780..b294654f20b1ee3c7f0cdb5c142789f3bc1b5933 100644
|
| --- a/build/android/pylib/symbols/elf_symbolizer.py
|
| +++ b/build/android/pylib/symbols/elf_symbolizer.py
|
| @@ -15,6 +15,13 @@ import sys
|
| import threading
|
|
|
|
|
| +# addr2line builds a possibly infinite memory cache that can exhaust
|
| +# the computer's memory if allowed to grow for too long. This constant
|
| +# controls how many lookups we do before restarting the process. 4000
|
| +# gives near peak performance without extreme memory usage.
|
| +ADDR2LINE_RECYCLE_LIMIT = 4000
|
| +
|
| +
|
| class ELFSymbolizer(object):
|
| """An uber-fast (multiprocessing, pipelined and asynchronous) ELF symbolizer.
|
|
|
| @@ -117,6 +124,7 @@ class ELFSymbolizer(object):
|
| # Essentially, this drains all the addr2line(s) out queues.
|
| for a2l_to_purge in self._a2l_instances:
|
| a2l_to_purge.ProcessAllResolvedSymbolsInQueue()
|
| + a2l_to_purge.RecycleIfNecessary()
|
|
|
| # Find the best instance according to this logic:
|
| # 1. Find an existing instance with the shortest queue.
|
| @@ -184,6 +192,10 @@ class ELFSymbolizer(object):
|
| # separate field because turned out to be a perf hot-spot.
|
| self.queue_size = 0
|
|
|
| + # Keep track of the number of symbols a process has processed to
|
| + # avoid a single process growing too big and using all the memory.
|
| + self._processed_symbols_count = 0
|
| +
|
| # Objects required to handle the addr2line subprocess.
|
| self._proc = None # Subprocess.Popen(...) instance.
|
| self._thread = None # Threading.thread instance.
|
| @@ -251,6 +263,15 @@ class ELFSymbolizer(object):
|
| break
|
| self._ProcessSymbolOutput(lines)
|
|
|
| + def 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."""
|
| + if self._processed_symbols_count >= ADDR2LINE_RECYCLE_LIMIT:
|
| + self._RestartAddr2LineProcess()
|
| +
|
| +
|
| def Terminate(self):
|
| """Kills the underlying addr2line process.
|
|
|
| @@ -297,6 +318,7 @@ class ELFSymbolizer(object):
|
| if not innermost_sym_info:
|
| innermost_sym_info = sym_info
|
|
|
| + self._processed_symbols_count += 1
|
| self._symbolizer.callback(innermost_sym_info, callback_arg)
|
|
|
| def _RestartAddr2LineProcess(self):
|
| @@ -325,6 +347,8 @@ class ELFSymbolizer(object):
|
| self._thread.daemon = True # Don't prevent early process exit.
|
| self._thread.start()
|
|
|
| + self._processed_symbols_count = 0
|
| +
|
| # Replay the pending requests on the new process (only for the case
|
| # of a hung addr2line timing out during the game).
|
| for (addr, _, _) in self._request_queue:
|
|
|