Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(650)

Side by Side Diff: tools/isolate/strace_inputs.py

Issue 9689025: Add strace_inputs.py to strace a test executable and detect its dependencies. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Created 8 years, 9 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « no previous file | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
(Empty)
1 #!/usr/bin/env python
2 # Copyright (c) 2012 The Chromium Authors. All rights reserved.
3 # Use of this source code is governed by a BSD-style license that can be
4 # found in the LICENSE file.
5
6 """Runs strace on a test and processes the logs to extract the dependencies from
7 the source tree.
8
9 Automatically extracts directories where all the files are used to make the
10 dependencies list more compact.
11 """
12
13 import os
14 import re
15 import subprocess
16 import sys
17
18
19 BASE_DIR = os.path.dirname(os.path.abspath(__file__))
20 ROOT_DIR = os.path.dirname(os.path.dirname(BASE_DIR))
21
22 IGNORED = (
23 '/dev',
24 '/etc',
25 '/home',
26 '/lib',
27 '/proc',
28 '/sys',
29 '/tmp',
30 '/usr',
31 '/var',
32 )
33
34
35 def gen_trace(cmd, cwd, logname, silent):
36 """Runs strace on an executable."""
37 strace = ['strace', '-f', '-e', 'trace=open', '-o', logname]
38 stdout = stderr = None
39 if silent:
40 stdout = subprocess.PIPE
41 stderr = subprocess.PIPE
42
43 cmd = [os.path.normpath(os.path.join(cwd, c)) for c in cmd]
44 p = subprocess.Popen(
45 strace + cmd, cwd=cwd, stdout=stdout, stderr=stderr)
46 out, err = p.communicate()
47 if p.returncode != 0:
48 print 'Failure: %d' % p.returncode
49 # pylint: disable=E1103
50 print ''.join(out.splitlines(True)[-100:])
51 print ''.join(err.splitlines(True)[-100:])
52 return p.returncode
53
54
55 def parse_log(filename, blacklist):
56 """Processes a strace log and returns the files opened and the files that do
57 not exist.
58
59 Most of the time, files that do not exist are temporary test files that should
60 be put in /tmp instead. See http://crbug.com/116251
61
62 TODO(maruel): Process chdir() calls so relative paths can be processed.
63 """
64 files = set()
65 non_existent = set()
66 for line in open(filename):
67 # 1=pid, 2=filepath, 3=mode, 4=result
68 m = re.match(r'^(\d+)\s+open\("([^"]+)", ([^\)]+)\)\s+= (.+)$', line)
69 if not m:
70 continue
71 if m.group(4).startswith('-1') or 'O_DIRECTORY' in m.group(3):
72 # Not present or a directory.
73 continue
74 filepath = m.group(2)
75 if blacklist(filepath):
76 continue
77 if not os.path.isfile(filepath):
78 non_existent.add(filepath)
79 else:
80 files.add(filepath)
81 return files, non_existent
82
83
84 def relevant_files(files, root):
85 """Trims the list of files to keep the expected files and unexpected files.
86
87 Unexpected files are files that are not based inside the |root| directory.
88 """
89 expected = []
90 unexpected = []
91 for f in files:
92 if f.startswith(root):
93 expected.append(f[len(root):])
94 else:
95 unexpected.append(f)
96 return sorted(set(expected)), sorted(set(unexpected))
97
98
99 def extract_directories(files, root):
100 """Detects if all the files in a directory were loaded and if so, replace the
101 individual files by the directory entry.
102 """
103 directories = set(os.path.dirname(f) for f in files)
104 files = set(files)
105 for directory in sorted(directories, reverse=True):
106 actual = set(
107 os.path.join(directory, f) for f in
108 os.listdir(os.path.join(root, directory))
109 if not f.endswith(('.svn', '.pyc'))
110 )
111 if not (actual - files):
112 files -= actual
113 files.add(directory + '/')
114 return sorted(files)
115
116
117 def strace_inputs(unittest, cmd):
118 """Tries to load the logs if available. If not, strace the test."""
119 logname = os.path.join(BASE_DIR, os.path.basename(unittest))
120 if not os.path.isfile(logname):
121 returncode = gen_trace(cmd, ROOT_DIR, logname, True)
122 if returncode:
123 return returncode
124
125 def blacklist(f):
126 """Strips ignored paths."""
127 return f.startswith(IGNORED) or f.endswith('.pyc')
128
129 files, non_existent = parse_log(logname, blacklist)
130 print('Total: %d' % len(files))
131 print('Non existent: %d' % len(non_existent))
132 for f in non_existent:
133 print(' %s' % f)
134
135 expected, unexpected = relevant_files(files, ROOT_DIR + '/')
136 if unexpected:
137 print('Unexpected: %d' % len(unexpected))
138 for f in unexpected:
139 print(' %s' % f)
140
141 simplified = extract_directories(expected, ROOT_DIR)
142 print('Interesting: %d reduced to %d' % (len(expected), len(simplified)))
143 for f in simplified:
144 print(' %s' % f)
145
146 return 0
147
148
149 def main():
150 if len(sys.argv) < 3:
151 print >> sys.stderr, (
152 'Usage: strace_inputs.py [testname] [cmd line...]\n'
153 '\n'
154 'Example:\n'
155 ' ./strace_inputs.py base_unittests testing/xvfb.py out/Release '
156 'out/Release/base_unittests')
157 return 1
158 return strace_inputs(sys.argv[1], sys.argv[2:])
159
160
161 if __name__ == '__main__':
162 sys.exit(main())
OLDNEW
« no previous file with comments | « no previous file | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698