diff options
author | Andreas Gampe <agampe@google.com> | 2017-05-17 15:12:27 -0700 |
---|---|---|
committer | Andreas Gampe <agampe@google.com> | 2017-05-18 10:38:30 -0700 |
commit | 46b00d66acf24808d1bf85de50fa9b124a7916e2 (patch) | |
tree | aeed548845976ba6035c89c18099e18cb0906a3b | |
parent | b60fce019dbcca643988ab38e1c86d28f9ce0e6b (diff) | |
download | android_development-46b00d66acf24808d1bf85de50fa9b124a7916e2.tar.gz android_development-46b00d66acf24808d1bf85de50fa9b124a7916e2.tar.bz2 android_development-46b00d66acf24808d1bf85de50fa9b124a7916e2.zip |
Stack: Add subprocess caching
Add subprocess caching to the stack tool. This caches open pipes for
commands, improving symbolization speed for (sets of) stack traces with
duplicated libraries.
Bug: 38226236
Test: m
Test: manual tests
Change-Id: Iadbd74255b9a40c86939be3a1b172275a0b34d54
-rwxr-xr-x | scripts/symbol.py | 84 |
1 files changed, 78 insertions, 6 deletions
diff --git a/scripts/symbol.py b/scripts/symbol.py index ed5b575b0..7531b7d27 100755 --- a/scripts/symbol.py +++ b/scripts/symbol.py @@ -19,10 +19,12 @@ The information can include symbol names, offsets, and source locations. """ +import atexit import glob import os import platform import re +import signal import subprocess import unittest @@ -56,6 +58,78 @@ _SYMBOL_INFORMATION_ADDR2LINE_CACHE = {} _SYMBOL_INFORMATION_OBJDUMP_CACHE = {} _SYMBOL_DEMANGLING_CACHE = {} +# Caches for pipes to subprocesses. + +class ProcessCache: + _cmd2pipe = {} + _lru = [] + + # Max number of open pipes. + _PIPE_MAX_OPEN = 10 + + def GetProcess(self, cmd): + cmd_tuple = tuple(cmd) # Need to use a tuple as lists can't be dict keys. + # Pipe already available? + if cmd_tuple in self._cmd2pipe: + pipe = self._cmd2pipe[cmd_tuple] + # Update LRU. + self._lru = [(cmd_tuple, pipe)] + [i for i in self._lru if i[0] != cmd_tuple] + return pipe + + # Not cached, yet. Open a new one. + + # Check if too many are open, close the old ones. + while len(self._lru) >= self._PIPE_MAX_OPEN: + open_cmd, open_pipe = self._lru.pop() + del self._cmd2pipe[open_cmd] + self.TerminateProcess(open_pipe) + + # Create and put into cache. + pipe = self.SpawnProcess(cmd) + self._cmd2pipe[cmd_tuple] = pipe + self._lru = [(cmd_tuple, pipe)] + self._lru + return pipe + + def SpawnProcess(self, cmd): + return subprocess.Popen(cmd, stdin=subprocess.PIPE, stdout=subprocess.PIPE) + + def TerminateProcess(self, pipe): + pipe.stdin.close() + pipe.stdout.close() + pipe.terminate() + pipe.wait() + + def KillAllProcesses(self): + for _, open_pipe in self._lru: + self.TerminateProcess(open_pipe) + _cmd2pipe = {} + _lru = [] + + +_PIPE_ADDR2LINE_CACHE = ProcessCache() +_PIPE_CPPFILT_CACHE = ProcessCache() + + +# Process cache cleanup on shutdown. + +def CloseAllPipes(): + _PIPE_ADDR2LINE_CACHE.KillAllProcesses() + _PIPE_CPPFILT_CACHE.KillAllProcesses() + + +atexit.register(CloseAllPipes) + + +def PipeTermHandler(signum, frame): + CloseAllPipes() + os._exit(0) + + +for sig in (signal.SIGABRT, signal.SIGINT, signal.SIGTERM): + signal.signal(sig, PipeTermHandler) + + + def ToolPath(tool, toolchain=None): """Return a fully-qualified path to the specified tool""" @@ -222,7 +296,7 @@ def CallAddr2LineForSet(lib, unique_addrs): cmd = [ToolPath("addr2line"), "--functions", "--inlines", "--demangle", "--exe=" + symbols] - child = subprocess.Popen(cmd, stdin=subprocess.PIPE, stdout=subprocess.PIPE) + child = _PIPE_ADDR2LINE_CACHE.GetProcess(cmd) for addr in addrs: child.stdin.write("0x%s\n" % addr) @@ -247,8 +321,6 @@ def CallAddr2LineForSet(lib, unique_addrs): first = False result[addr] = records addr_cache[addr] = records - child.stdin.close() - child.stdout.close() return result @@ -376,12 +448,12 @@ def CallCppFilt(mangled_symbol): return _SYMBOL_DEMANGLING_CACHE[mangled_symbol] cmd = [ToolPath("c++filt")] - process = subprocess.Popen(cmd, stdin=subprocess.PIPE, stdout=subprocess.PIPE) + process = _PIPE_CPPFILT_CACHE.GetProcess(cmd) process.stdin.write(mangled_symbol) process.stdin.write("\n") - process.stdin.close() + process.stdin.flush() + demangled_symbol = process.stdout.readline().strip() - process.stdout.close() _SYMBOL_DEMANGLING_CACHE[mangled_symbol] = demangled_symbol |