Merge "Stack: Add subprocess caching"

This commit is contained in:
Treehugger Robot
2017-05-18 20:47:27 +00:00
committed by Gerrit Code Review

View File

@@ -19,10 +19,12 @@
The information can include symbol names, offsets, and source locations. The information can include symbol names, offsets, and source locations.
""" """
import atexit
import glob import glob
import os import os
import platform import platform
import re import re
import signal
import subprocess import subprocess
import unittest import unittest
@@ -56,6 +58,78 @@ _SYMBOL_INFORMATION_ADDR2LINE_CACHE = {}
_SYMBOL_INFORMATION_OBJDUMP_CACHE = {} _SYMBOL_INFORMATION_OBJDUMP_CACHE = {}
_SYMBOL_DEMANGLING_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): def ToolPath(tool, toolchain=None):
"""Return a fully-qualified path to the specified tool""" """Return a fully-qualified path to the specified tool"""
@@ -222,7 +296,7 @@ def CallAddr2LineForSet(lib, unique_addrs):
cmd = [ToolPath("addr2line"), "--functions", "--inlines", cmd = [ToolPath("addr2line"), "--functions", "--inlines",
"--demangle", "--exe=" + symbols] "--demangle", "--exe=" + symbols]
child = subprocess.Popen(cmd, stdin=subprocess.PIPE, stdout=subprocess.PIPE) child = _PIPE_ADDR2LINE_CACHE.GetProcess(cmd)
for addr in addrs: for addr in addrs:
child.stdin.write("0x%s\n" % addr) child.stdin.write("0x%s\n" % addr)
@@ -247,8 +321,6 @@ def CallAddr2LineForSet(lib, unique_addrs):
first = False first = False
result[addr] = records result[addr] = records
addr_cache[addr] = records addr_cache[addr] = records
child.stdin.close()
child.stdout.close()
return result return result
@@ -376,12 +448,12 @@ def CallCppFilt(mangled_symbol):
return _SYMBOL_DEMANGLING_CACHE[mangled_symbol] return _SYMBOL_DEMANGLING_CACHE[mangled_symbol]
cmd = [ToolPath("c++filt")] 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(mangled_symbol)
process.stdin.write("\n") process.stdin.write("\n")
process.stdin.close() process.stdin.flush()
demangled_symbol = process.stdout.readline().strip() demangled_symbol = process.stdout.readline().strip()
process.stdout.close()
_SYMBOL_DEMANGLING_CACHE[mangled_symbol] = demangled_symbol _SYMBOL_DEMANGLING_CACHE[mangled_symbol] = demangled_symbol