summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAndreas Gampe <agampe@google.com>2017-05-17 15:12:27 -0700
committerAndreas Gampe <agampe@google.com>2017-05-18 10:38:30 -0700
commit46b00d66acf24808d1bf85de50fa9b124a7916e2 (patch)
treeaeed548845976ba6035c89c18099e18cb0906a3b
parentb60fce019dbcca643988ab38e1c86d28f9ce0e6b (diff)
downloadandroid_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-xscripts/symbol.py84
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