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