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

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

Issue 10541064: Add Strace parallel support. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Remove maxDiff Created 8 years, 6 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 | tools/isolate/trace_inputs_smoke_test.py » ('j') | 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 11 matching lines...) Expand all
22 import csv 22 import csv
23 import getpass 23 import getpass
24 import glob 24 import glob
25 import json 25 import json
26 import logging 26 import logging
27 import optparse 27 import optparse
28 import os 28 import os
29 import re 29 import re
30 import subprocess 30 import subprocess
31 import sys 31 import sys
32 import threading
32 import weakref 33 import weakref
33 34
34 ## OS-specific imports 35 ## OS-specific imports
35 36
36 if sys.platform == 'win32': 37 if sys.platform == 'win32':
37 from ctypes.wintypes import byref, create_unicode_buffer, c_int, c_wchar_p 38 from ctypes.wintypes import byref, create_unicode_buffer, c_int, c_wchar_p
38 from ctypes.wintypes import windll, FormatError # pylint: disable=E0611 39 from ctypes.wintypes import windll, FormatError # pylint: disable=E0611
39 from ctypes.wintypes import GetLastError # pylint: disable=E0611 40 from ctypes.wintypes import GetLastError # pylint: disable=E0611
40 elif sys.platform == 'darwin': 41 elif sys.platform == 'darwin':
41 import Carbon.File # pylint: disable=F0401 42 import Carbon.File # pylint: disable=F0401
(...skipping 567 matching lines...) Expand 10 before | Expand all | Expand 10 after
609 self.files.add(filepath) 610 self.files.add(filepath)
610 611
611 def __init__(self, blacklist): 612 def __init__(self, blacklist):
612 self.blacklist = blacklist 613 self.blacklist = blacklist
613 self.processes = {} 614 self.processes = {}
614 615
615 class Tracer(object): 616 class Tracer(object):
616 """During it's lifetime, the tracing subsystem is enabled.""" 617 """During it's lifetime, the tracing subsystem is enabled."""
617 def __init__(self, logname): 618 def __init__(self, logname):
618 self._logname = logname 619 self._logname = logname
620 self._lock = threading.Lock()
621 self._traces = []
619 self._initialized = True 622 self._initialized = True
620 623
621 def trace(self, cmd, cwd, tracename, output): 624 def trace(self, cmd, cwd, tracename, output):
622 """Runs the OS-specific trace program on an executable. 625 """Runs the OS-specific trace program on an executable.
623 626
624 Arguments: 627 Arguments:
625 - cmd: The command (a list) to run. 628 - cmd: The command (a list) to run.
626 - cwd: Current directory to start the child process in. 629 - cwd: Current directory to start the child process in.
627 - tracename: Name of the trace in the logname file. 630 - tracename: Name of the trace in the logname file.
628 - output: If False, redirects output to PIPEs. 631 - output: If False, redirects output to PIPEs.
629 632
630 Returns a tuple (resultcode, output) and updates the internal trace 633 Returns a tuple (resultcode, output) and updates the internal trace
631 entries. 634 entries.
632 """ 635 """
636 # The implementation adds an item to self._traces.
633 raise NotImplementedError(self.__class__.__name__) 637 raise NotImplementedError(self.__class__.__name__)
634 638
635 def close(self): 639 def close(self, _timeout=None):
636 self._initialized = False 640 """Saves the meta-data in the logname file.
641
642 For kernel-based tracing, stops the tracing subsystem.
643
644 Must not be used manually when using 'with' construct.
645 """
646 with self._lock:
647 assert self._initialized
648 try:
649 data = {
650 'traces': self._traces,
651 }
652 write_json(self._logname, data, False)
653 finally:
654 self._initialized = False
637 655
638 def post_process_log(self): 656 def post_process_log(self):
639 """Post-processes the log so it becomes faster to load afterward. 657 """Post-processes the log so it becomes faster to load afterward.
640 658
641 Must not be used manually when using 'with' construct. 659 Must not be used manually when using 'with' construct.
642 """ 660 """
643 assert not self._initialized, 'Must stop tracing first.' 661 assert not self._initialized, 'Must stop tracing first.'
644 662
645 def __enter__(self): 663 def __enter__(self):
646 """Enables 'with' statement.""" 664 """Enables 'with' statement."""
(...skipping 12 matching lines...) Expand all
659 Initializes the tracing subsystem, which is a requirement for kernel-based 677 Initializes the tracing subsystem, which is a requirement for kernel-based
660 tracers. Only one tracer instance should be live at a time! 678 tracers. Only one tracer instance should be live at a time!
661 679
662 logname is the filepath to the json file that will contain the meta-data 680 logname is the filepath to the json file that will contain the meta-data
663 about the logs. 681 about the logs.
664 """ 682 """
665 return self.Tracer(logname) 683 return self.Tracer(logname)
666 684
667 @staticmethod 685 @staticmethod
668 def clean_trace(logname): 686 def clean_trace(logname):
669 """Deletes the old log.""" 687 """Deletes an old log."""
670 raise NotImplementedError() 688 raise NotImplementedError()
671 689
672 @classmethod 690 @classmethod
673 def parse_log(cls, logname, blacklist): 691 def parse_log(cls, logname, blacklist):
674 """Processes a trace log and returns the files opened and the files that do 692 """Processes trace logs and returns the files opened and the files that do
675 not exist. 693 not exist.
676 694
677 It does not track directories. 695 It does not track directories.
678 696
679 Most of the time, files that do not exist are temporary test files that 697 Most of the time, files that do not exist are temporary test files that
680 should be put in /tmp instead. See http://crbug.com/116251. 698 should be put in /tmp instead. See http://crbug.com/116251.
681 699
682 Returns a tuple (existing files, non existing files, nb_processes_created) 700 Returns a list of dict with keys:
701 - results: A Results instance.
702 - trace: The corresponding tracename parameter provided to
703 get_tracer().trace().
704 - output: Output gathered during execution, if get_tracer().trace(...,
705 output=False) was used.
683 """ 706 """
684 raise NotImplementedError(cls.__class__.__name__) 707 raise NotImplementedError(cls.__class__.__name__)
685 708
686 709
687 class Strace(ApiBase): 710 class Strace(ApiBase):
688 """strace implies linux.""" 711 """strace implies linux."""
689 IGNORED = ( 712 IGNORED = (
690 '/bin', 713 '/bin',
691 '/dev', 714 '/dev',
692 '/etc', 715 '/etc',
(...skipping 301 matching lines...) Expand 10 before | Expand all | Expand 10 after
994 """Returns the list of all handled traces to pass this as an argument to 1017 """Returns the list of all handled traces to pass this as an argument to
995 strace. 1018 strace.
996 """ 1019 """
997 prefix = 'handle_' 1020 prefix = 'handle_'
998 return [i[len(prefix):] for i in dir(cls.Process) if i.startswith(prefix)] 1021 return [i[len(prefix):] for i in dir(cls.Process) if i.startswith(prefix)]
999 1022
1000 class Tracer(ApiBase.Tracer): 1023 class Tracer(ApiBase.Tracer):
1001 def trace(self, cmd, cwd, tracename, output): 1024 def trace(self, cmd, cwd, tracename, output):
1002 """Runs strace on an executable.""" 1025 """Runs strace on an executable."""
1003 logging.info('trace(%s, %s, %s, %s)' % (cmd, cwd, tracename, output)) 1026 logging.info('trace(%s, %s, %s, %s)' % (cmd, cwd, tracename, output))
1027 with self._lock:
1028 if not self._initialized:
1029 raise TracingFailure(
1030 'Called Tracer.trace() on an unitialized object',
1031 None, None, None, tracename)
1032 assert tracename not in (i['trace'] for i in self._traces)
1004 stdout = stderr = None 1033 stdout = stderr = None
1005 if output: 1034 if output:
1006 stdout = subprocess.PIPE 1035 stdout = subprocess.PIPE
1007 stderr = subprocess.STDOUT 1036 stderr = subprocess.STDOUT
1008 traces = ','.join(Strace.Context.traces()) 1037 traces = ','.join(Strace.Context.traces())
1009 trace_cmd = [ 1038 trace_cmd = [
1010 'strace', 1039 'strace',
1011 '-ff', 1040 '-ff',
1012 '-s', '256', 1041 '-s', '256',
1013 '-e', 'trace=%s' % traces, 1042 '-e', 'trace=%s' % traces,
1014 '-o', self._logname, 1043 '-o', self._logname + '.' + tracename,
1015 ] 1044 ]
1016 child = subprocess.Popen( 1045 child = subprocess.Popen(
1017 trace_cmd + cmd, 1046 trace_cmd + cmd,
1018 cwd=cwd, 1047 cwd=cwd,
1019 stdin=subprocess.PIPE, 1048 stdin=subprocess.PIPE,
1020 stdout=stdout, 1049 stdout=stdout,
1021 stderr=stderr) 1050 stderr=stderr)
1022 out = child.communicate()[0] 1051 out = child.communicate()[0]
1023 # Once it's done, write metadata into the log file to be able to follow 1052 # TODO(maruel): Walk the logs and figure out the root process would
1024 # the pid files. 1053 # simplify parsing the logs a *lot*.
1025 value = { 1054 with self._lock:
1026 'cwd': cwd, 1055 assert tracename not in (i['trace'] for i in self._traces)
1027 # The pid of strace process, not very useful. 1056 self._traces.append(
1028 'pid': child.pid, 1057 {
1029 } 1058 'cmd': cmd,
1030 write_json(self._logname, value, False) 1059 'cwd': cwd,
1060 # The pid of strace process, not very useful.
1061 'pid': child.pid,
1062 'trace': tracename,
1063 'output': out,
1064 })
1031 return child.returncode, out 1065 return child.returncode, out
1032 1066
1033 @staticmethod 1067 @staticmethod
1034 def clean_trace(logname): 1068 def clean_trace(logname):
1035 if os.path.isfile(logname): 1069 if os.path.isfile(logname):
1036 os.remove(logname) 1070 os.remove(logname)
1037 # Also delete any pid specific file from previous traces. 1071 # Also delete any pid specific file from previous traces.
1038 for i in glob.iglob(logname + '.*'): 1072 for i in glob.iglob(logname + '.*'):
1039 if i.rsplit('.', 1)[1].isdigit(): 1073 if i.rsplit('.', 1)[1].isdigit():
1040 os.remove(i) 1074 os.remove(i)
1041 1075
1042 @classmethod 1076 @classmethod
1043 def parse_log(cls, logname, blacklist): 1077 def parse_log(cls, logname, blacklist):
1044 logging.info('parse_log(%s, %s)' % (logname, blacklist)) 1078 logging.info('parse_log(%s, %s)' % (logname, blacklist))
1045 data = read_json(logname) 1079 data = read_json(logname)
1046 context = cls.Context(blacklist, data['cwd']) 1080 out = []
1047 for pidfile in glob.iglob(logname + '.*'): 1081 for item in data['traces']:
1048 pid = pidfile.rsplit('.', 1)[1] 1082 result = {
1049 if pid.isdigit(): 1083 'trace': item['trace'],
1050 pid = int(pid) 1084 'output': item['output'],
1051 # TODO(maruel): Load as utf-8 1085 }
1052 for line in open(pidfile, 'rb'): 1086 try:
1053 context.on_line(pid, line) 1087 context = cls.Context(blacklist, item['cwd'])
1054 1088 for pidfile in glob.iglob('%s.%s.*' % (logname, item['trace'])):
1055 return context.to_results() 1089 pid = pidfile.rsplit('.', 1)[1]
1090 if pid.isdigit():
1091 pid = int(pid)
1092 # TODO(maruel): Load as utf-8
1093 for line in open(pidfile, 'rb'):
1094 context.on_line(pid, line)
1095 result['results'] = context.to_results()
1096 except TracingFailure, e:
1097 result['exception'] = e
1098 out.append(result)
1099 return out
1056 1100
1057 1101
1058 class Dtrace(ApiBase): 1102 class Dtrace(ApiBase):
1059 """Uses DTrace framework through dtrace. Requires root access. 1103 """Uses DTrace framework through dtrace. Requires root access.
1060 1104
1061 Implies Mac OSX. 1105 Implies Mac OSX.
1062 1106
1063 dtruss can't be used because it has compatibility issues with python. 1107 dtruss can't be used because it has compatibility issues with python.
1064 1108
1065 Also, the pid->cwd handling needs to be done manually since OSX has no way to 1109 Also, the pid->cwd handling needs to be done manually since OSX has no way to
(...skipping 542 matching lines...) Expand 10 before | Expand all | Expand 10 after
1608 1652
1609 This dtruss is broken when it starts the process itself or when tracing 1653 This dtruss is broken when it starts the process itself or when tracing
1610 child processes, this code starts a wrapper process 1654 child processes, this code starts a wrapper process
1611 trace_child_process.py, which waits for dtrace to start, then 1655 trace_child_process.py, which waits for dtrace to start, then
1612 trace_child_process.py starts the executable to trace. 1656 trace_child_process.py starts the executable to trace.
1613 """ 1657 """
1614 logging.info('trace(%s, %s, %s, %s)' % (cmd, cwd, tracename, output)) 1658 logging.info('trace(%s, %s, %s, %s)' % (cmd, cwd, tracename, output))
1615 logging.info('Running: %s' % cmd) 1659 logging.info('Running: %s' % cmd)
1616 signal = 'Go!' 1660 signal = 'Go!'
1617 logging.debug('Our pid: %d' % os.getpid()) 1661 logging.debug('Our pid: %d' % os.getpid())
1662 with self._lock:
1663 if not self._initialized:
1664 raise TracingFailure(
1665 'Called Tracer.trace() on an unitialized object',
1666 None, None, None, tracename)
1667 assert tracename not in (i['trace'] for i in self._traces)
1618 1668
1619 # Part 1: start the child process. 1669 # Part 1: start the child process.
1620 stdout = stderr = None 1670 stdout = stderr = None
1621 if output: 1671 if output:
1622 stdout = subprocess.PIPE 1672 stdout = subprocess.PIPE
1623 stderr = subprocess.STDOUT 1673 stderr = subprocess.STDOUT
1624 child_cmd = [ 1674 child_cmd = [
1625 sys.executable, 1675 sys.executable,
1626 os.path.join(BASE_DIR, 'trace_child_process.py'), 1676 os.path.join(BASE_DIR, 'trace_child_process.py'),
1627 '--wait', 1677 '--wait',
(...skipping 38 matching lines...) Expand 10 before | Expand all | Expand 10 after
1666 out = child.communicate(signal)[0] 1716 out = child.communicate(signal)[0]
1667 1717
1668 dtrace.wait() 1718 dtrace.wait()
1669 if dtrace.returncode != 0: 1719 if dtrace.returncode != 0:
1670 print 'dtrace failure: %d' % dtrace.returncode 1720 print 'dtrace failure: %d' % dtrace.returncode
1671 with open(logname) as logfile: 1721 with open(logname) as logfile:
1672 print ''.join(logfile.readlines()[-100:]) 1722 print ''.join(logfile.readlines()[-100:])
1673 # Find a better way. 1723 # Find a better way.
1674 os.remove(logname) 1724 os.remove(logname)
1675 1725
1726 with self._lock:
1727 assert tracename not in (i['trace'] for i in self._traces)
1728 self._traces.append(
1729 {
1730 'cmd': cmd,
1731 'cwd': cwd,
1732 # The pid of strace process, not very useful.
1733 'pid': child.pid,
1734 'trace': tracename,
1735 'output': out,
1736 })
1676 return dtrace.returncode or child.returncode, out 1737 return dtrace.returncode or child.returncode, out
1677 1738
1678 def post_process_log(self): 1739 def post_process_log(self):
1679 """Sorts the log back in order when each call occured. 1740 """Sorts the log back in order when each call occured.
1680 1741
1681 dtrace doesn't save the buffer in strict order since it keeps one buffer 1742 dtrace doesn't save the buffer in strict order since it keeps one buffer
1682 per CPU. 1743 per CPU.
1683 """ 1744 """
1684 super(Dtrace.Tracer, self).post_process_log() 1745 super(Dtrace.Tracer, self).post_process_log()
1685 logname = self._logname + '.log' 1746 logname = self._logname + '.log'
(...skipping 16 matching lines...) Expand all
1702 1763
1703 @staticmethod 1764 @staticmethod
1704 def clean_trace(logname): 1765 def clean_trace(logname):
1705 for ext in ('', '.log'): 1766 for ext in ('', '.log'):
1706 if os.path.isfile(logname + ext): 1767 if os.path.isfile(logname + ext):
1707 os.remove(logname + ext) 1768 os.remove(logname + ext)
1708 1769
1709 @classmethod 1770 @classmethod
1710 def parse_log(cls, logname, blacklist): 1771 def parse_log(cls, logname, blacklist):
1711 logging.info('parse_log(%s, %s)' % (logname, blacklist)) 1772 logging.info('parse_log(%s, %s)' % (logname, blacklist))
1712 context = cls.Context(blacklist) 1773 data = read_json(logname)
1713 for line in open(logname + '.log', 'rb'): 1774 out = []
1714 context.on_line(line) 1775 for item in data['traces']:
1715 return context.to_results() 1776 context = cls.Context(blacklist)
1777 for line in open(logname + '.log', 'rb'):
1778 context.on_line(line)
1779 out.append(
1780 {
1781 'results': context.to_results(),
1782 'trace': item['trace'],
1783 'output': item['output'],
1784 })
1785 return out
1716 1786
1717 1787
1718 class LogmanTrace(ApiBase): 1788 class LogmanTrace(ApiBase):
1719 """Uses the native Windows ETW based tracing functionality to trace a child 1789 """Uses the native Windows ETW based tracing functionality to trace a child
1720 process. 1790 process.
1721 1791
1722 Caveat: this implementations doesn't track cwd or initial_cwd. It is because 1792 Caveat: this implementations doesn't track cwd or initial_cwd. It is because
1723 the Windows Kernel doesn't have a concept of 'current working directory' at 1793 the Windows Kernel doesn't have a concept of 'current working directory' at
1724 all. A Win32 process has a map of current directories, one per drive letter 1794 all. A Win32 process has a map of current directories, one per drive letter
1725 and it is managed by the user mode kernel32.dll. In kernel, a file is always 1795 and it is managed by the user mode kernel32.dll. In kernel, a file is always
(...skipping 320 matching lines...) Expand 10 before | Expand all | Expand 10 after
2046 PROCESSOR_ID = 11 2116 PROCESSOR_ID = 11
2047 TIMESTAMP = 16 2117 TIMESTAMP = 16
2048 NULL_GUID = '{00000000-0000-0000-0000-000000000000}' 2118 NULL_GUID = '{00000000-0000-0000-0000-000000000000}'
2049 USER_DATA = 19 2119 USER_DATA = 19
2050 2120
2051 def trace(self, cmd, cwd, tracename, output): 2121 def trace(self, cmd, cwd, tracename, output):
2052 """Uses logman.exe to start and stop the NT Kernel Logger while the 2122 """Uses logman.exe to start and stop the NT Kernel Logger while the
2053 executable to be traced is run. 2123 executable to be traced is run.
2054 """ 2124 """
2055 logging.info('trace(%s, %s, %s, %s)' % (cmd, cwd, tracename, output)) 2125 logging.info('trace(%s, %s, %s, %s)' % (cmd, cwd, tracename, output))
2126 with self._lock:
2127 if not self._initialized:
2128 raise TracingFailure(
2129 'Called Tracer.trace() on an unitialized object',
2130 None, None, None, tracename)
2131 assert tracename not in (i['trace'] for i in self._traces)
2132
2056 # Use "logman -?" for help. 2133 # Use "logman -?" for help.
2057 2134
2058 stdout = stderr = None 2135 stdout = stderr = None
2059 if output: 2136 if output:
2060 stdout = subprocess.PIPE 2137 stdout = subprocess.PIPE
2061 stderr = subprocess.STDOUT 2138 stderr = subprocess.STDOUT
2062 2139
2063 # 1. Start the log collection. 2140 # 1. Start the log collection.
2064 self._start_log(self._logname + '.etl') 2141 self._start_log(self._logname + '.etl')
2065 2142
(...skipping 14 matching lines...) Expand all
2080 cwd=cwd, 2157 cwd=cwd,
2081 stdin=subprocess.PIPE, 2158 stdin=subprocess.PIPE,
2082 stdout=stdout, 2159 stdout=stdout,
2083 stderr=stderr) 2160 stderr=stderr)
2084 logging.debug('Started child pid: %d' % child.pid) 2161 logging.debug('Started child pid: %d' % child.pid)
2085 out = child.communicate()[0] 2162 out = child.communicate()[0]
2086 finally: 2163 finally:
2087 # 3. Stop the log collection. 2164 # 3. Stop the log collection.
2088 self._stop_log() 2165 self._stop_log()
2089 2166
2090 # 5. Save metadata. 2167 with self._lock:
2091 value = { 2168 assert tracename not in (i['trace'] for i in self._traces)
2092 'pid': child.pid, 2169 self._traces.append({
2093 'format': 'csv', 2170 'command': cmd,
2094 } 2171 'cwd': cwd,
2095 write_json(self._logname, value, False) 2172 'pid': child.pid,
2173 'trace': tracename,
2174 'output': out,
2175 })
2176
2096 return child.returncode, out 2177 return child.returncode, out
2097 2178
2098 @classmethod 2179 @classmethod
2099 def _start_log(cls, etl): 2180 def _start_log(cls, etl):
2100 """Starts the log collection. 2181 """Starts the log collection.
2101 2182
2102 One can get the list of potentially interesting providers with: 2183 One can get the list of potentially interesting providers with:
2103 "logman query providers | findstr /i file" 2184 "logman query providers | findstr /i file"
2104 """ 2185 """
2105 cmd_start = [ 2186 cmd_start = [
(...skipping 212 matching lines...) Expand 10 before | Expand all | Expand 10 after
2318 @classmethod 2399 @classmethod
2319 def parse_log(cls, logname, blacklist): 2400 def parse_log(cls, logname, blacklist):
2320 logging.info('parse_log(%s, %s)' % (logname, blacklist)) 2401 logging.info('parse_log(%s, %s)' % (logname, blacklist))
2321 2402
2322 def blacklist_more(filepath): 2403 def blacklist_more(filepath):
2323 # All the NTFS metadata is in the form x:\$EXTEND or stuff like that. 2404 # All the NTFS metadata is in the form x:\$EXTEND or stuff like that.
2324 return blacklist(filepath) or re.match(r'[A-Z]\:\\\$EXTEND', filepath) 2405 return blacklist(filepath) or re.match(r'[A-Z]\:\\\$EXTEND', filepath)
2325 2406
2326 data = read_json(logname) 2407 data = read_json(logname)
2327 lines = read_json(logname + '.json') 2408 lines = read_json(logname + '.json')
2328 context = cls.Context(blacklist_more, data['pid']) 2409 out = []
2329 for line in lines: 2410 for index, item in enumerate(data['traces']):
2330 context.on_line(line) 2411 print >> sys.stderr, ('%d out of %d' % (index, len(data['traces'])))
2331 return context.to_results() 2412 context = cls.Context(blacklist_more, item['pid'])
2413 for line in lines:
2414 context.on_line(line)
2415 out.append(
2416 {
2417 'results': context.to_results(),
2418 'trace': item['trace'],
2419 'output': item['output'],
2420 })
2421 return out
2332 2422
2333 2423
2334 def get_api(): 2424 def get_api():
2335 """Returns the correct implementation for the current OS.""" 2425 """Returns the correct implementation for the current OS."""
2336 if sys.platform == 'cygwin': 2426 if sys.platform == 'cygwin':
2337 raise NotImplementedError( 2427 raise NotImplementedError(
2338 'Not implemented for cygwin, start the script from Win32 python') 2428 'Not implemented for cygwin, start the script from Win32 python')
2339 flavors = { 2429 flavors = {
2340 'win32': LogmanTrace, 2430 'win32': LogmanTrace,
2341 'darwin': Dtrace, 2431 'darwin': Dtrace,
(...skipping 97 matching lines...) Expand 10 before | Expand all | Expand 10 after
2439 2529
2440 def load_trace(logfile, root_dir, api): 2530 def load_trace(logfile, root_dir, api):
2441 """Loads a trace file and returns the Results instance. 2531 """Loads a trace file and returns the Results instance.
2442 2532
2443 Arguments: 2533 Arguments:
2444 - logfile: File to load. 2534 - logfile: File to load.
2445 - root_dir: Root directory to use to determine if a file is relevant to the 2535 - root_dir: Root directory to use to determine if a file is relevant to the
2446 trace or not. 2536 trace or not.
2447 - api: A tracing api instance. 2537 - api: A tracing api instance.
2448 """ 2538 """
2449 results = api.parse_log(logfile, get_blacklist(api)) 2539 data = api.parse_log(logfile, get_blacklist(api))
2540 assert len(data) == 1, 'More than one trace was detected!'
2541 results = data[0]['results']
2450 if root_dir: 2542 if root_dir:
2451 results = results.strip_root(root_dir) 2543 results = results.strip_root(root_dir)
2452 return results 2544 return results
2453 2545
2454 2546
2455 def CMDclean(parser, args): 2547 def CMDclean(parser, args):
2456 """Cleans up traces.""" 2548 """Cleans up traces."""
2457 options, args = parser.parse_args(args) 2549 options, args = parser.parse_args(args)
2458 api = get_api() 2550 api = get_api()
2459 api.clean_trace(options.log) 2551 api.clean_trace(options.log)
(...skipping 144 matching lines...) Expand 10 before | Expand all | Expand 10 after
2604 for fn in dir(sys.modules[__name__]) 2696 for fn in dir(sys.modules[__name__])
2605 if fn.startswith('CMD'))) 2697 if fn.startswith('CMD')))
2606 2698
2607 command = get_command_handler(argv[0] if argv else None) 2699 command = get_command_handler(argv[0] if argv else None)
2608 parser = gen_parser(command) 2700 parser = gen_parser(command)
2609 return command(parser, argv[1:]) 2701 return command(parser, argv[1:])
2610 2702
2611 2703
2612 if __name__ == '__main__': 2704 if __name__ == '__main__':
2613 sys.exit(main(sys.argv[1:])) 2705 sys.exit(main(sys.argv[1:]))
OLDNEW
« no previous file with comments | « no previous file | tools/isolate/trace_inputs_smoke_test.py » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698