1ad0b04f54dab7c049e98abd97353bd46ce30294bChris Craik# Copyright (c) 2015 The Chromium Authors. All rights reserved.
2ad0b04f54dab7c049e98abd97353bd46ce30294bChris Craik# Use of this source code is governed by a BSD-style license that can be
3ad0b04f54dab7c049e98abd97353bd46ce30294bChris Craik# found in the LICENSE file.
4ad0b04f54dab7c049e98abd97353bd46ce30294bChris Craik
5ad0b04f54dab7c049e98abd97353bd46ce30294bChris Craikimport Queue
6ad0b04f54dab7c049e98abd97353bd46ce30294bChris Craikimport re
7ad0b04f54dab7c049e98abd97353bd46ce30294bChris Craikimport subprocess
8ad0b04f54dab7c049e98abd97353bd46ce30294bChris Craikimport sys
9ad0b04f54dab7c049e98abd97353bd46ce30294bChris Craikimport threading
10ad0b04f54dab7c049e98abd97353bd46ce30294bChris Craikimport time
11ad0b04f54dab7c049e98abd97353bd46ce30294bChris Craikimport zlib
12ad0b04f54dab7c049e98abd97353bd46ce30294bChris Craik
13ad0b04f54dab7c049e98abd97353bd46ce30294bChris Craikimport systrace_agent
14ad0b04f54dab7c049e98abd97353bd46ce30294bChris Craikimport util
15ad0b04f54dab7c049e98abd97353bd46ce30294bChris Craik
16ad0b04f54dab7c049e98abd97353bd46ce30294bChris Craik# Text that ADB sends, but does not need to be displayed to the user.
17ad0b04f54dab7c049e98abd97353bd46ce30294bChris CraikADB_IGNORE_REGEXP = r'^capturing trace\.\.\. done|^capturing trace\.\.\.'
18ad0b04f54dab7c049e98abd97353bd46ce30294bChris Craik# The number of seconds to wait on output from ADB.
19ad0b04f54dab7c049e98abd97353bd46ce30294bChris CraikADB_STDOUT_READ_TIMEOUT = 0.2
20ad0b04f54dab7c049e98abd97353bd46ce30294bChris Craik# The adb shell command to initiate a trace.
21ad0b04f54dab7c049e98abd97353bd46ce30294bChris CraikATRACE_BASE_ARGS = ['atrace']
22ad0b04f54dab7c049e98abd97353bd46ce30294bChris Craik# If a custom list of categories is not specified, traces will include
23ad0b04f54dab7c049e98abd97353bd46ce30294bChris Craik# these categories (if available on the device).
24ad0b04f54dab7c049e98abd97353bd46ce30294bChris CraikDEFAULT_CATEGORIES = 'sched gfx view dalvik webview input disk am wm'.split()
25ad0b04f54dab7c049e98abd97353bd46ce30294bChris Craik# The command to list trace categories.
26ad0b04f54dab7c049e98abd97353bd46ce30294bChris CraikLIST_CATEGORIES_ARGS = ATRACE_BASE_ARGS + ['--list_categories']
27ad0b04f54dab7c049e98abd97353bd46ce30294bChris Craik# Minimum number of seconds between displaying status updates.
28ad0b04f54dab7c049e98abd97353bd46ce30294bChris CraikMIN_TIME_BETWEEN_STATUS_UPDATES = 0.2
29ad0b04f54dab7c049e98abd97353bd46ce30294bChris Craik# ADB sends this text to indicate the beginning of the trace data.
30ad0b04f54dab7c049e98abd97353bd46ce30294bChris CraikTRACE_START_REGEXP = r'TRACE\:'
31ad0b04f54dab7c049e98abd97353bd46ce30294bChris Craik# Plain-text trace data should always start with this string.
32ad0b04f54dab7c049e98abd97353bd46ce30294bChris CraikTRACE_TEXT_HEADER = '# tracer'
33ad0b04f54dab7c049e98abd97353bd46ce30294bChris Craik
34ad0b04f54dab7c049e98abd97353bd46ce30294bChris Craik# This list is based on the tags in frameworks/native/include/utils/Trace.h for
35ad0b04f54dab7c049e98abd97353bd46ce30294bChris Craik# legacy platform.
36ad0b04f54dab7c049e98abd97353bd46ce30294bChris CraikLEGACY_TRACE_TAG_BITS = (
37ad0b04f54dab7c049e98abd97353bd46ce30294bChris Craik  ('gfx',       1<<1),
38ad0b04f54dab7c049e98abd97353bd46ce30294bChris Craik  ('input',     1<<2),
39ad0b04f54dab7c049e98abd97353bd46ce30294bChris Craik  ('view',      1<<3),
40ad0b04f54dab7c049e98abd97353bd46ce30294bChris Craik  ('webview',   1<<4),
41ad0b04f54dab7c049e98abd97353bd46ce30294bChris Craik  ('wm',        1<<5),
42ad0b04f54dab7c049e98abd97353bd46ce30294bChris Craik  ('am',        1<<6),
43ad0b04f54dab7c049e98abd97353bd46ce30294bChris Craik  ('sm',        1<<7),
44ad0b04f54dab7c049e98abd97353bd46ce30294bChris Craik  ('audio',     1<<8),
45ad0b04f54dab7c049e98abd97353bd46ce30294bChris Craik  ('video',     1<<9),
46ad0b04f54dab7c049e98abd97353bd46ce30294bChris Craik  ('camera',    1<<10),
47ad0b04f54dab7c049e98abd97353bd46ce30294bChris Craik)
48ad0b04f54dab7c049e98abd97353bd46ce30294bChris Craik
49ad0b04f54dab7c049e98abd97353bd46ce30294bChris Craik
50ad0b04f54dab7c049e98abd97353bd46ce30294bChris Craikdef try_create_agent(options, categories):
51ad0b04f54dab7c049e98abd97353bd46ce30294bChris Craik  if options.from_file is not None:
52ad0b04f54dab7c049e98abd97353bd46ce30294bChris Craik    return AtraceAgent(options, categories)
53ad0b04f54dab7c049e98abd97353bd46ce30294bChris Craik
54ad0b04f54dab7c049e98abd97353bd46ce30294bChris Craik  device_sdk_version = util.get_device_sdk_version()
55ad0b04f54dab7c049e98abd97353bd46ce30294bChris Craik  if device_sdk_version >= 18:
56ad0b04f54dab7c049e98abd97353bd46ce30294bChris Craik    return AtraceAgent(options, categories)
57ad0b04f54dab7c049e98abd97353bd46ce30294bChris Craik  elif device_sdk_version >= 16:
58ad0b04f54dab7c049e98abd97353bd46ce30294bChris Craik    return AtraceLegacyAgent(options, categories)
59ad0b04f54dab7c049e98abd97353bd46ce30294bChris Craik
60ad0b04f54dab7c049e98abd97353bd46ce30294bChris Craik
61ad0b04f54dab7c049e98abd97353bd46ce30294bChris Craikclass AtraceAgent(systrace_agent.SystraceAgent):
62ad0b04f54dab7c049e98abd97353bd46ce30294bChris Craik  def __init__(self, options, categories):
63ad0b04f54dab7c049e98abd97353bd46ce30294bChris Craik    super(AtraceAgent, self).__init__(options, categories)
64ad0b04f54dab7c049e98abd97353bd46ce30294bChris Craik    self._expect_trace = False
65ad0b04f54dab7c049e98abd97353bd46ce30294bChris Craik    self._adb = None
66ad0b04f54dab7c049e98abd97353bd46ce30294bChris Craik    self._trace_data = None
67ad0b04f54dab7c049e98abd97353bd46ce30294bChris Craik
68ad0b04f54dab7c049e98abd97353bd46ce30294bChris Craik  def start(self):
69ad0b04f54dab7c049e98abd97353bd46ce30294bChris Craik    tracer_args = self._construct_trace_command()
70ad0b04f54dab7c049e98abd97353bd46ce30294bChris Craik    try:
71ad0b04f54dab7c049e98abd97353bd46ce30294bChris Craik      self._adb = subprocess.Popen(tracer_args, stdout=subprocess.PIPE,
72ad0b04f54dab7c049e98abd97353bd46ce30294bChris Craik                                   stderr=subprocess.PIPE)
73ad0b04f54dab7c049e98abd97353bd46ce30294bChris Craik    except OSError as error:
74ad0b04f54dab7c049e98abd97353bd46ce30294bChris Craik      print >> sys.stderr, (
75ad0b04f54dab7c049e98abd97353bd46ce30294bChris Craik          'The command "%s" failed with the following error:' %
76ad0b04f54dab7c049e98abd97353bd46ce30294bChris Craik          ' '.join(tracer_args))
77ad0b04f54dab7c049e98abd97353bd46ce30294bChris Craik      print >> sys.stderr, '    ', error
78ad0b04f54dab7c049e98abd97353bd46ce30294bChris Craik      sys.exit(1)
79ad0b04f54dab7c049e98abd97353bd46ce30294bChris Craik
80ad0b04f54dab7c049e98abd97353bd46ce30294bChris Craik  def collect_result(self):
81ad0b04f54dab7c049e98abd97353bd46ce30294bChris Craik    trace_data = self._collect_trace_data();
82ad0b04f54dab7c049e98abd97353bd46ce30294bChris Craik    if self._expect_trace:
83ad0b04f54dab7c049e98abd97353bd46ce30294bChris Craik      self._trace_data = self._preprocess_trace_data(trace_data);
84ad0b04f54dab7c049e98abd97353bd46ce30294bChris Craik
85ad0b04f54dab7c049e98abd97353bd46ce30294bChris Craik  def expect_trace(self):
86ad0b04f54dab7c049e98abd97353bd46ce30294bChris Craik    return self._expect_trace
87ad0b04f54dab7c049e98abd97353bd46ce30294bChris Craik
88ad0b04f54dab7c049e98abd97353bd46ce30294bChris Craik  def get_trace_data(self):
89ad0b04f54dab7c049e98abd97353bd46ce30294bChris Craik    return self._trace_data
90ad0b04f54dab7c049e98abd97353bd46ce30294bChris Craik
91ad0b04f54dab7c049e98abd97353bd46ce30294bChris Craik  def get_class_name(self):
92ad0b04f54dab7c049e98abd97353bd46ce30294bChris Craik    return 'trace-data'
93ad0b04f54dab7c049e98abd97353bd46ce30294bChris Craik
94ad0b04f54dab7c049e98abd97353bd46ce30294bChris Craik  def _construct_list_categories_command(self):
95ad0b04f54dab7c049e98abd97353bd46ce30294bChris Craik    return util.construct_adb_shell_command(
96ad0b04f54dab7c049e98abd97353bd46ce30294bChris Craik          LIST_CATEGORIES_ARGS, self._options.device_serial)
97ad0b04f54dab7c049e98abd97353bd46ce30294bChris Craik
98ad0b04f54dab7c049e98abd97353bd46ce30294bChris Craik  def _construct_extra_trace_command(self):
99ad0b04f54dab7c049e98abd97353bd46ce30294bChris Craik    extra_args = []
100ad0b04f54dab7c049e98abd97353bd46ce30294bChris Craik    if self._options.app_name is not None:
101ad0b04f54dab7c049e98abd97353bd46ce30294bChris Craik      extra_args.extend(['-a', self._options.app_name])
102ad0b04f54dab7c049e98abd97353bd46ce30294bChris Craik
103ad0b04f54dab7c049e98abd97353bd46ce30294bChris Craik    if self._options.kfuncs is not None:
104ad0b04f54dab7c049e98abd97353bd46ce30294bChris Craik      extra_args.extend(['-k', self._options.kfuncs])
105ad0b04f54dab7c049e98abd97353bd46ce30294bChris Craik
106ad0b04f54dab7c049e98abd97353bd46ce30294bChris Craik    if not self._categories:
107ad0b04f54dab7c049e98abd97353bd46ce30294bChris Craik      self._categories = get_default_categories(self._options.device_serial)
108ad0b04f54dab7c049e98abd97353bd46ce30294bChris Craik    extra_args.extend(self._categories)
109ad0b04f54dab7c049e98abd97353bd46ce30294bChris Craik    return extra_args
110ad0b04f54dab7c049e98abd97353bd46ce30294bChris Craik
111ad0b04f54dab7c049e98abd97353bd46ce30294bChris Craik  def _construct_trace_command(self):
112ad0b04f54dab7c049e98abd97353bd46ce30294bChris Craik    """Builds a command-line used to invoke a trace process.
113ad0b04f54dab7c049e98abd97353bd46ce30294bChris Craik
114ad0b04f54dab7c049e98abd97353bd46ce30294bChris Craik    Returns:
115ad0b04f54dab7c049e98abd97353bd46ce30294bChris Craik      A tuple where the first element is an array of command-line arguments, and
116ad0b04f54dab7c049e98abd97353bd46ce30294bChris Craik      the second element is a boolean which will be true if the commend will
117ad0b04f54dab7c049e98abd97353bd46ce30294bChris Craik      stream trace data.
118ad0b04f54dab7c049e98abd97353bd46ce30294bChris Craik    """
119ad0b04f54dab7c049e98abd97353bd46ce30294bChris Craik    if self._options.list_categories:
120ad0b04f54dab7c049e98abd97353bd46ce30294bChris Craik      tracer_args = self._construct_list_categories_command()
121ad0b04f54dab7c049e98abd97353bd46ce30294bChris Craik      self._expect_trace = False
122ad0b04f54dab7c049e98abd97353bd46ce30294bChris Craik    elif self._options.from_file is not None:
123ad0b04f54dab7c049e98abd97353bd46ce30294bChris Craik      tracer_args = ['cat', self._options.from_file]
124ad0b04f54dab7c049e98abd97353bd46ce30294bChris Craik      self._expect_trace = True
125ad0b04f54dab7c049e98abd97353bd46ce30294bChris Craik    else:
126ad0b04f54dab7c049e98abd97353bd46ce30294bChris Craik      atrace_args = ATRACE_BASE_ARGS[:]
127ad0b04f54dab7c049e98abd97353bd46ce30294bChris Craik      self._expect_trace = True
128ad0b04f54dab7c049e98abd97353bd46ce30294bChris Craik      if self._options.compress_trace_data:
129ad0b04f54dab7c049e98abd97353bd46ce30294bChris Craik        atrace_args.extend(['-z'])
130ad0b04f54dab7c049e98abd97353bd46ce30294bChris Craik
131ad0b04f54dab7c049e98abd97353bd46ce30294bChris Craik      if ((self._options.trace_time is not None)
132ad0b04f54dab7c049e98abd97353bd46ce30294bChris Craik          and (self._options.trace_time > 0)):
133ad0b04f54dab7c049e98abd97353bd46ce30294bChris Craik        atrace_args.extend(['-t', str(self._options.trace_time)])
134ad0b04f54dab7c049e98abd97353bd46ce30294bChris Craik
135ad0b04f54dab7c049e98abd97353bd46ce30294bChris Craik      if ((self._options.trace_buf_size is not None)
136ad0b04f54dab7c049e98abd97353bd46ce30294bChris Craik          and (self._options.trace_buf_size > 0)):
137ad0b04f54dab7c049e98abd97353bd46ce30294bChris Craik        atrace_args.extend(['-b', str(self._options.trace_buf_size)])
138ad0b04f54dab7c049e98abd97353bd46ce30294bChris Craik      extra_args = self._construct_extra_trace_command()
139ad0b04f54dab7c049e98abd97353bd46ce30294bChris Craik      atrace_args.extend(extra_args)
140ad0b04f54dab7c049e98abd97353bd46ce30294bChris Craik
141ad0b04f54dab7c049e98abd97353bd46ce30294bChris Craik      if self._options.fix_threads:
142ad0b04f54dab7c049e98abd97353bd46ce30294bChris Craik        atrace_args.extend([';', 'ps', '-t'])
143ad0b04f54dab7c049e98abd97353bd46ce30294bChris Craik      tracer_args = util.construct_adb_shell_command(
144ad0b04f54dab7c049e98abd97353bd46ce30294bChris Craik          atrace_args, self._options.device_serial)
145ad0b04f54dab7c049e98abd97353bd46ce30294bChris Craik
146ad0b04f54dab7c049e98abd97353bd46ce30294bChris Craik    return tracer_args
147ad0b04f54dab7c049e98abd97353bd46ce30294bChris Craik
148ad0b04f54dab7c049e98abd97353bd46ce30294bChris Craik  def _collect_trace_data(self):
149ad0b04f54dab7c049e98abd97353bd46ce30294bChris Craik    # Read the output from ADB in a worker thread.  This allows us to monitor
150ad0b04f54dab7c049e98abd97353bd46ce30294bChris Craik    # the progress of ADB and bail if ADB becomes unresponsive for any reason.
151ad0b04f54dab7c049e98abd97353bd46ce30294bChris Craik
152ad0b04f54dab7c049e98abd97353bd46ce30294bChris Craik    # Limit the stdout_queue to 128 entries because we will initially be reading
153ad0b04f54dab7c049e98abd97353bd46ce30294bChris Craik    # one byte at a time.  When the queue fills up, the reader thread will
154ad0b04f54dab7c049e98abd97353bd46ce30294bChris Craik    # block until there is room in the queue.  Once we start downloading the
155ad0b04f54dab7c049e98abd97353bd46ce30294bChris Craik    # trace data, we will switch to reading data in larger chunks, and 128
156ad0b04f54dab7c049e98abd97353bd46ce30294bChris Craik    # entries should be plenty for that purpose.
157ad0b04f54dab7c049e98abd97353bd46ce30294bChris Craik    stdout_queue = Queue.Queue(maxsize=128)
158ad0b04f54dab7c049e98abd97353bd46ce30294bChris Craik    stderr_queue = Queue.Queue()
159ad0b04f54dab7c049e98abd97353bd46ce30294bChris Craik
160ad0b04f54dab7c049e98abd97353bd46ce30294bChris Craik    if self._expect_trace:
161ad0b04f54dab7c049e98abd97353bd46ce30294bChris Craik      # Use stdout.write() (here and for the rest of this function) instead
162ad0b04f54dab7c049e98abd97353bd46ce30294bChris Craik      # of print() to avoid extra newlines.
163ad0b04f54dab7c049e98abd97353bd46ce30294bChris Craik      sys.stdout.write('Capturing trace...')
164ad0b04f54dab7c049e98abd97353bd46ce30294bChris Craik
165ad0b04f54dab7c049e98abd97353bd46ce30294bChris Craik    # Use a chunk_size of 1 for stdout so we can display the output to
166ad0b04f54dab7c049e98abd97353bd46ce30294bChris Craik    # the user without waiting for a full line to be sent.
167ad0b04f54dab7c049e98abd97353bd46ce30294bChris Craik    stdout_thread = FileReaderThread(self._adb.stdout, stdout_queue,
168ad0b04f54dab7c049e98abd97353bd46ce30294bChris Craik                                     text_file=False, chunk_size=1)
169ad0b04f54dab7c049e98abd97353bd46ce30294bChris Craik    stderr_thread = FileReaderThread(self._adb.stderr, stderr_queue,
170ad0b04f54dab7c049e98abd97353bd46ce30294bChris Craik                                     text_file=True)
171ad0b04f54dab7c049e98abd97353bd46ce30294bChris Craik    stdout_thread.start()
172ad0b04f54dab7c049e98abd97353bd46ce30294bChris Craik    stderr_thread.start()
173ad0b04f54dab7c049e98abd97353bd46ce30294bChris Craik
174ad0b04f54dab7c049e98abd97353bd46ce30294bChris Craik    # Holds the trace data returned by ADB.
175ad0b04f54dab7c049e98abd97353bd46ce30294bChris Craik    trace_data = []
176ad0b04f54dab7c049e98abd97353bd46ce30294bChris Craik    # Keep track of the current line so we can find the TRACE_START_REGEXP.
177ad0b04f54dab7c049e98abd97353bd46ce30294bChris Craik    current_line = ''
178ad0b04f54dab7c049e98abd97353bd46ce30294bChris Craik    # Set to True once we've received the TRACE_START_REGEXP.
179ad0b04f54dab7c049e98abd97353bd46ce30294bChris Craik    reading_trace_data = False
180ad0b04f54dab7c049e98abd97353bd46ce30294bChris Craik
181ad0b04f54dab7c049e98abd97353bd46ce30294bChris Craik    last_status_update_time = time.time()
182ad0b04f54dab7c049e98abd97353bd46ce30294bChris Craik
183ad0b04f54dab7c049e98abd97353bd46ce30294bChris Craik    while (stdout_thread.isAlive() or stderr_thread.isAlive() or
184ad0b04f54dab7c049e98abd97353bd46ce30294bChris Craik           not stdout_queue.empty() or not stderr_queue.empty()):
185ad0b04f54dab7c049e98abd97353bd46ce30294bChris Craik      if self._expect_trace:
186ad0b04f54dab7c049e98abd97353bd46ce30294bChris Craik        last_status_update_time = status_update(last_status_update_time)
187ad0b04f54dab7c049e98abd97353bd46ce30294bChris Craik
188ad0b04f54dab7c049e98abd97353bd46ce30294bChris Craik      while not stderr_queue.empty():
189ad0b04f54dab7c049e98abd97353bd46ce30294bChris Craik        # Pass along errors from adb.
190ad0b04f54dab7c049e98abd97353bd46ce30294bChris Craik        line = stderr_queue.get()
191ad0b04f54dab7c049e98abd97353bd46ce30294bChris Craik        sys.stderr.write(line)
192ad0b04f54dab7c049e98abd97353bd46ce30294bChris Craik
193ad0b04f54dab7c049e98abd97353bd46ce30294bChris Craik      # Read stdout from adb.  The loop exits if we don't get any data for
194ad0b04f54dab7c049e98abd97353bd46ce30294bChris Craik      # ADB_STDOUT_READ_TIMEOUT seconds.
195ad0b04f54dab7c049e98abd97353bd46ce30294bChris Craik      while True:
196ad0b04f54dab7c049e98abd97353bd46ce30294bChris Craik        try:
197ad0b04f54dab7c049e98abd97353bd46ce30294bChris Craik          chunk = stdout_queue.get(True, ADB_STDOUT_READ_TIMEOUT)
198ad0b04f54dab7c049e98abd97353bd46ce30294bChris Craik        except Queue.Empty:
199ad0b04f54dab7c049e98abd97353bd46ce30294bChris Craik          # Didn't get any data, so exit the loop to check that ADB is still
200ad0b04f54dab7c049e98abd97353bd46ce30294bChris Craik          # alive and print anything sent to stderr.
201ad0b04f54dab7c049e98abd97353bd46ce30294bChris Craik          break
202ad0b04f54dab7c049e98abd97353bd46ce30294bChris Craik
203ad0b04f54dab7c049e98abd97353bd46ce30294bChris Craik        if reading_trace_data:
204ad0b04f54dab7c049e98abd97353bd46ce30294bChris Craik          # Save, but don't print, the trace data.
205ad0b04f54dab7c049e98abd97353bd46ce30294bChris Craik          trace_data.append(chunk)
206ad0b04f54dab7c049e98abd97353bd46ce30294bChris Craik        else:
207ad0b04f54dab7c049e98abd97353bd46ce30294bChris Craik          if not self._expect_trace:
208ad0b04f54dab7c049e98abd97353bd46ce30294bChris Craik            sys.stdout.write(chunk)
209ad0b04f54dab7c049e98abd97353bd46ce30294bChris Craik          else:
210ad0b04f54dab7c049e98abd97353bd46ce30294bChris Craik            # Buffer the output from ADB so we can remove some strings that
211ad0b04f54dab7c049e98abd97353bd46ce30294bChris Craik            # don't need to be shown to the user.
212ad0b04f54dab7c049e98abd97353bd46ce30294bChris Craik            current_line += chunk
213ad0b04f54dab7c049e98abd97353bd46ce30294bChris Craik            if re.match(TRACE_START_REGEXP, current_line):
214ad0b04f54dab7c049e98abd97353bd46ce30294bChris Craik              # We are done capturing the trace.
215ad0b04f54dab7c049e98abd97353bd46ce30294bChris Craik              sys.stdout.write('Done.\n')
216ad0b04f54dab7c049e98abd97353bd46ce30294bChris Craik              # Now we start downloading the trace data.
217ad0b04f54dab7c049e98abd97353bd46ce30294bChris Craik              sys.stdout.write('Downloading trace...')
218ad0b04f54dab7c049e98abd97353bd46ce30294bChris Craik              current_line = ''
219ad0b04f54dab7c049e98abd97353bd46ce30294bChris Craik              # Use a larger chunk size for efficiency since we no longer
220ad0b04f54dab7c049e98abd97353bd46ce30294bChris Craik              # need to worry about parsing the stream.
221ad0b04f54dab7c049e98abd97353bd46ce30294bChris Craik              stdout_thread.set_chunk_size(4096)
222ad0b04f54dab7c049e98abd97353bd46ce30294bChris Craik              reading_trace_data = True
223ad0b04f54dab7c049e98abd97353bd46ce30294bChris Craik            elif chunk == '\n' or chunk == '\r':
224ad0b04f54dab7c049e98abd97353bd46ce30294bChris Craik              # Remove ADB output that we don't care about.
225ad0b04f54dab7c049e98abd97353bd46ce30294bChris Craik              current_line = re.sub(ADB_IGNORE_REGEXP, '', current_line)
226ad0b04f54dab7c049e98abd97353bd46ce30294bChris Craik              if len(current_line) > 1:
227ad0b04f54dab7c049e98abd97353bd46ce30294bChris Craik                # ADB printed something that we didn't understand, so show it
228ad0b04f54dab7c049e98abd97353bd46ce30294bChris Craik                # it to the user (might be helpful for debugging).
229ad0b04f54dab7c049e98abd97353bd46ce30294bChris Craik                sys.stdout.write(current_line)
230ad0b04f54dab7c049e98abd97353bd46ce30294bChris Craik              # Reset our current line.
231ad0b04f54dab7c049e98abd97353bd46ce30294bChris Craik              current_line = ''
232ad0b04f54dab7c049e98abd97353bd46ce30294bChris Craik
233ad0b04f54dab7c049e98abd97353bd46ce30294bChris Craik    if self._expect_trace:
234ad0b04f54dab7c049e98abd97353bd46ce30294bChris Craik      if reading_trace_data:
235ad0b04f54dab7c049e98abd97353bd46ce30294bChris Craik        # Indicate to the user that the data download is complete.
236ad0b04f54dab7c049e98abd97353bd46ce30294bChris Craik        sys.stdout.write('Done.\n')
237ad0b04f54dab7c049e98abd97353bd46ce30294bChris Craik      else:
238ad0b04f54dab7c049e98abd97353bd46ce30294bChris Craik        # We didn't receive the trace start tag, so something went wrong.
239ad0b04f54dab7c049e98abd97353bd46ce30294bChris Craik        sys.stdout.write('ERROR.\n')
240ad0b04f54dab7c049e98abd97353bd46ce30294bChris Craik        # Show any buffered ADB output to the user.
241ad0b04f54dab7c049e98abd97353bd46ce30294bChris Craik        current_line = re.sub(ADB_IGNORE_REGEXP, '', current_line)
242ad0b04f54dab7c049e98abd97353bd46ce30294bChris Craik        if current_line:
243ad0b04f54dab7c049e98abd97353bd46ce30294bChris Craik          sys.stdout.write(current_line)
244ad0b04f54dab7c049e98abd97353bd46ce30294bChris Craik          sys.stdout.write('\n')
245ad0b04f54dab7c049e98abd97353bd46ce30294bChris Craik
246ad0b04f54dab7c049e98abd97353bd46ce30294bChris Craik    # The threads should already have stopped, so this is just for cleanup.
247ad0b04f54dab7c049e98abd97353bd46ce30294bChris Craik    stdout_thread.join()
248ad0b04f54dab7c049e98abd97353bd46ce30294bChris Craik    stderr_thread.join()
249ad0b04f54dab7c049e98abd97353bd46ce30294bChris Craik
250ad0b04f54dab7c049e98abd97353bd46ce30294bChris Craik    self._adb.stdout.close()
251ad0b04f54dab7c049e98abd97353bd46ce30294bChris Craik    self._adb.stderr.close()
252ad0b04f54dab7c049e98abd97353bd46ce30294bChris Craik
253ad0b04f54dab7c049e98abd97353bd46ce30294bChris Craik    # The adb process should be done since it's io pipes are closed.  Call
254ad0b04f54dab7c049e98abd97353bd46ce30294bChris Craik    # poll() to set the returncode.
255ad0b04f54dab7c049e98abd97353bd46ce30294bChris Craik    self._adb.poll()
256ad0b04f54dab7c049e98abd97353bd46ce30294bChris Craik
257ad0b04f54dab7c049e98abd97353bd46ce30294bChris Craik    if self._adb.returncode != 0:
258ad0b04f54dab7c049e98abd97353bd46ce30294bChris Craik      print >> sys.stderr, ('The command "%s" returned error code %d.' %
259ad0b04f54dab7c049e98abd97353bd46ce30294bChris Craik                            (' '.join(tracer_args), self._adb.returncode))
260ad0b04f54dab7c049e98abd97353bd46ce30294bChris Craik      sys.exit(1)
261ad0b04f54dab7c049e98abd97353bd46ce30294bChris Craik
262ad0b04f54dab7c049e98abd97353bd46ce30294bChris Craik    return trace_data
263ad0b04f54dab7c049e98abd97353bd46ce30294bChris Craik
264ad0b04f54dab7c049e98abd97353bd46ce30294bChris Craik  def _preprocess_trace_data(self, trace_data):
265ad0b04f54dab7c049e98abd97353bd46ce30294bChris Craik    """Performs various processing on atrace data.
266ad0b04f54dab7c049e98abd97353bd46ce30294bChris Craik
267ad0b04f54dab7c049e98abd97353bd46ce30294bChris Craik    Args:
268ad0b04f54dab7c049e98abd97353bd46ce30294bChris Craik      trace_data: The raw trace data.
269ad0b04f54dab7c049e98abd97353bd46ce30294bChris Craik    Returns:
270ad0b04f54dab7c049e98abd97353bd46ce30294bChris Craik      The processed trace data.
271ad0b04f54dab7c049e98abd97353bd46ce30294bChris Craik    """
272ad0b04f54dab7c049e98abd97353bd46ce30294bChris Craik    trace_data = ''.join(trace_data)
273ad0b04f54dab7c049e98abd97353bd46ce30294bChris Craik
274ad0b04f54dab7c049e98abd97353bd46ce30294bChris Craik    if self._options.fix_threads:
275ad0b04f54dab7c049e98abd97353bd46ce30294bChris Craik      # Extract the thread list dumped by ps.
276ad0b04f54dab7c049e98abd97353bd46ce30294bChris Craik      trace_data, thread_names = extract_thread_list(trace_data)
277ad0b04f54dab7c049e98abd97353bd46ce30294bChris Craik
278ad0b04f54dab7c049e98abd97353bd46ce30294bChris Craik    if trace_data:
279ad0b04f54dab7c049e98abd97353bd46ce30294bChris Craik      trace_data = strip_and_decompress_trace(trace_data)
280ad0b04f54dab7c049e98abd97353bd46ce30294bChris Craik
281ad0b04f54dab7c049e98abd97353bd46ce30294bChris Craik    if not trace_data:
282ad0b04f54dab7c049e98abd97353bd46ce30294bChris Craik      print >> sys.stderr, ('No data was captured.  Output file was not '
283ad0b04f54dab7c049e98abd97353bd46ce30294bChris Craik                            'written.')
284ad0b04f54dab7c049e98abd97353bd46ce30294bChris Craik      sys.exit(1)
285ad0b04f54dab7c049e98abd97353bd46ce30294bChris Craik
286ad0b04f54dab7c049e98abd97353bd46ce30294bChris Craik    if self._options.fix_threads:
287ad0b04f54dab7c049e98abd97353bd46ce30294bChris Craik      trace_data = fix_thread_names(trace_data, thread_names)
288ad0b04f54dab7c049e98abd97353bd46ce30294bChris Craik
289ad0b04f54dab7c049e98abd97353bd46ce30294bChris Craik    if self._options.fix_circular:
290ad0b04f54dab7c049e98abd97353bd46ce30294bChris Craik      trace_data = fix_circular_traces(trace_data)
291ad0b04f54dab7c049e98abd97353bd46ce30294bChris Craik
292ad0b04f54dab7c049e98abd97353bd46ce30294bChris Craik    return trace_data
293ad0b04f54dab7c049e98abd97353bd46ce30294bChris Craik
294ad0b04f54dab7c049e98abd97353bd46ce30294bChris Craik
295ad0b04f54dab7c049e98abd97353bd46ce30294bChris Craikclass AtraceLegacyAgent(AtraceAgent):
296ad0b04f54dab7c049e98abd97353bd46ce30294bChris Craik  def _construct_list_categories_command(self):
297ad0b04f54dab7c049e98abd97353bd46ce30294bChris Craik    LEGACY_CATEGORIES = """       sched - CPU Scheduling
298ad0b04f54dab7c049e98abd97353bd46ce30294bChris Craik        freq - CPU Frequency
299ad0b04f54dab7c049e98abd97353bd46ce30294bChris Craik        idle - CPU Idle
300ad0b04f54dab7c049e98abd97353bd46ce30294bChris Craik        load - CPU Load
301ad0b04f54dab7c049e98abd97353bd46ce30294bChris Craik        disk - Disk I/O (requires root)
302ad0b04f54dab7c049e98abd97353bd46ce30294bChris Craik         bus - Bus utilization (requires root)
303ad0b04f54dab7c049e98abd97353bd46ce30294bChris Craik   workqueue - Kernel workqueues (requires root)"""
304ad0b04f54dab7c049e98abd97353bd46ce30294bChris Craik    return ["echo", LEGACY_CATEGORIES]
305ad0b04f54dab7c049e98abd97353bd46ce30294bChris Craik
306ad0b04f54dab7c049e98abd97353bd46ce30294bChris Craik  def start(self):
307ad0b04f54dab7c049e98abd97353bd46ce30294bChris Craik    super(AtraceLegacyAgent, self).start()
308ad0b04f54dab7c049e98abd97353bd46ce30294bChris Craik    if self.expect_trace():
309ad0b04f54dab7c049e98abd97353bd46ce30294bChris Craik      SHELL_ARGS = ['getprop', 'debug.atrace.tags.enableflags']
310ad0b04f54dab7c049e98abd97353bd46ce30294bChris Craik      output, return_code = util.run_adb_shell(SHELL_ARGS, self._options.device_serial)
311ad0b04f54dab7c049e98abd97353bd46ce30294bChris Craik      flags = 0
312ad0b04f54dab7c049e98abd97353bd46ce30294bChris Craik      if return_code == 0:
313ad0b04f54dab7c049e98abd97353bd46ce30294bChris Craik        try:
314ad0b04f54dab7c049e98abd97353bd46ce30294bChris Craik          if output.startswith('0x'):
315ad0b04f54dab7c049e98abd97353bd46ce30294bChris Craik            flags = int(output, 16)
316ad0b04f54dab7c049e98abd97353bd46ce30294bChris Craik          elif output.startswith('0'):
317ad0b04f54dab7c049e98abd97353bd46ce30294bChris Craik            flags = int(output, 8)
318ad0b04f54dab7c049e98abd97353bd46ce30294bChris Craik          else:
319ad0b04f54dab7c049e98abd97353bd46ce30294bChris Craik            flags = int(output)
320ad0b04f54dab7c049e98abd97353bd46ce30294bChris Craik        except ValueError, e:
321ad0b04f54dab7c049e98abd97353bd46ce30294bChris Craik          pass
322ad0b04f54dab7c049e98abd97353bd46ce30294bChris Craik
323ad0b04f54dab7c049e98abd97353bd46ce30294bChris Craik      if flags:
324ad0b04f54dab7c049e98abd97353bd46ce30294bChris Craik        tags = []
325ad0b04f54dab7c049e98abd97353bd46ce30294bChris Craik        for desc, bit in LEGACY_TRACE_TAG_BITS:
326ad0b04f54dab7c049e98abd97353bd46ce30294bChris Craik          if bit & flags:
327ad0b04f54dab7c049e98abd97353bd46ce30294bChris Craik            tags.append(desc)
328ad0b04f54dab7c049e98abd97353bd46ce30294bChris Craik        categories = tags + self._categories
329ad0b04f54dab7c049e98abd97353bd46ce30294bChris Craik        print 'Collecting data with following categories:', ' '.join(categories)
330ad0b04f54dab7c049e98abd97353bd46ce30294bChris Craik
331ad0b04f54dab7c049e98abd97353bd46ce30294bChris Craik  def _construct_extra_trace_command(self):
332ad0b04f54dab7c049e98abd97353bd46ce30294bChris Craik    extra_args = []
333ad0b04f54dab7c049e98abd97353bd46ce30294bChris Craik    if not self._categories:
334ad0b04f54dab7c049e98abd97353bd46ce30294bChris Craik      self._categories = ['sched', ]
335ad0b04f54dab7c049e98abd97353bd46ce30294bChris Craik    if 'sched' in self._categories:
336ad0b04f54dab7c049e98abd97353bd46ce30294bChris Craik      extra_args.append('-s')
337ad0b04f54dab7c049e98abd97353bd46ce30294bChris Craik    if 'freq' in self._categories:
338ad0b04f54dab7c049e98abd97353bd46ce30294bChris Craik      extra_args.append('-f')
339ad0b04f54dab7c049e98abd97353bd46ce30294bChris Craik    if 'idle' in self._categories:
340ad0b04f54dab7c049e98abd97353bd46ce30294bChris Craik      extra_args.append('-i')
341ad0b04f54dab7c049e98abd97353bd46ce30294bChris Craik    if 'load' in self._categories:
342ad0b04f54dab7c049e98abd97353bd46ce30294bChris Craik      extra_args.append('-l')
343ad0b04f54dab7c049e98abd97353bd46ce30294bChris Craik    if 'disk' in self._categories:
344ad0b04f54dab7c049e98abd97353bd46ce30294bChris Craik      extra_args.append('-d')
345ad0b04f54dab7c049e98abd97353bd46ce30294bChris Craik    if 'bus' in self._categories:
346ad0b04f54dab7c049e98abd97353bd46ce30294bChris Craik      extra_args.append('-u')
347ad0b04f54dab7c049e98abd97353bd46ce30294bChris Craik    if 'workqueue' in self._categories:
348ad0b04f54dab7c049e98abd97353bd46ce30294bChris Craik      extra_args.append('-w')
349ad0b04f54dab7c049e98abd97353bd46ce30294bChris Craik
350ad0b04f54dab7c049e98abd97353bd46ce30294bChris Craik    return extra_args
351ad0b04f54dab7c049e98abd97353bd46ce30294bChris Craik
352ad0b04f54dab7c049e98abd97353bd46ce30294bChris Craik
353ad0b04f54dab7c049e98abd97353bd46ce30294bChris Craikclass FileReaderThread(threading.Thread):
354ad0b04f54dab7c049e98abd97353bd46ce30294bChris Craik  """Reads data from a file/pipe on a worker thread.
355ad0b04f54dab7c049e98abd97353bd46ce30294bChris Craik
356ad0b04f54dab7c049e98abd97353bd46ce30294bChris Craik  Use the standard threading. Thread object API to start and interact with the
357ad0b04f54dab7c049e98abd97353bd46ce30294bChris Craik  thread (start(), join(), etc.).
358ad0b04f54dab7c049e98abd97353bd46ce30294bChris Craik  """
359ad0b04f54dab7c049e98abd97353bd46ce30294bChris Craik
360ad0b04f54dab7c049e98abd97353bd46ce30294bChris Craik  def __init__(self, file_object, output_queue, text_file, chunk_size=-1):
361ad0b04f54dab7c049e98abd97353bd46ce30294bChris Craik    """Initializes a FileReaderThread.
362ad0b04f54dab7c049e98abd97353bd46ce30294bChris Craik
363ad0b04f54dab7c049e98abd97353bd46ce30294bChris Craik    Args:
364ad0b04f54dab7c049e98abd97353bd46ce30294bChris Craik      file_object: The file or pipe to read from.
365ad0b04f54dab7c049e98abd97353bd46ce30294bChris Craik      output_queue: A Queue.Queue object that will receive the data
366ad0b04f54dab7c049e98abd97353bd46ce30294bChris Craik      text_file: If True, the file will be read one line at a time, and
367ad0b04f54dab7c049e98abd97353bd46ce30294bChris Craik          chunk_size will be ignored.  If False, line breaks are ignored and
368ad0b04f54dab7c049e98abd97353bd46ce30294bChris Craik          chunk_size must be set to a positive integer.
369ad0b04f54dab7c049e98abd97353bd46ce30294bChris Craik      chunk_size: When processing a non-text file (text_file = False),
370ad0b04f54dab7c049e98abd97353bd46ce30294bChris Craik          chunk_size is the amount of data to copy into the queue with each
371ad0b04f54dab7c049e98abd97353bd46ce30294bChris Craik          read operation.  For text files, this parameter is ignored.
372ad0b04f54dab7c049e98abd97353bd46ce30294bChris Craik    """
373ad0b04f54dab7c049e98abd97353bd46ce30294bChris Craik    threading.Thread.__init__(self)
374ad0b04f54dab7c049e98abd97353bd46ce30294bChris Craik    self._file_object = file_object
375ad0b04f54dab7c049e98abd97353bd46ce30294bChris Craik    self._output_queue = output_queue
376ad0b04f54dab7c049e98abd97353bd46ce30294bChris Craik    self._text_file = text_file
377ad0b04f54dab7c049e98abd97353bd46ce30294bChris Craik    self._chunk_size = chunk_size
378ad0b04f54dab7c049e98abd97353bd46ce30294bChris Craik    assert text_file or chunk_size > 0
379ad0b04f54dab7c049e98abd97353bd46ce30294bChris Craik
380ad0b04f54dab7c049e98abd97353bd46ce30294bChris Craik  def run(self):
381ad0b04f54dab7c049e98abd97353bd46ce30294bChris Craik    """Overrides Thread's run() function.
382ad0b04f54dab7c049e98abd97353bd46ce30294bChris Craik
383ad0b04f54dab7c049e98abd97353bd46ce30294bChris Craik    Returns when an EOF is encountered.
384ad0b04f54dab7c049e98abd97353bd46ce30294bChris Craik    """
385ad0b04f54dab7c049e98abd97353bd46ce30294bChris Craik    if self._text_file:
386ad0b04f54dab7c049e98abd97353bd46ce30294bChris Craik      # Read a text file one line at a time.
387ad0b04f54dab7c049e98abd97353bd46ce30294bChris Craik      for line in self._file_object:
388ad0b04f54dab7c049e98abd97353bd46ce30294bChris Craik        self._output_queue.put(line)
389ad0b04f54dab7c049e98abd97353bd46ce30294bChris Craik    else:
390ad0b04f54dab7c049e98abd97353bd46ce30294bChris Craik      # Read binary or text data until we get to EOF.
391ad0b04f54dab7c049e98abd97353bd46ce30294bChris Craik      while True:
392ad0b04f54dab7c049e98abd97353bd46ce30294bChris Craik        chunk = self._file_object.read(self._chunk_size)
393ad0b04f54dab7c049e98abd97353bd46ce30294bChris Craik        if not chunk:
394ad0b04f54dab7c049e98abd97353bd46ce30294bChris Craik          break
395ad0b04f54dab7c049e98abd97353bd46ce30294bChris Craik        self._output_queue.put(chunk)
396ad0b04f54dab7c049e98abd97353bd46ce30294bChris Craik
397ad0b04f54dab7c049e98abd97353bd46ce30294bChris Craik  def set_chunk_size(self, chunk_size):
398ad0b04f54dab7c049e98abd97353bd46ce30294bChris Craik    """Change the read chunk size.
399ad0b04f54dab7c049e98abd97353bd46ce30294bChris Craik
400ad0b04f54dab7c049e98abd97353bd46ce30294bChris Craik    This function can only be called if the FileReaderThread object was
401ad0b04f54dab7c049e98abd97353bd46ce30294bChris Craik    created with an initial chunk_size > 0.
402ad0b04f54dab7c049e98abd97353bd46ce30294bChris Craik    Args:
403ad0b04f54dab7c049e98abd97353bd46ce30294bChris Craik      chunk_size: the new chunk size for this file.  Must be > 0.
404ad0b04f54dab7c049e98abd97353bd46ce30294bChris Craik    """
405ad0b04f54dab7c049e98abd97353bd46ce30294bChris Craik    # The chunk size can be changed asynchronously while a file is being read
406ad0b04f54dab7c049e98abd97353bd46ce30294bChris Craik    # in a worker thread.  However, type of file can not be changed after the
407ad0b04f54dab7c049e98abd97353bd46ce30294bChris Craik    # the FileReaderThread has been created.  These asserts verify that we are
408ad0b04f54dab7c049e98abd97353bd46ce30294bChris Craik    # only changing the chunk size, and not the type of file.
409ad0b04f54dab7c049e98abd97353bd46ce30294bChris Craik    assert not self._text_file
410ad0b04f54dab7c049e98abd97353bd46ce30294bChris Craik    assert chunk_size > 0
411ad0b04f54dab7c049e98abd97353bd46ce30294bChris Craik    self._chunk_size = chunk_size
412ad0b04f54dab7c049e98abd97353bd46ce30294bChris Craik
413ad0b04f54dab7c049e98abd97353bd46ce30294bChris Craik
414ad0b04f54dab7c049e98abd97353bd46ce30294bChris Craikdef get_default_categories(device_serial):
415ad0b04f54dab7c049e98abd97353bd46ce30294bChris Craik  categories_output, return_code = util.run_adb_shell(LIST_CATEGORIES_ARGS,
416ad0b04f54dab7c049e98abd97353bd46ce30294bChris Craik                                                    device_serial)
417ad0b04f54dab7c049e98abd97353bd46ce30294bChris Craik
418ad0b04f54dab7c049e98abd97353bd46ce30294bChris Craik  if return_code == 0 and categories_output:
419ad0b04f54dab7c049e98abd97353bd46ce30294bChris Craik    categories = [c.split('-')[0].strip()
420ad0b04f54dab7c049e98abd97353bd46ce30294bChris Craik                  for c in categories_output.splitlines()]
421ad0b04f54dab7c049e98abd97353bd46ce30294bChris Craik    return [c for c in categories if c in DEFAULT_CATEGORIES]
422ad0b04f54dab7c049e98abd97353bd46ce30294bChris Craik
423ad0b04f54dab7c049e98abd97353bd46ce30294bChris Craik  return []
424ad0b04f54dab7c049e98abd97353bd46ce30294bChris Craik
425ad0b04f54dab7c049e98abd97353bd46ce30294bChris Craik
426ad0b04f54dab7c049e98abd97353bd46ce30294bChris Craikdef status_update(last_update_time):
427ad0b04f54dab7c049e98abd97353bd46ce30294bChris Craik  current_time = time.time()
428ad0b04f54dab7c049e98abd97353bd46ce30294bChris Craik  if (current_time - last_update_time) >= MIN_TIME_BETWEEN_STATUS_UPDATES:
429ad0b04f54dab7c049e98abd97353bd46ce30294bChris Craik    # Gathering a trace may take a while.  Keep printing something so users
430ad0b04f54dab7c049e98abd97353bd46ce30294bChris Craik    # don't think the script has hung.
431ad0b04f54dab7c049e98abd97353bd46ce30294bChris Craik    sys.stdout.write('.')
432ad0b04f54dab7c049e98abd97353bd46ce30294bChris Craik    sys.stdout.flush()
433ad0b04f54dab7c049e98abd97353bd46ce30294bChris Craik    return current_time
434ad0b04f54dab7c049e98abd97353bd46ce30294bChris Craik
435ad0b04f54dab7c049e98abd97353bd46ce30294bChris Craik  return last_update_time
436ad0b04f54dab7c049e98abd97353bd46ce30294bChris Craik
437ad0b04f54dab7c049e98abd97353bd46ce30294bChris Craik
438ad0b04f54dab7c049e98abd97353bd46ce30294bChris Craikdef extract_thread_list(trace_data):
439ad0b04f54dab7c049e98abd97353bd46ce30294bChris Craik  """Removes the thread list from the given trace data.
440ad0b04f54dab7c049e98abd97353bd46ce30294bChris Craik
441ad0b04f54dab7c049e98abd97353bd46ce30294bChris Craik  Args:
442ad0b04f54dab7c049e98abd97353bd46ce30294bChris Craik    trace_data: The raw trace data (before decompression).
443ad0b04f54dab7c049e98abd97353bd46ce30294bChris Craik  Returns:
444ad0b04f54dab7c049e98abd97353bd46ce30294bChris Craik    A tuple containing the trace data and a map of thread ids to thread names.
445ad0b04f54dab7c049e98abd97353bd46ce30294bChris Craik  """
446ad0b04f54dab7c049e98abd97353bd46ce30294bChris Craik  threads = {}
447ad0b04f54dab7c049e98abd97353bd46ce30294bChris Craik  parts = re.split('USER +PID +PPID +VSIZE +RSS +WCHAN +PC +NAME',
448ad0b04f54dab7c049e98abd97353bd46ce30294bChris Craik                   trace_data, 1)
449ad0b04f54dab7c049e98abd97353bd46ce30294bChris Craik  if len(parts) == 2:
450ad0b04f54dab7c049e98abd97353bd46ce30294bChris Craik    trace_data = parts[0]
451ad0b04f54dab7c049e98abd97353bd46ce30294bChris Craik    for line in parts[1].splitlines():
452ad0b04f54dab7c049e98abd97353bd46ce30294bChris Craik      cols = line.split(None, 8)
453ad0b04f54dab7c049e98abd97353bd46ce30294bChris Craik      if len(cols) == 9:
454ad0b04f54dab7c049e98abd97353bd46ce30294bChris Craik        tid = int(cols[1])
455ad0b04f54dab7c049e98abd97353bd46ce30294bChris Craik        name = cols[8]
456ad0b04f54dab7c049e98abd97353bd46ce30294bChris Craik        threads[tid] = name
457ad0b04f54dab7c049e98abd97353bd46ce30294bChris Craik
458ad0b04f54dab7c049e98abd97353bd46ce30294bChris Craik  return (trace_data, threads)
459ad0b04f54dab7c049e98abd97353bd46ce30294bChris Craik
460ad0b04f54dab7c049e98abd97353bd46ce30294bChris Craik
461ad0b04f54dab7c049e98abd97353bd46ce30294bChris Craikdef strip_and_decompress_trace(trace_data):
462ad0b04f54dab7c049e98abd97353bd46ce30294bChris Craik  """Fixes new-lines and decompresses trace data.
463ad0b04f54dab7c049e98abd97353bd46ce30294bChris Craik
464ad0b04f54dab7c049e98abd97353bd46ce30294bChris Craik  Args:
465ad0b04f54dab7c049e98abd97353bd46ce30294bChris Craik    trace_data: The trace data returned by atrace.
466ad0b04f54dab7c049e98abd97353bd46ce30294bChris Craik  Returns:
467ad0b04f54dab7c049e98abd97353bd46ce30294bChris Craik    The decompressed trace data.
468ad0b04f54dab7c049e98abd97353bd46ce30294bChris Craik  """
469ad0b04f54dab7c049e98abd97353bd46ce30294bChris Craik  # Collapse CRLFs that are added by adb shell.
470ad0b04f54dab7c049e98abd97353bd46ce30294bChris Craik  if trace_data.startswith('\r\n'):
471ad0b04f54dab7c049e98abd97353bd46ce30294bChris Craik    trace_data = trace_data.replace('\r\n', '\n')
472ad0b04f54dab7c049e98abd97353bd46ce30294bChris Craik  elif trace_data.startswith('\r\r\n'):
473ad0b04f54dab7c049e98abd97353bd46ce30294bChris Craik    # On windows, adb adds an extra '\r' character for each line.
474ad0b04f54dab7c049e98abd97353bd46ce30294bChris Craik    trace_data = trace_data.replace('\r\r\n', '\n')
475ad0b04f54dab7c049e98abd97353bd46ce30294bChris Craik
476ad0b04f54dab7c049e98abd97353bd46ce30294bChris Craik  # Skip the initial newline.
477ad0b04f54dab7c049e98abd97353bd46ce30294bChris Craik  trace_data = trace_data[1:]
478ad0b04f54dab7c049e98abd97353bd46ce30294bChris Craik
479ad0b04f54dab7c049e98abd97353bd46ce30294bChris Craik  if not trace_data.startswith(TRACE_TEXT_HEADER):
480ad0b04f54dab7c049e98abd97353bd46ce30294bChris Craik    # No header found, so assume the data is compressed.
481ad0b04f54dab7c049e98abd97353bd46ce30294bChris Craik    trace_data = zlib.decompress(trace_data)
482ad0b04f54dab7c049e98abd97353bd46ce30294bChris Craik
483ad0b04f54dab7c049e98abd97353bd46ce30294bChris Craik  # Enforce Unix line-endings.
484ad0b04f54dab7c049e98abd97353bd46ce30294bChris Craik  trace_data = trace_data.replace('\r', '')
485ad0b04f54dab7c049e98abd97353bd46ce30294bChris Craik
486ad0b04f54dab7c049e98abd97353bd46ce30294bChris Craik  # Skip any initial newlines.
487ad0b04f54dab7c049e98abd97353bd46ce30294bChris Craik  while trace_data and trace_data[0] == '\n':
488ad0b04f54dab7c049e98abd97353bd46ce30294bChris Craik    trace_data = trace_data[1:]
489ad0b04f54dab7c049e98abd97353bd46ce30294bChris Craik
490ad0b04f54dab7c049e98abd97353bd46ce30294bChris Craik  return trace_data
491ad0b04f54dab7c049e98abd97353bd46ce30294bChris Craik
492ad0b04f54dab7c049e98abd97353bd46ce30294bChris Craik
493ad0b04f54dab7c049e98abd97353bd46ce30294bChris Craikdef fix_thread_names(trace_data, thread_names):
494ad0b04f54dab7c049e98abd97353bd46ce30294bChris Craik  """Replaces thread ids with their names.
495ad0b04f54dab7c049e98abd97353bd46ce30294bChris Craik
496ad0b04f54dab7c049e98abd97353bd46ce30294bChris Craik  Args:
497ad0b04f54dab7c049e98abd97353bd46ce30294bChris Craik    trace_data: The atrace data.
498ad0b04f54dab7c049e98abd97353bd46ce30294bChris Craik    thread_names: A mapping of thread ids to thread names.
499ad0b04f54dab7c049e98abd97353bd46ce30294bChris Craik  Returns:
500ad0b04f54dab7c049e98abd97353bd46ce30294bChris Craik    The updated trace data.
501ad0b04f54dab7c049e98abd97353bd46ce30294bChris Craik  """
502ad0b04f54dab7c049e98abd97353bd46ce30294bChris Craik  def repl(m):
503ad0b04f54dab7c049e98abd97353bd46ce30294bChris Craik    tid = int(m.group(2))
504ad0b04f54dab7c049e98abd97353bd46ce30294bChris Craik    if tid > 0:
505ad0b04f54dab7c049e98abd97353bd46ce30294bChris Craik      name = thread_names.get(tid)
506ad0b04f54dab7c049e98abd97353bd46ce30294bChris Craik      if name is None:
507ad0b04f54dab7c049e98abd97353bd46ce30294bChris Craik        name = m.group(1)
508ad0b04f54dab7c049e98abd97353bd46ce30294bChris Craik        if name == '<...>':
509ad0b04f54dab7c049e98abd97353bd46ce30294bChris Craik          name = '<' + str(tid) + '>'
510ad0b04f54dab7c049e98abd97353bd46ce30294bChris Craik        thread_names[tid] = name
511ad0b04f54dab7c049e98abd97353bd46ce30294bChris Craik      return name + '-' + m.group(2)
512ad0b04f54dab7c049e98abd97353bd46ce30294bChris Craik    else:
513ad0b04f54dab7c049e98abd97353bd46ce30294bChris Craik      return m.group(0)
514ad0b04f54dab7c049e98abd97353bd46ce30294bChris Craik  trace_data = re.sub(r'^\s*(\S+)-(\d+)', repl, trace_data,
515ad0b04f54dab7c049e98abd97353bd46ce30294bChris Craik                      flags=re.MULTILINE)
516ad0b04f54dab7c049e98abd97353bd46ce30294bChris Craik  return trace_data
517ad0b04f54dab7c049e98abd97353bd46ce30294bChris Craik
518ad0b04f54dab7c049e98abd97353bd46ce30294bChris Craik
519ad0b04f54dab7c049e98abd97353bd46ce30294bChris Craikdef fix_circular_traces(out):
520ad0b04f54dab7c049e98abd97353bd46ce30294bChris Craik  """Fix inconsistentcies in traces due to circular buffering.
521ad0b04f54dab7c049e98abd97353bd46ce30294bChris Craik
522ad0b04f54dab7c049e98abd97353bd46ce30294bChris Craik  The circular buffers are kept per CPU, so it is not guaranteed that the
523ad0b04f54dab7c049e98abd97353bd46ce30294bChris Craik  beginning of a slice is overwritten before the end. To work around this, we
524ad0b04f54dab7c049e98abd97353bd46ce30294bChris Craik  throw away the prefix of the trace where not all CPUs have events yet.
525ad0b04f54dab7c049e98abd97353bd46ce30294bChris Craik
526ad0b04f54dab7c049e98abd97353bd46ce30294bChris Craik  Args:
527ad0b04f54dab7c049e98abd97353bd46ce30294bChris Craik    out: The data to fix.
528ad0b04f54dab7c049e98abd97353bd46ce30294bChris Craik  Returns:
529ad0b04f54dab7c049e98abd97353bd46ce30294bChris Craik    The updated trace data.
530ad0b04f54dab7c049e98abd97353bd46ce30294bChris Craik  """
531ad0b04f54dab7c049e98abd97353bd46ce30294bChris Craik  # If any of the CPU's buffers have filled up and
532ad0b04f54dab7c049e98abd97353bd46ce30294bChris Craik  # older events have been dropped, the kernel
533ad0b04f54dab7c049e98abd97353bd46ce30294bChris Craik  # emits markers of the form '##### CPU 2 buffer started ####' on
534ad0b04f54dab7c049e98abd97353bd46ce30294bChris Craik  # the line before the first event in the trace on that CPU.
535ad0b04f54dab7c049e98abd97353bd46ce30294bChris Craik  #
536ad0b04f54dab7c049e98abd97353bd46ce30294bChris Craik  # No such headers are emitted if there were no overflows or the trace
537ad0b04f54dab7c049e98abd97353bd46ce30294bChris Craik  # was captured with non-circular buffers.
538ad0b04f54dab7c049e98abd97353bd46ce30294bChris Craik  buffer_start_re = re.compile(r'^#+ CPU \d+ buffer started', re.MULTILINE)
539ad0b04f54dab7c049e98abd97353bd46ce30294bChris Craik
540ad0b04f54dab7c049e98abd97353bd46ce30294bChris Craik  start_of_full_trace = 0
541ad0b04f54dab7c049e98abd97353bd46ce30294bChris Craik
542ad0b04f54dab7c049e98abd97353bd46ce30294bChris Craik  while True:
543ad0b04f54dab7c049e98abd97353bd46ce30294bChris Craik    result = buffer_start_re.search(out, start_of_full_trace + 1)
544ad0b04f54dab7c049e98abd97353bd46ce30294bChris Craik    if result:
545ad0b04f54dab7c049e98abd97353bd46ce30294bChris Craik      start_of_full_trace = result.start()
546ad0b04f54dab7c049e98abd97353bd46ce30294bChris Craik    else:
547ad0b04f54dab7c049e98abd97353bd46ce30294bChris Craik      break
548ad0b04f54dab7c049e98abd97353bd46ce30294bChris Craik
549ad0b04f54dab7c049e98abd97353bd46ce30294bChris Craik  if start_of_full_trace > 0:
550ad0b04f54dab7c049e98abd97353bd46ce30294bChris Craik    # Need to keep the header intact to make the importer happy.
551ad0b04f54dab7c049e98abd97353bd46ce30294bChris Craik    end_of_header = re.search(r'^[^#]', out, re.MULTILINE).start()
552ad0b04f54dab7c049e98abd97353bd46ce30294bChris Craik    out = out[:end_of_header] + out[start_of_full_trace:]
553ad0b04f54dab7c049e98abd97353bd46ce30294bChris Craik  return out
554