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

Side by Side Diff: trace_inputs.py

Issue 12740009: Always accept strace logs to have the last line corrupted. (Closed) Base URL: https://chromium.googlesource.com/chromium/tools/swarm_client.git@master
Patch Set: Created 7 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
« no previous file with comments | « tests/trace_inputs_test.py ('k') | 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
1 #!/usr/bin/env python 1 #!/usr/bin/env python
2 # coding=utf-8 2 # coding=utf-8
3 # Copyright (c) 2012 The Chromium Authors. All rights reserved. 3 # Copyright (c) 2012 The Chromium Authors. All rights reserved.
4 # Use of this source code is governed by a BSD-style license that can be 4 # Use of this source code is governed by a BSD-style license that can be
5 # found in the LICENSE file. 5 # found in the LICENSE file.
6 6
7 """Traces an executable and its child processes and extract the files accessed 7 """Traces an executable and its child processes and extract the files accessed
8 by them. 8 by them.
9 9
10 The implementation uses OS-specific API. The native Kernel logger and the ETL 10 The implementation uses OS-specific API. The native Kernel logger and the ETL
(...skipping 1089 matching lines...) Expand 10 before | Expand all | Expand 10 after
1100 class Process(ApiBase.Context.Process): 1100 class Process(ApiBase.Context.Process):
1101 """Represents the state of a process. 1101 """Represents the state of a process.
1102 1102
1103 Contains all the information retrieved from the pid-specific log. 1103 Contains all the information retrieved from the pid-specific log.
1104 """ 1104 """
1105 # Function names are using ([a-z_0-9]+) 1105 # Function names are using ([a-z_0-9]+)
1106 # This is the most common format. function(args) = result 1106 # This is the most common format. function(args) = result
1107 RE_HEADER = re.compile(r'^([a-z_0-9]+)\((.+?)\)\s+= (.+)$') 1107 RE_HEADER = re.compile(r'^([a-z_0-9]+)\((.+?)\)\s+= (.+)$')
1108 # An interrupted function call, only grab the minimal header. 1108 # An interrupted function call, only grab the minimal header.
1109 RE_UNFINISHED = re.compile(r'^([^\(]+)(.*) \<unfinished \.\.\.\>$') 1109 RE_UNFINISHED = re.compile(r'^([^\(]+)(.*) \<unfinished \.\.\.\>$')
1110 # An interrupted function call, with the process exiting. It must be the
1111 # last line in the log.
1112 RE_UNFINISHED_EXIT = re.compile(
1113 r'^([^\(]+)(.*) \<unfinished \.\.\.\ exit status \d+>$')
1114 # An interrupted function call the hard way. Usually observed with futex()
1115 # on ubuntu 12.04.
1116 RE_INTERRUPTED_HARD = re.compile(r'^([^\(]+)\('
1117 '[A-Z0-9a-z:\,\_\|\{\}\(\)\>\< ]*$')
1118 # A resumed function call. 1110 # A resumed function call.
1119 RE_RESUMED = re.compile(r'^<\.\.\. ([^ ]+) resumed> (.+)$') 1111 RE_RESUMED = re.compile(r'^<\.\.\. ([^ ]+) resumed> (.+)$')
1120 # A process received a signal. 1112 # A process received a signal.
1121 RE_SIGNAL = re.compile(r'^--- SIG[A-Z]+ .+ ---') 1113 RE_SIGNAL = re.compile(r'^--- SIG[A-Z]+ .+ ---')
1122 # A process didn't handle a signal. Ignore any junk appearing before, 1114 # A process didn't handle a signal. Ignore any junk appearing before,
1123 # because the process was forcibly killed so it won't open any new file. 1115 # because the process was forcibly killed so it won't open any new file.
1124 RE_KILLED = re.compile( 1116 RE_KILLED = re.compile(
1125 r'^.*\+\+\+ killed by ([A-Z]+)( \(core dumped\))? \+\+\+$') 1117 r'^.*\+\+\+ killed by ([A-Z]+)( \(core dumped\))? \+\+\+$')
1126 # The process has exited. 1118 # The process has exited.
1127 RE_PROCESS_EXITED = re.compile(r'^\+\+\+ exited with (\d+) \+\+\+') 1119 RE_PROCESS_EXITED = re.compile(r'^\+\+\+ exited with (\d+) \+\+\+')
(...skipping 93 matching lines...) Expand 10 before | Expand all | Expand 10 after
1221 1213
1222 The validity is only guaranteed once all the logs are processed. 1214 The validity is only guaranteed once all the logs are processed.
1223 """ 1215 """
1224 return self.initial_cwd.render() 1216 return self.initial_cwd.render()
1225 1217
1226 def on_line(self, line): 1218 def on_line(self, line):
1227 assert isinstance(line, str) 1219 assert isinstance(line, str)
1228 self._line_number += 1 1220 self._line_number += 1
1229 if self._done: 1221 if self._done:
1230 raise TracingFailure( 1222 raise TracingFailure(
1231 'Found a trace for a terminated process', 1223 'Found a trace for a terminated process or corrupted log',
1232 None, None, None) 1224 None, None, None)
1233 1225
1234 if self.RE_SIGNAL.match(line): 1226 if self.RE_SIGNAL.match(line):
1235 # Ignore signals. 1227 # Ignore signals.
1236 return 1228 return
1237 1229
1238 try: 1230 try:
1239 match = self.RE_KILLED.match(line) 1231 match = self.RE_KILLED.match(line)
1240 if match: 1232 if match:
1241 # Converts a '+++ killed by Foo +++' trace into an exit_group(). 1233 # Converts a '+++ killed by Foo +++' trace into an exit_group().
(...skipping 10 matching lines...) Expand all
1252 if match: 1244 if match:
1253 if match.group(1) in self._pending_calls: 1245 if match.group(1) in self._pending_calls:
1254 raise TracingFailure( 1246 raise TracingFailure(
1255 'Found two unfinished calls for the same function', 1247 'Found two unfinished calls for the same function',
1256 None, None, None, 1248 None, None, None,
1257 self._pending_calls) 1249 self._pending_calls)
1258 self._pending_calls[match.group(1)] = ( 1250 self._pending_calls[match.group(1)] = (
1259 match.group(1) + match.group(2)) 1251 match.group(1) + match.group(2))
1260 return 1252 return
1261 1253
1262 match = (
1263 self.RE_UNFINISHED_EXIT.match(line) or
1264 self.RE_INTERRUPTED_HARD.match(line))
1265 if match:
1266 # The process died. No other line can be processed afterward.
1267 self._done = True
1268 return
1269
1270 match = self.RE_UNAVAILABLE.match(line) 1254 match = self.RE_UNAVAILABLE.match(line)
1271 if match: 1255 if match:
1272 # This usually means a process was killed and a pending call was 1256 # This usually means a process was killed and a pending call was
1273 # canceled. 1257 # canceled.
1274 # TODO(maruel): Look up the last exit_group() trace just above and 1258 # TODO(maruel): Look up the last exit_group() trace just above and
1275 # make sure any self._pending_calls[anything] is properly flushed. 1259 # make sure any self._pending_calls[anything] is properly flushed.
1276 return 1260 return
1277 1261
1278 match = self.RE_RESUMED.match(line) 1262 match = self.RE_RESUMED.match(line)
1279 if match: 1263 if match:
1280 if match.group(1) not in self._pending_calls: 1264 if match.group(1) not in self._pending_calls:
1281 raise TracingFailure( 1265 raise TracingFailure(
1282 'Found a resumed call that was not logged as unfinished', 1266 'Found a resumed call that was not logged as unfinished',
1283 None, None, None, 1267 None, None, None,
1284 self._pending_calls) 1268 self._pending_calls)
1285 pending = self._pending_calls.pop(match.group(1)) 1269 pending = self._pending_calls.pop(match.group(1))
1286 # Reconstruct the line. 1270 # Reconstruct the line.
1287 line = pending + match.group(2) 1271 line = pending + match.group(2)
1288 1272
1289 match = self.RE_HEADER.match(line) 1273 match = self.RE_HEADER.match(line)
1290 if not match: 1274 if not match:
1291 raise TracingFailure( 1275 # The line is corrupted. It happens occasionally when a process is
1292 'Found an invalid line: %s' % line, 1276 # killed forcibly with activity going on. Assume the process died.
1293 None, None, None) 1277 # No other line can be processed afterward.
1278 self._done = True
1279 return
1280
1294 if match.group(1) == self.UNNAMED_FUNCTION: 1281 if match.group(1) == self.UNNAMED_FUNCTION:
1295 return 1282 return
1296 1283
1297 # It's a valid line, handle it. 1284 # It's a valid line, handle it.
1298 handler = getattr(self, 'handle_%s' % match.group(1), None) 1285 handler = getattr(self, 'handle_%s' % match.group(1), None)
1299 if not handler: 1286 if not handler:
1300 self._handle_unknown(match.group(1), match.group(2), match.group(3)) 1287 self._handle_unknown(match.group(1), match.group(2), match.group(3))
1301 return handler(match.group(2), match.group(3)) 1288 return handler(match.group(2), match.group(3))
1302 except TracingFailure, e: 1289 except TracingFailure, e:
1303 # Hack in the values since the handler could be a static function. 1290 # Hack in the values since the handler could be a static function.
(...skipping 2247 matching lines...) Expand 10 before | Expand all | Expand 10 after
3551 main_impl(argv) 3538 main_impl(argv)
3552 except TracingFailure, e: 3539 except TracingFailure, e:
3553 sys.stderr.write('\nError: ') 3540 sys.stderr.write('\nError: ')
3554 sys.stderr.write(str(e)) 3541 sys.stderr.write(str(e))
3555 sys.stderr.write('\n') 3542 sys.stderr.write('\n')
3556 return 1 3543 return 1
3557 3544
3558 3545
3559 if __name__ == '__main__': 3546 if __name__ == '__main__':
3560 sys.exit(main(sys.argv[1:])) 3547 sys.exit(main(sys.argv[1:]))
OLDNEW
« no previous file with comments | « tests/trace_inputs_test.py ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698