1*288bf522SAndroid Build Coastguard Worker#!/usr/bin/python3 2*288bf522SAndroid Build Coastguard Worker 3*288bf522SAndroid Build Coastguard Worker# Copyright (C) 2016 The Android Open Source Project 4*288bf522SAndroid Build Coastguard Worker# 5*288bf522SAndroid Build Coastguard Worker# Licensed under the Apache License, Version 2.0 (the "License"); 6*288bf522SAndroid Build Coastguard Worker# you may not use this file except in compliance with the License. 7*288bf522SAndroid Build Coastguard Worker# You may obtain a copy of the License at 8*288bf522SAndroid Build Coastguard Worker# 9*288bf522SAndroid Build Coastguard Worker# http://www.apache.org/licenses/LICENSE-2.0 10*288bf522SAndroid Build Coastguard Worker# 11*288bf522SAndroid Build Coastguard Worker# Unless required by applicable law or agreed to in writing, software 12*288bf522SAndroid Build Coastguard Worker# distributed under the License is distributed on an "AS IS" BASIS, 13*288bf522SAndroid Build Coastguard Worker# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14*288bf522SAndroid Build Coastguard Worker# See the License for the specific language governing permissions and 15*288bf522SAndroid Build Coastguard Worker# limitations under the License. 16*288bf522SAndroid Build Coastguard Worker# 17*288bf522SAndroid Build Coastguard Worker"""Tool to analyze logcat and dmesg logs. 18*288bf522SAndroid Build Coastguard Worker 19*288bf522SAndroid Build Coastguard Workerbootanalyze read logcat and dmesg logs and determines key points for boot. 20*288bf522SAndroid Build Coastguard Worker""" 21*288bf522SAndroid Build Coastguard Worker 22*288bf522SAndroid Build Coastguard Workerimport argparse 23*288bf522SAndroid Build Coastguard Workerimport collections 24*288bf522SAndroid Build Coastguard Workerimport datetime 25*288bf522SAndroid Build Coastguard Workerimport math 26*288bf522SAndroid Build Coastguard Workerimport operator 27*288bf522SAndroid Build Coastguard Workerimport os 28*288bf522SAndroid Build Coastguard Workerimport re 29*288bf522SAndroid Build Coastguard Workerimport select 30*288bf522SAndroid Build Coastguard Workerimport subprocess 31*288bf522SAndroid Build Coastguard Workerimport time 32*288bf522SAndroid Build Coastguard Workerimport threading 33*288bf522SAndroid Build Coastguard Workerimport yaml 34*288bf522SAndroid Build Coastguard Worker 35*288bf522SAndroid Build Coastguard Workerfrom datetime import datetime 36*288bf522SAndroid Build Coastguard Worker 37*288bf522SAndroid Build Coastguard WorkerTIME_DMESG = r"\[\s*(\d+\.\d+)\]" 38*288bf522SAndroid Build Coastguard WorkerTIME_LOGCAT = r"[0-9]+\.?[0-9]*" 39*288bf522SAndroid Build Coastguard WorkerKERNEL_TIME_KEY = "kernel" 40*288bf522SAndroid Build Coastguard WorkerBOOT_ANIM_END_TIME_KEY = "BootAnimEnd" 41*288bf522SAndroid Build Coastguard WorkerKERNEL_BOOT_COMPLETE = "BootComplete_kernel" 42*288bf522SAndroid Build Coastguard WorkerLOGCAT_BOOT_COMPLETE = "BootComplete" 43*288bf522SAndroid Build Coastguard WorkerANDROID_INIT_SECOND_STAGE = "android_init_2st_stage" 44*288bf522SAndroid Build Coastguard WorkerCARWATCHDOG_BOOT_COMPLETE = "CarWatchdogBootupProfilingComplete" 45*288bf522SAndroid Build Coastguard WorkerLAUNCHER_START = "LauncherStart" 46*288bf522SAndroid Build Coastguard WorkerCARWATCHDOG_DUMP_COMMAND = "adb shell dumpsys android.automotive.watchdog.ICarWatchdog/default" 47*288bf522SAndroid Build Coastguard WorkerBOOT_TIME_TOO_BIG = 200.0 48*288bf522SAndroid Build Coastguard WorkerMAX_RETRIES = 5 49*288bf522SAndroid Build Coastguard WorkerDEBUG = False 50*288bf522SAndroid Build Coastguard WorkerDEBUG_PATTERN = False 51*288bf522SAndroid Build Coastguard WorkerADB_CMD = "adb" 52*288bf522SAndroid Build Coastguard WorkerTIMING_THRESHOLD = 5.0 53*288bf522SAndroid Build Coastguard WorkerBOOT_PROP = r"\[ro\.boottime\.([^\]]+)\]:\s+\[(\d+)\]" 54*288bf522SAndroid Build Coastguard WorkerBOOTLOADER_TIME_PROP = r"\[ro\.boot\.boottime\]:\s+\[([^\]]+)\]" 55*288bf522SAndroid Build Coastguard WorkerCARWATCHDOG_PARSER_CMD = 'perf_stats_parser' 56*288bf522SAndroid Build Coastguard Worker 57*288bf522SAndroid Build Coastguard Workermax_wait_time = BOOT_TIME_TOO_BIG 58*288bf522SAndroid Build Coastguard Worker 59*288bf522SAndroid Build Coastguard Workerdef main(): 60*288bf522SAndroid Build Coastguard Worker global ADB_CMD 61*288bf522SAndroid Build Coastguard Worker 62*288bf522SAndroid Build Coastguard Worker args = init_arguments() 63*288bf522SAndroid Build Coastguard Worker 64*288bf522SAndroid Build Coastguard Worker if args.iterate < 1: 65*288bf522SAndroid Build Coastguard Worker raise Exception('Number of iteration must be >=1') 66*288bf522SAndroid Build Coastguard Worker 67*288bf522SAndroid Build Coastguard Worker if args.iterate > 1 and not args.reboot: 68*288bf522SAndroid Build Coastguard Worker print("Forcing reboot flag") 69*288bf522SAndroid Build Coastguard Worker args.reboot = True 70*288bf522SAndroid Build Coastguard Worker 71*288bf522SAndroid Build Coastguard Worker if args.serial: 72*288bf522SAndroid Build Coastguard Worker ADB_CMD = "%s %s" % ("adb -s", args.serial) 73*288bf522SAndroid Build Coastguard Worker 74*288bf522SAndroid Build Coastguard Worker error_time = BOOT_TIME_TOO_BIG * 10 75*288bf522SAndroid Build Coastguard Worker if args.errortime: 76*288bf522SAndroid Build Coastguard Worker error_time = float(args.errortime) 77*288bf522SAndroid Build Coastguard Worker if args.maxwaittime: 78*288bf522SAndroid Build Coastguard Worker global max_wait_time 79*288bf522SAndroid Build Coastguard Worker max_wait_time = float(args.maxwaittime) 80*288bf522SAndroid Build Coastguard Worker 81*288bf522SAndroid Build Coastguard Worker components_to_monitor = {} 82*288bf522SAndroid Build Coastguard Worker if args.componentmonitor: 83*288bf522SAndroid Build Coastguard Worker items = args.componentmonitor.split(",") 84*288bf522SAndroid Build Coastguard Worker for item in items: 85*288bf522SAndroid Build Coastguard Worker kv = item.split("=") 86*288bf522SAndroid Build Coastguard Worker key = kv[0] 87*288bf522SAndroid Build Coastguard Worker value = float(kv[1]) 88*288bf522SAndroid Build Coastguard Worker components_to_monitor[key] = value 89*288bf522SAndroid Build Coastguard Worker 90*288bf522SAndroid Build Coastguard Worker cfg = yaml.load(args.config, Loader=yaml.SafeLoader) 91*288bf522SAndroid Build Coastguard Worker 92*288bf522SAndroid Build Coastguard Worker if args.stressfs: 93*288bf522SAndroid Build Coastguard Worker if run_adb_cmd('install -r -g ' + args.stressfs) != 0: 94*288bf522SAndroid Build Coastguard Worker raise Exception('StressFS APK not installed') 95*288bf522SAndroid Build Coastguard Worker 96*288bf522SAndroid Build Coastguard Worker if args.iterate > 1 and args.bootchart: 97*288bf522SAndroid Build Coastguard Worker run_adb_shell_cmd_as_root('touch /data/bootchart/enabled') 98*288bf522SAndroid Build Coastguard Worker 99*288bf522SAndroid Build Coastguard Worker search_events_pattern = {key: re.compile(pattern) 100*288bf522SAndroid Build Coastguard Worker for key, pattern in cfg['events'].items()} 101*288bf522SAndroid Build Coastguard Worker timing_events_pattern = {key: re.compile(pattern) 102*288bf522SAndroid Build Coastguard Worker for key, pattern in cfg['timings'].items()} 103*288bf522SAndroid Build Coastguard Worker shutdown_events_pattern = {key: re.compile(pattern) 104*288bf522SAndroid Build Coastguard Worker for key, pattern in cfg['shutdown_events'].items()} 105*288bf522SAndroid Build Coastguard Worker if DEBUG_PATTERN: 106*288bf522SAndroid Build Coastguard Worker print("search event:{} timing event:{}".format(search_events_pattern, timing_events_pattern)) 107*288bf522SAndroid Build Coastguard Worker 108*288bf522SAndroid Build Coastguard Worker now = datetime.now().strftime("%Y-%m-%d-%H-%M-%S") 109*288bf522SAndroid Build Coastguard Worker boot_chart_file_path_prefix = "bootchart-" + now 110*288bf522SAndroid Build Coastguard Worker systrace_file_path_prefix = "systrace-" + now 111*288bf522SAndroid Build Coastguard Worker 112*288bf522SAndroid Build Coastguard Worker if args.output: 113*288bf522SAndroid Build Coastguard Worker boot_chart_file_path_prefix = args.output + '/' + boot_chart_file_path_prefix 114*288bf522SAndroid Build Coastguard Worker systrace_file_path_prefix = args.output + '/' + systrace_file_path_prefix 115*288bf522SAndroid Build Coastguard Worker 116*288bf522SAndroid Build Coastguard Worker data_points = {} 117*288bf522SAndroid Build Coastguard Worker kernel_timing_points = collections.OrderedDict() 118*288bf522SAndroid Build Coastguard Worker logcat_timing_points = collections.OrderedDict() 119*288bf522SAndroid Build Coastguard Worker boottime_points = collections.OrderedDict() 120*288bf522SAndroid Build Coastguard Worker shutdown_event_all = collections.OrderedDict() 121*288bf522SAndroid Build Coastguard Worker shutdown_timing_event_all = collections.OrderedDict() 122*288bf522SAndroid Build Coastguard Worker for it in range(0, args.iterate): 123*288bf522SAndroid Build Coastguard Worker if args.iterate > 1: 124*288bf522SAndroid Build Coastguard Worker print("Run: {0}".format(it)) 125*288bf522SAndroid Build Coastguard Worker attempt = 1 126*288bf522SAndroid Build Coastguard Worker processing_data = None 127*288bf522SAndroid Build Coastguard Worker timings = None 128*288bf522SAndroid Build Coastguard Worker boottime_events = None 129*288bf522SAndroid Build Coastguard Worker while attempt <= MAX_RETRIES and processing_data is None: 130*288bf522SAndroid Build Coastguard Worker attempt += 1 131*288bf522SAndroid Build Coastguard Worker processing_data, kernel_timings, logcat_timings, boottime_events, shutdown_events,\ 132*288bf522SAndroid Build Coastguard Worker shutdown_timing_events = iterate(\ 133*288bf522SAndroid Build Coastguard Worker args, search_events_pattern, timing_events_pattern, shutdown_events_pattern, cfg,\ 134*288bf522SAndroid Build Coastguard Worker error_time, components_to_monitor) 135*288bf522SAndroid Build Coastguard Worker if shutdown_events: 136*288bf522SAndroid Build Coastguard Worker for k, v in shutdown_events.items(): 137*288bf522SAndroid Build Coastguard Worker events = shutdown_event_all.get(k) 138*288bf522SAndroid Build Coastguard Worker if not events: 139*288bf522SAndroid Build Coastguard Worker events = [] 140*288bf522SAndroid Build Coastguard Worker shutdown_event_all[k] = events 141*288bf522SAndroid Build Coastguard Worker events.append(v) 142*288bf522SAndroid Build Coastguard Worker if shutdown_timing_events: 143*288bf522SAndroid Build Coastguard Worker for k, v in shutdown_timing_events.items(): 144*288bf522SAndroid Build Coastguard Worker events = shutdown_timing_event_all.get(k) 145*288bf522SAndroid Build Coastguard Worker if not events: 146*288bf522SAndroid Build Coastguard Worker events = [] 147*288bf522SAndroid Build Coastguard Worker shutdown_timing_event_all[k] = events 148*288bf522SAndroid Build Coastguard Worker events.append(v) 149*288bf522SAndroid Build Coastguard Worker if not processing_data or not boottime_events: 150*288bf522SAndroid Build Coastguard Worker # Processing error 151*288bf522SAndroid Build Coastguard Worker print("Failed to collect valid samples for run {0}".format(it)) 152*288bf522SAndroid Build Coastguard Worker continue 153*288bf522SAndroid Build Coastguard Worker 154*288bf522SAndroid Build Coastguard Worker if args.bootchart: 155*288bf522SAndroid Build Coastguard Worker grab_bootchart(boot_chart_file_path_prefix + "_run_" + str(it)) 156*288bf522SAndroid Build Coastguard Worker 157*288bf522SAndroid Build Coastguard Worker if args.systrace: 158*288bf522SAndroid Build Coastguard Worker grab_systrace(systrace_file_path_prefix + "_run_" + str(it)) 159*288bf522SAndroid Build Coastguard Worker 160*288bf522SAndroid Build Coastguard Worker if args.carwatchdog: 161*288bf522SAndroid Build Coastguard Worker grab_carwatchdog_bootstats(args.output) 162*288bf522SAndroid Build Coastguard Worker 163*288bf522SAndroid Build Coastguard Worker for k, v in processing_data.items(): 164*288bf522SAndroid Build Coastguard Worker if k not in data_points: 165*288bf522SAndroid Build Coastguard Worker data_points[k] = [] 166*288bf522SAndroid Build Coastguard Worker data_points[k].append(v['value']) 167*288bf522SAndroid Build Coastguard Worker 168*288bf522SAndroid Build Coastguard Worker if kernel_timings is not None: 169*288bf522SAndroid Build Coastguard Worker for k, v in kernel_timings.items(): 170*288bf522SAndroid Build Coastguard Worker if k not in kernel_timing_points: 171*288bf522SAndroid Build Coastguard Worker kernel_timing_points[k] = [] 172*288bf522SAndroid Build Coastguard Worker kernel_timing_points[k].append(v) 173*288bf522SAndroid Build Coastguard Worker if logcat_timings is not None: 174*288bf522SAndroid Build Coastguard Worker for k, v in logcat_timings.items(): 175*288bf522SAndroid Build Coastguard Worker if k not in logcat_timing_points: 176*288bf522SAndroid Build Coastguard Worker logcat_timing_points[k] = [] 177*288bf522SAndroid Build Coastguard Worker logcat_timing_points[k].append(v) 178*288bf522SAndroid Build Coastguard Worker 179*288bf522SAndroid Build Coastguard Worker for k, v in boottime_events.items(): 180*288bf522SAndroid Build Coastguard Worker if k not in boottime_points: 181*288bf522SAndroid Build Coastguard Worker boottime_points[k] = [] 182*288bf522SAndroid Build Coastguard Worker boottime_points[k].append(v) 183*288bf522SAndroid Build Coastguard Worker 184*288bf522SAndroid Build Coastguard Worker if args.stressfs: 185*288bf522SAndroid Build Coastguard Worker run_adb_cmd('uninstall com.android.car.test.stressfs') 186*288bf522SAndroid Build Coastguard Worker run_adb_shell_cmd('"rm -rf /storage/emulated/0/stressfs_data*"') 187*288bf522SAndroid Build Coastguard Worker 188*288bf522SAndroid Build Coastguard Worker if args.iterate > 1: 189*288bf522SAndroid Build Coastguard Worker print("-----------------") 190*288bf522SAndroid Build Coastguard Worker print("\nshutdown events after {0} runs".format(args.iterate)) 191*288bf522SAndroid Build Coastguard Worker print('{0:30}: {1:<7} {2:<7} {3}'.format("Event", "Mean", "stddev", "#runs")) 192*288bf522SAndroid Build Coastguard Worker for item in list(shutdown_event_all.items()): 193*288bf522SAndroid Build Coastguard Worker num_runs = len(item[1]) 194*288bf522SAndroid Build Coastguard Worker print('{0:30}: {1:<7.5} {2:<7.5} {3} {4}'.format( 195*288bf522SAndroid Build Coastguard Worker item[0], sum(item[1])/num_runs, stddev(item[1]),\ 196*288bf522SAndroid Build Coastguard Worker "*time taken" if item[0].startswith("init.") else "",\ 197*288bf522SAndroid Build Coastguard Worker num_runs if num_runs != args.iterate else "")) 198*288bf522SAndroid Build Coastguard Worker print("\nshutdown timing events after {0} runs".format(args.iterate)) 199*288bf522SAndroid Build Coastguard Worker print('{0:30}: {1:<7} {2:<7} {3}'.format("Event", "Mean", "stddev", "#runs")) 200*288bf522SAndroid Build Coastguard Worker for item in list(shutdown_timing_event_all.items()): 201*288bf522SAndroid Build Coastguard Worker num_runs = len(item[1]) 202*288bf522SAndroid Build Coastguard Worker print('{0:30}: {1:<7.5} {2:<7.5} {3} {4}'.format( 203*288bf522SAndroid Build Coastguard Worker item[0], sum(item[1])/num_runs, stddev(item[1]),\ 204*288bf522SAndroid Build Coastguard Worker "*time taken" if item[0].startswith("init.") else "",\ 205*288bf522SAndroid Build Coastguard Worker num_runs if num_runs != args.iterate else "")) 206*288bf522SAndroid Build Coastguard Worker 207*288bf522SAndroid Build Coastguard Worker print("-----------------") 208*288bf522SAndroid Build Coastguard Worker print("ro.boottime.* after {0} runs".format(args.iterate)) 209*288bf522SAndroid Build Coastguard Worker print('{0:30}: {1:<7} {2:<7} {3}'.format("Event", "Mean", "stddev", "#runs")) 210*288bf522SAndroid Build Coastguard Worker for item in list(boottime_points.items()): 211*288bf522SAndroid Build Coastguard Worker num_runs = len(item[1]) 212*288bf522SAndroid Build Coastguard Worker print('{0:30}: {1:<7.5} {2:<7.5} {3} {4}'.format( 213*288bf522SAndroid Build Coastguard Worker item[0], sum(item[1])/num_runs, stddev(item[1]),\ 214*288bf522SAndroid Build Coastguard Worker "*time taken" if item[0].startswith("init.") else "",\ 215*288bf522SAndroid Build Coastguard Worker num_runs if num_runs != args.iterate else "")) 216*288bf522SAndroid Build Coastguard Worker 217*288bf522SAndroid Build Coastguard Worker if args.timings: 218*288bf522SAndroid Build Coastguard Worker dump_timings_points_summary("Kernel", kernel_timing_points, args) 219*288bf522SAndroid Build Coastguard Worker dump_timings_points_summary("Logcat", logcat_timing_points, args) 220*288bf522SAndroid Build Coastguard Worker 221*288bf522SAndroid Build Coastguard Worker 222*288bf522SAndroid Build Coastguard Worker print("-----------------") 223*288bf522SAndroid Build Coastguard Worker print("Avg values after {0} runs".format(args.iterate)) 224*288bf522SAndroid Build Coastguard Worker print('{0:30}: {1:<7} {2:<7} {3}'.format("Event", "Mean", "stddev", "#runs")) 225*288bf522SAndroid Build Coastguard Worker 226*288bf522SAndroid Build Coastguard Worker average_with_stddev = [] 227*288bf522SAndroid Build Coastguard Worker for item in list(data_points.items()): 228*288bf522SAndroid Build Coastguard Worker average_with_stddev.append((item[0], sum(item[1])/len(item[1]), stddev(item[1]),\ 229*288bf522SAndroid Build Coastguard Worker len(item[1]))) 230*288bf522SAndroid Build Coastguard Worker for item in sorted(average_with_stddev, key=lambda entry: entry[1]): 231*288bf522SAndroid Build Coastguard Worker print('{0:30}: {1:<7.5} {2:<7.5} {3}'.format( 232*288bf522SAndroid Build Coastguard Worker item[0], item[1], item[2], item[3] if item[3] != args.iterate else "")) 233*288bf522SAndroid Build Coastguard Worker 234*288bf522SAndroid Build Coastguard Worker run_adb_shell_cmd_as_root('rm /data/bootchart/enabled') 235*288bf522SAndroid Build Coastguard Worker 236*288bf522SAndroid Build Coastguard Worker 237*288bf522SAndroid Build Coastguard Workerdef dump_timings_points_summary(msg_header, timing_points, args): 238*288bf522SAndroid Build Coastguard Worker averaged_timing_points = [] 239*288bf522SAndroid Build Coastguard Worker for item in list(timing_points.items()): 240*288bf522SAndroid Build Coastguard Worker average = sum(item[1])/len(item[1]) 241*288bf522SAndroid Build Coastguard Worker std_dev = stddev(item[1]) 242*288bf522SAndroid Build Coastguard Worker averaged_timing_points.append((item[0], average, std_dev, len(item[1]))) 243*288bf522SAndroid Build Coastguard Worker 244*288bf522SAndroid Build Coastguard Worker print("-----------------") 245*288bf522SAndroid Build Coastguard Worker print(msg_header + " timing in order, Avg time values after {0} runs".format(args.iterate)) 246*288bf522SAndroid Build Coastguard Worker print('{0:30}: {1:<7} {2:<7} {3}'.format("Event", "Mean", "stddev", "#runs")) 247*288bf522SAndroid Build Coastguard Worker for item in averaged_timing_points: 248*288bf522SAndroid Build Coastguard Worker print('{0:30}: {1:<7.5} {2:<7.5} {3}'.format( 249*288bf522SAndroid Build Coastguard Worker item[0], item[1], item[2], item[3] if item[3] != args.iterate else "")) 250*288bf522SAndroid Build Coastguard Worker 251*288bf522SAndroid Build Coastguard Worker print("-----------------") 252*288bf522SAndroid Build Coastguard Worker print(msg_header + " timing top items, Avg time values after {0} runs".format(args.iterate)) 253*288bf522SAndroid Build Coastguard Worker print('{0:30}: {1:<7} {2:<7} {3}'.format("Event", "Mean", "stddev", "#runs")) 254*288bf522SAndroid Build Coastguard Worker for item in sorted(averaged_timing_points, key=lambda entry: entry[1], reverse=True): 255*288bf522SAndroid Build Coastguard Worker if item[1] < TIMING_THRESHOLD: 256*288bf522SAndroid Build Coastguard Worker break 257*288bf522SAndroid Build Coastguard Worker print('{0:30}: {1:<7.5} {2:<7.5} {3}'.format( 258*288bf522SAndroid Build Coastguard Worker item[0], item[1], item[2], item[3] if item[3] != args.iterate else "")) 259*288bf522SAndroid Build Coastguard Worker 260*288bf522SAndroid Build Coastguard Workerdef capture_bugreport(bugreport_hint, boot_complete_time): 261*288bf522SAndroid Build Coastguard Worker now = datetime.now() 262*288bf522SAndroid Build Coastguard Worker bugreport_file = ("bugreport-%s-" + bugreport_hint + "-%s.zip") \ 263*288bf522SAndroid Build Coastguard Worker % (now.strftime("%Y-%m-%d-%H-%M-%S"), str(boot_complete_time)) 264*288bf522SAndroid Build Coastguard Worker print("Boot up time too big, will capture bugreport %s" % (bugreport_file)) 265*288bf522SAndroid Build Coastguard Worker os.system(ADB_CMD + " bugreport " + bugreport_file) 266*288bf522SAndroid Build Coastguard Worker 267*288bf522SAndroid Build Coastguard Workerdef generate_timing_points(timing_events, timings): 268*288bf522SAndroid Build Coastguard Worker timing_points = collections.OrderedDict() 269*288bf522SAndroid Build Coastguard Worker monitor_contention_points = collections.OrderedDict() 270*288bf522SAndroid Build Coastguard Worker for k, l in timing_events.items(): 271*288bf522SAndroid Build Coastguard Worker for v in l: 272*288bf522SAndroid Build Coastguard Worker name, time_v = extract_timing(v, timings) 273*288bf522SAndroid Build Coastguard Worker if name and time_v: 274*288bf522SAndroid Build Coastguard Worker if v.find("SystemServerTimingAsync") > 0: 275*288bf522SAndroid Build Coastguard Worker name = "(" + name + ")" 276*288bf522SAndroid Build Coastguard Worker if k.endswith("_secs"): 277*288bf522SAndroid Build Coastguard Worker time_v = time_v * 1000.0 278*288bf522SAndroid Build Coastguard Worker if k.startswith("long_monitor_contention"): 279*288bf522SAndroid Build Coastguard Worker monitor_contention_points[v] = time_v 280*288bf522SAndroid Build Coastguard Worker continue 281*288bf522SAndroid Build Coastguard Worker new_name = name 282*288bf522SAndroid Build Coastguard Worker name_index = 0 283*288bf522SAndroid Build Coastguard Worker while timing_points.get(new_name): # if the name is already taken, append #digit 284*288bf522SAndroid Build Coastguard Worker name_index += 1 285*288bf522SAndroid Build Coastguard Worker new_name = name + "#" + str(name_index) 286*288bf522SAndroid Build Coastguard Worker timing_points[new_name] = time_v 287*288bf522SAndroid Build Coastguard Worker return timing_points, monitor_contention_points 288*288bf522SAndroid Build Coastguard Worker 289*288bf522SAndroid Build Coastguard Workerdef dump_timing_points(msg_header, timing_points): 290*288bf522SAndroid Build Coastguard Worker print(msg_header + " event timing in time order, key: time") 291*288bf522SAndroid Build Coastguard Worker for item in list(timing_points.items()): 292*288bf522SAndroid Build Coastguard Worker print('{0:30}: {1:<7.5}'.format(item[0], item[1])) 293*288bf522SAndroid Build Coastguard Worker print("-----------------") 294*288bf522SAndroid Build Coastguard Worker print(msg_header + " event timing top items") 295*288bf522SAndroid Build Coastguard Worker for item in sorted(list(timing_points.items()), key=operator.itemgetter(1), reverse=True): 296*288bf522SAndroid Build Coastguard Worker if item[1] < TIMING_THRESHOLD: 297*288bf522SAndroid Build Coastguard Worker break 298*288bf522SAndroid Build Coastguard Worker print('{0:30}: {1:<7.5}'.format( 299*288bf522SAndroid Build Coastguard Worker item[0], item[1])) 300*288bf522SAndroid Build Coastguard Worker print("-----------------") 301*288bf522SAndroid Build Coastguard Worker 302*288bf522SAndroid Build Coastguard Workerdef dump_monitor_contentions(logcat_monitor_contentions): 303*288bf522SAndroid Build Coastguard Worker print("Monitor contentions over 100ms:") 304*288bf522SAndroid Build Coastguard Worker for item in list(logcat_monitor_contentions.items()): 305*288bf522SAndroid Build Coastguard Worker if item[1] > 100: 306*288bf522SAndroid Build Coastguard Worker print('{0:<7.5}ms: {1}'.format(item[1], item[0])) 307*288bf522SAndroid Build Coastguard Worker print("-----------------") 308*288bf522SAndroid Build Coastguard Worker 309*288bf522SAndroid Build Coastguard Workerdef handle_reboot_log(capture_log_on_error, shutdown_events_pattern, components_to_monitor): 310*288bf522SAndroid Build Coastguard Worker shutdown_events, shutdown_timing_events = collect_logcat_for_shutdown(capture_log_on_error,\ 311*288bf522SAndroid Build Coastguard Worker shutdown_events_pattern, components_to_monitor) 312*288bf522SAndroid Build Coastguard Worker print("\nshutdown events: time") 313*288bf522SAndroid Build Coastguard Worker for item in list(shutdown_events.items()): 314*288bf522SAndroid Build Coastguard Worker print('{0:30}: {1:<7.5}'.format(item[0], item[1])) 315*288bf522SAndroid Build Coastguard Worker print("\nshutdown timing events: time") 316*288bf522SAndroid Build Coastguard Worker for item in list(shutdown_timing_events.items()): 317*288bf522SAndroid Build Coastguard Worker print('{0:30}: {1:<7.5}'.format(item[0], item[1])) 318*288bf522SAndroid Build Coastguard Worker return shutdown_events, shutdown_timing_events 319*288bf522SAndroid Build Coastguard Worker 320*288bf522SAndroid Build Coastguard Workerdef collect_dmesg_events(search_events_pattern, timings_pattern, results): 321*288bf522SAndroid Build Coastguard Worker dmesg_events, kernel_timing_events = collect_events(search_events_pattern, ADB_CMD +\ 322*288bf522SAndroid Build Coastguard Worker ' shell su root dmesg -w', timings_pattern, 323*288bf522SAndroid Build Coastguard Worker [ 324*288bf522SAndroid Build Coastguard Worker KERNEL_BOOT_COMPLETE, 325*288bf522SAndroid Build Coastguard Worker ANDROID_INIT_SECOND_STAGE 326*288bf522SAndroid Build Coastguard Worker ], 327*288bf522SAndroid Build Coastguard Worker False, True) 328*288bf522SAndroid Build Coastguard Worker results.append(dmesg_events) 329*288bf522SAndroid Build Coastguard Worker results.append(kernel_timing_events) 330*288bf522SAndroid Build Coastguard Worker 331*288bf522SAndroid Build Coastguard Workerdef iterate(args, search_events_pattern, timings_pattern, shutdown_events_pattern, cfg, error_time,\ 332*288bf522SAndroid Build Coastguard Worker components_to_monitor): 333*288bf522SAndroid Build Coastguard Worker shutdown_events = None 334*288bf522SAndroid Build Coastguard Worker shutdown_timing_events = None 335*288bf522SAndroid Build Coastguard Worker if args.reboot: 336*288bf522SAndroid Build Coastguard Worker # sleep to make sure that logcat reader is reading before adb is gone by reboot. ugly but make 337*288bf522SAndroid Build Coastguard Worker # impl simple. 338*288bf522SAndroid Build Coastguard Worker t = threading.Thread(target=lambda: (time.sleep(2), reboot(args.serial, args.stressfs != '',\ 339*288bf522SAndroid Build Coastguard Worker args.permissive, args.adb_reboot, args.buffersize))) 340*288bf522SAndroid Build Coastguard Worker t.start() 341*288bf522SAndroid Build Coastguard Worker shutdown_events, shutdown_timing_events = handle_reboot_log(True, shutdown_events_pattern,\ 342*288bf522SAndroid Build Coastguard Worker components_to_monitor) 343*288bf522SAndroid Build Coastguard Worker t.join() 344*288bf522SAndroid Build Coastguard Worker 345*288bf522SAndroid Build Coastguard Worker results = [] 346*288bf522SAndroid Build Coastguard Worker t = threading.Thread(target=collect_dmesg_events, args=(search_events_pattern,\ 347*288bf522SAndroid Build Coastguard Worker timings_pattern, results)) 348*288bf522SAndroid Build Coastguard Worker t.start() 349*288bf522SAndroid Build Coastguard Worker 350*288bf522SAndroid Build Coastguard Worker logcat_stop_events = [LOGCAT_BOOT_COMPLETE, LAUNCHER_START] 351*288bf522SAndroid Build Coastguard Worker if args.fs_check: 352*288bf522SAndroid Build Coastguard Worker logcat_stop_events.append("FsStat") 353*288bf522SAndroid Build Coastguard Worker if args.carwatchdog: 354*288bf522SAndroid Build Coastguard Worker logcat_stop_events.append(CARWATCHDOG_BOOT_COMPLETE) 355*288bf522SAndroid Build Coastguard Worker logcat_events, logcat_timing_events = collect_events( 356*288bf522SAndroid Build Coastguard Worker search_events_pattern, ADB_CMD + ' logcat -b all -v epoch', timings_pattern,\ 357*288bf522SAndroid Build Coastguard Worker logcat_stop_events, True, False) 358*288bf522SAndroid Build Coastguard Worker 359*288bf522SAndroid Build Coastguard Worker t.join() 360*288bf522SAndroid Build Coastguard Worker dmesg_events = results[0] 361*288bf522SAndroid Build Coastguard Worker kernel_timing_events = results[1] 362*288bf522SAndroid Build Coastguard Worker 363*288bf522SAndroid Build Coastguard Worker logcat_event_time = extract_time(logcat_events, TIME_LOGCAT, float) 364*288bf522SAndroid Build Coastguard Worker logcat_original_time = extract_time(logcat_events, TIME_LOGCAT, str); 365*288bf522SAndroid Build Coastguard Worker dmesg_event_time = extract_time(dmesg_events, TIME_DMESG, float); 366*288bf522SAndroid Build Coastguard Worker boottime_events = fetch_boottime_property() 367*288bf522SAndroid Build Coastguard Worker events = {} 368*288bf522SAndroid Build Coastguard Worker events_to_correct = [] 369*288bf522SAndroid Build Coastguard Worker replaced_from_dmesg = set() 370*288bf522SAndroid Build Coastguard Worker 371*288bf522SAndroid Build Coastguard Worker time_correction_delta = 0 372*288bf522SAndroid Build Coastguard Worker time_correction_time = 0 373*288bf522SAndroid Build Coastguard Worker if ('time_correction_key' in cfg 374*288bf522SAndroid Build Coastguard Worker and cfg['time_correction_key'] in logcat_events): 375*288bf522SAndroid Build Coastguard Worker match = search_events_pattern[cfg['time_correction_key']].search( 376*288bf522SAndroid Build Coastguard Worker logcat_events[cfg['time_correction_key']]) 377*288bf522SAndroid Build Coastguard Worker if match and logcat_event_time[cfg['time_correction_key']]: 378*288bf522SAndroid Build Coastguard Worker time_correction_delta = float(match.group(1)) 379*288bf522SAndroid Build Coastguard Worker time_correction_time = logcat_event_time[cfg['time_correction_key']] 380*288bf522SAndroid Build Coastguard Worker 381*288bf522SAndroid Build Coastguard Worker debug("time_correction_delta = {0}, time_correction_time = {1}".format( 382*288bf522SAndroid Build Coastguard Worker time_correction_delta, time_correction_time)) 383*288bf522SAndroid Build Coastguard Worker 384*288bf522SAndroid Build Coastguard Worker for k, v in logcat_event_time.items(): 385*288bf522SAndroid Build Coastguard Worker if v <= time_correction_time: 386*288bf522SAndroid Build Coastguard Worker logcat_event_time[k] += time_correction_delta 387*288bf522SAndroid Build Coastguard Worker v = v + time_correction_delta 388*288bf522SAndroid Build Coastguard Worker debug("correcting event to event[{0}, {1}]".format(k, v)) 389*288bf522SAndroid Build Coastguard Worker 390*288bf522SAndroid Build Coastguard Worker diffs = [] 391*288bf522SAndroid Build Coastguard Worker if logcat_event_time.get(KERNEL_TIME_KEY) is None: 392*288bf522SAndroid Build Coastguard Worker print("kernel time not captured in logcat") 393*288bf522SAndroid Build Coastguard Worker else: 394*288bf522SAndroid Build Coastguard Worker diffs.append((logcat_event_time[KERNEL_TIME_KEY], logcat_event_time[KERNEL_TIME_KEY])) 395*288bf522SAndroid Build Coastguard Worker 396*288bf522SAndroid Build Coastguard Worker if logcat_event_time.get(BOOT_ANIM_END_TIME_KEY) and dmesg_event_time.get(BOOT_ANIM_END_TIME_KEY): 397*288bf522SAndroid Build Coastguard Worker diffs.append((logcat_event_time[BOOT_ANIM_END_TIME_KEY],\ 398*288bf522SAndroid Build Coastguard Worker logcat_event_time[BOOT_ANIM_END_TIME_KEY] -\ 399*288bf522SAndroid Build Coastguard Worker dmesg_event_time[BOOT_ANIM_END_TIME_KEY])) 400*288bf522SAndroid Build Coastguard Worker if logcat_event_time.get(LOGCAT_BOOT_COMPLETE) and dmesg_event_time.get(KERNEL_BOOT_COMPLETE): 401*288bf522SAndroid Build Coastguard Worker diffs.append(( 402*288bf522SAndroid Build Coastguard Worker logcat_event_time[LOGCAT_BOOT_COMPLETE], 403*288bf522SAndroid Build Coastguard Worker logcat_event_time[LOGCAT_BOOT_COMPLETE] - dmesg_event_time[KERNEL_BOOT_COMPLETE], 404*288bf522SAndroid Build Coastguard Worker )) 405*288bf522SAndroid Build Coastguard Worker elif logcat_event_time.get(ANDROID_INIT_SECOND_STAGE) and \ 406*288bf522SAndroid Build Coastguard Worker dmesg_event_time.get(ANDROID_INIT_SECOND_STAGE): 407*288bf522SAndroid Build Coastguard Worker print("BootAnimEnd time or BootComplete-kernel not captured in both log" +\ 408*288bf522SAndroid Build Coastguard Worker ", use Android init 2nd stage get time diff") 409*288bf522SAndroid Build Coastguard Worker diffs.append(( 410*288bf522SAndroid Build Coastguard Worker logcat_event_time[ANDROID_INIT_SECOND_STAGE], 411*288bf522SAndroid Build Coastguard Worker logcat_event_time[ANDROID_INIT_SECOND_STAGE] - dmesg_event_time[ANDROID_INIT_SECOND_STAGE], 412*288bf522SAndroid Build Coastguard Worker )) 413*288bf522SAndroid Build Coastguard Worker else: 414*288bf522SAndroid Build Coastguard Worker print("BootComplete and Android init 2nd stage not captured in both log" +\ 415*288bf522SAndroid Build Coastguard Worker ", cannot get time diff") 416*288bf522SAndroid Build Coastguard Worker print('dmesg {} logcat {}'.format(dmesg_event_time, logcat_event_time)) 417*288bf522SAndroid Build Coastguard Worker return None, None, None, None, None, None 418*288bf522SAndroid Build Coastguard Worker 419*288bf522SAndroid Build Coastguard Worker for k, v in logcat_event_time.items(): 420*288bf522SAndroid Build Coastguard Worker debug("event[{0}, {1}]".format(k, v)) 421*288bf522SAndroid Build Coastguard Worker events[k] = v 422*288bf522SAndroid Build Coastguard Worker if k in dmesg_event_time: 423*288bf522SAndroid Build Coastguard Worker debug("{0} is in dmesg".format(k)) 424*288bf522SAndroid Build Coastguard Worker events[k] = dmesg_event_time[k] 425*288bf522SAndroid Build Coastguard Worker replaced_from_dmesg.add(k) 426*288bf522SAndroid Build Coastguard Worker else: 427*288bf522SAndroid Build Coastguard Worker events_to_correct.append(k) 428*288bf522SAndroid Build Coastguard Worker 429*288bf522SAndroid Build Coastguard Worker diff_prev = diffs[0] 430*288bf522SAndroid Build Coastguard Worker for k in events_to_correct: 431*288bf522SAndroid Build Coastguard Worker diff = diffs[0] 432*288bf522SAndroid Build Coastguard Worker while diff[0] < events[k] and len(diffs) > 1: 433*288bf522SAndroid Build Coastguard Worker diffs.pop(0) 434*288bf522SAndroid Build Coastguard Worker diff_prev = diff 435*288bf522SAndroid Build Coastguard Worker diff = diffs[0] 436*288bf522SAndroid Build Coastguard Worker events[k] = events[k] - diff[1] 437*288bf522SAndroid Build Coastguard Worker if events[k] < 0.0: 438*288bf522SAndroid Build Coastguard Worker if events[k] < -0.1: # maybe previous one is better fit 439*288bf522SAndroid Build Coastguard Worker events[k] = events[k] + diff[1] - diff_prev[1] 440*288bf522SAndroid Build Coastguard Worker else: 441*288bf522SAndroid Build Coastguard Worker events[k] = 0.0 442*288bf522SAndroid Build Coastguard Worker 443*288bf522SAndroid Build Coastguard Worker data_points = collections.OrderedDict() 444*288bf522SAndroid Build Coastguard Worker 445*288bf522SAndroid Build Coastguard Worker print("-----------------") 446*288bf522SAndroid Build Coastguard Worker print("ro.boottime.*: time") 447*288bf522SAndroid Build Coastguard Worker for item in list(boottime_events.items()): 448*288bf522SAndroid Build Coastguard Worker print('{0:30}: {1:<7.5} {2}'.format(item[0], item[1],\ 449*288bf522SAndroid Build Coastguard Worker "*time taken" if item[0].startswith("init.") else "")) 450*288bf522SAndroid Build Coastguard Worker print("-----------------") 451*288bf522SAndroid Build Coastguard Worker 452*288bf522SAndroid Build Coastguard Worker if args.timings: 453*288bf522SAndroid Build Coastguard Worker kernel_timing_points, _ = generate_timing_points(kernel_timing_events, timings_pattern) 454*288bf522SAndroid Build Coastguard Worker logcat_timing_points, logcat_monitor_contentions =\ 455*288bf522SAndroid Build Coastguard Worker generate_timing_points(logcat_timing_events, timings_pattern) 456*288bf522SAndroid Build Coastguard Worker dump_timing_points("Kernel", kernel_timing_points) 457*288bf522SAndroid Build Coastguard Worker dump_timing_points("Logcat", logcat_timing_points) 458*288bf522SAndroid Build Coastguard Worker dump_monitor_contentions(logcat_monitor_contentions) 459*288bf522SAndroid Build Coastguard Worker 460*288bf522SAndroid Build Coastguard Worker for item in sorted(list(events.items()), key=operator.itemgetter(1)): 461*288bf522SAndroid Build Coastguard Worker data_points[item[0]] = { 462*288bf522SAndroid Build Coastguard Worker 'value': item[1], 463*288bf522SAndroid Build Coastguard Worker 'from_dmesg': item[0] in replaced_from_dmesg, 464*288bf522SAndroid Build Coastguard Worker 'logcat_value': logcat_original_time[item[0]] 465*288bf522SAndroid Build Coastguard Worker } 466*288bf522SAndroid Build Coastguard Worker # add times with bootloader 467*288bf522SAndroid Build Coastguard Worker if events.get("BootComplete") and boottime_events.get("bootloader"): 468*288bf522SAndroid Build Coastguard Worker total = events["BootComplete"] + boottime_events["bootloader"] 469*288bf522SAndroid Build Coastguard Worker data_points["*BootComplete+Bootloader"] = { 470*288bf522SAndroid Build Coastguard Worker 'value': total, 471*288bf522SAndroid Build Coastguard Worker 'from_dmesg': False, 472*288bf522SAndroid Build Coastguard Worker 'logcat_value': 0.0 473*288bf522SAndroid Build Coastguard Worker } 474*288bf522SAndroid Build Coastguard Worker if events.get("LauncherStart") and boottime_events.get("bootloader"): 475*288bf522SAndroid Build Coastguard Worker total = events["LauncherStart"] + boottime_events["bootloader"] 476*288bf522SAndroid Build Coastguard Worker data_points["*LauncherStart+Bootloader"] = { 477*288bf522SAndroid Build Coastguard Worker 'value': total, 478*288bf522SAndroid Build Coastguard Worker 'from_dmesg': False, 479*288bf522SAndroid Build Coastguard Worker 'logcat_value': 0.0 480*288bf522SAndroid Build Coastguard Worker } 481*288bf522SAndroid Build Coastguard Worker for k, v in data_points.items(): 482*288bf522SAndroid Build Coastguard Worker print('{0:30}: {1:<7.5} {2:1} ({3})'.format( 483*288bf522SAndroid Build Coastguard Worker k, v['value'], '*' if v['from_dmesg'] else '', v['logcat_value'])) 484*288bf522SAndroid Build Coastguard Worker 485*288bf522SAndroid Build Coastguard Worker print('\n* - event time was obtained from dmesg log\n') 486*288bf522SAndroid Build Coastguard Worker 487*288bf522SAndroid Build Coastguard Worker if events[LOGCAT_BOOT_COMPLETE] > error_time and not args.ignore: 488*288bf522SAndroid Build Coastguard Worker capture_bugreport("bootuptoolong", events[LOGCAT_BOOT_COMPLETE]) 489*288bf522SAndroid Build Coastguard Worker 490*288bf522SAndroid Build Coastguard Worker for k, v in components_to_monitor.items(): 491*288bf522SAndroid Build Coastguard Worker logcat_value_measured = logcat_timing_points.get(k) 492*288bf522SAndroid Build Coastguard Worker kernel_value_measured = kernel_timing_points.get(k) 493*288bf522SAndroid Build Coastguard Worker data_from_data_points = data_points.get(k) 494*288bf522SAndroid Build Coastguard Worker if logcat_value_measured and logcat_value_measured > v: 495*288bf522SAndroid Build Coastguard Worker capture_bugreport(k + "-" + str(logcat_value_measured), events[LOGCAT_BOOT_COMPLETE]) 496*288bf522SAndroid Build Coastguard Worker break 497*288bf522SAndroid Build Coastguard Worker elif kernel_value_measured and kernel_value_measured > v: 498*288bf522SAndroid Build Coastguard Worker capture_bugreport(k + "-" + str(kernel_value_measured), events[LOGCAT_BOOT_COMPLETE]) 499*288bf522SAndroid Build Coastguard Worker break 500*288bf522SAndroid Build Coastguard Worker elif data_from_data_points and data_from_data_points['value'] * 1000.0 > v: 501*288bf522SAndroid Build Coastguard Worker capture_bugreport(k + "-" + str(data_from_data_points['value']), events[LOGCAT_BOOT_COMPLETE]) 502*288bf522SAndroid Build Coastguard Worker break 503*288bf522SAndroid Build Coastguard Worker 504*288bf522SAndroid Build Coastguard Worker if args.fs_check: 505*288bf522SAndroid Build Coastguard Worker fs_stat = None 506*288bf522SAndroid Build Coastguard Worker if logcat_events.get("FsStat"): 507*288bf522SAndroid Build Coastguard Worker fs_stat_pattern = cfg["events"]["FsStat"] 508*288bf522SAndroid Build Coastguard Worker m = re.search(fs_stat_pattern, logcat_events.get("FsStat")) 509*288bf522SAndroid Build Coastguard Worker if m: 510*288bf522SAndroid Build Coastguard Worker fs_stat = m.group(1) 511*288bf522SAndroid Build Coastguard Worker print('fs_stat:', fs_stat) 512*288bf522SAndroid Build Coastguard Worker 513*288bf522SAndroid Build Coastguard Worker if fs_stat: 514*288bf522SAndroid Build Coastguard Worker fs_stat_val = int(fs_stat, 0) 515*288bf522SAndroid Build Coastguard Worker if (fs_stat_val & ~0x17) != 0: 516*288bf522SAndroid Build Coastguard Worker capture_bugreport("fs_stat_" + fs_stat, events[LOGCAT_BOOT_COMPLETE]) 517*288bf522SAndroid Build Coastguard Worker 518*288bf522SAndroid Build Coastguard Worker return data_points, kernel_timing_points, logcat_timing_points, boottime_events, shutdown_events,\ 519*288bf522SAndroid Build Coastguard Worker shutdown_timing_events 520*288bf522SAndroid Build Coastguard Worker 521*288bf522SAndroid Build Coastguard Workerdef debug(string): 522*288bf522SAndroid Build Coastguard Worker if DEBUG: 523*288bf522SAndroid Build Coastguard Worker print(string) 524*288bf522SAndroid Build Coastguard Worker 525*288bf522SAndroid Build Coastguard Workerdef extract_timing(s, patterns): 526*288bf522SAndroid Build Coastguard Worker for _, p in patterns.items(): 527*288bf522SAndroid Build Coastguard Worker m = p.search(s) 528*288bf522SAndroid Build Coastguard Worker if m: 529*288bf522SAndroid Build Coastguard Worker timing_dict = m.groupdict() 530*288bf522SAndroid Build Coastguard Worker return timing_dict['name'], float(timing_dict['time']) 531*288bf522SAndroid Build Coastguard Worker return None, None 532*288bf522SAndroid Build Coastguard Worker 533*288bf522SAndroid Build Coastguard Workerdef init_arguments(): 534*288bf522SAndroid Build Coastguard Worker parser = argparse.ArgumentParser(description='Measures boot time.') 535*288bf522SAndroid Build Coastguard Worker parser.add_argument('-r', '--reboot', dest='reboot', 536*288bf522SAndroid Build Coastguard Worker action='store_true', 537*288bf522SAndroid Build Coastguard Worker help='reboot device for measurement', ) 538*288bf522SAndroid Build Coastguard Worker parser.add_argument('-o', '--output', dest='output', type=str, 539*288bf522SAndroid Build Coastguard Worker help='Output directory where results are stored') 540*288bf522SAndroid Build Coastguard Worker parser.add_argument('-c', '--config', dest='config', 541*288bf522SAndroid Build Coastguard Worker default='config.yaml', type=argparse.FileType('r'), 542*288bf522SAndroid Build Coastguard Worker help='config file for the tool', ) 543*288bf522SAndroid Build Coastguard Worker parser.add_argument('-s', '--stressfs', dest='stressfs', 544*288bf522SAndroid Build Coastguard Worker default='', type=str, 545*288bf522SAndroid Build Coastguard Worker help='APK file for the stressfs tool used to write to the data partition ' +\ 546*288bf522SAndroid Build Coastguard Worker 'during shutdown') 547*288bf522SAndroid Build Coastguard Worker parser.add_argument('-n', '--iterate', dest='iterate', type=int, default=1, 548*288bf522SAndroid Build Coastguard Worker help='number of time to repeat the measurement', ) 549*288bf522SAndroid Build Coastguard Worker parser.add_argument('-g', '--ignore', dest='ignore', action='store_true', 550*288bf522SAndroid Build Coastguard Worker help='ignore too big values error', ) 551*288bf522SAndroid Build Coastguard Worker parser.add_argument('-t', '--timings', dest='timings', action='store_true', 552*288bf522SAndroid Build Coastguard Worker help='print individual component times', default=True, ) 553*288bf522SAndroid Build Coastguard Worker parser.add_argument('-p', '--serial', dest='serial', action='store', 554*288bf522SAndroid Build Coastguard Worker help='android device serial number') 555*288bf522SAndroid Build Coastguard Worker parser.add_argument('-e', '--errortime', dest='errortime', action='store', 556*288bf522SAndroid Build Coastguard Worker help='handle bootup time bigger than this as error') 557*288bf522SAndroid Build Coastguard Worker parser.add_argument('-w', '--maxwaittime', dest='maxwaittime', action='store', 558*288bf522SAndroid Build Coastguard Worker help='wait for up to this time to collect logs. Retry after this time.' +\ 559*288bf522SAndroid Build Coastguard Worker ' Default is 200 sec.') 560*288bf522SAndroid Build Coastguard Worker parser.add_argument('-f', '--fs_check', dest='fs_check', 561*288bf522SAndroid Build Coastguard Worker action='store_true', 562*288bf522SAndroid Build Coastguard Worker help='check fs_stat after reboot', ) 563*288bf522SAndroid Build Coastguard Worker parser.add_argument('-a', '--adb_reboot', dest='adb_reboot', 564*288bf522SAndroid Build Coastguard Worker action='store_true', 565*288bf522SAndroid Build Coastguard Worker help='reboot with adb reboot', ) 566*288bf522SAndroid Build Coastguard Worker parser.add_argument('-v', '--permissive', dest='permissive', 567*288bf522SAndroid Build Coastguard Worker action='store_true', 568*288bf522SAndroid Build Coastguard Worker help='set selinux into permissive before reboot', ) 569*288bf522SAndroid Build Coastguard Worker parser.add_argument('-m', '--componentmonitor', dest='componentmonitor', action='store', 570*288bf522SAndroid Build Coastguard Worker help='capture bugreport if specified timing component is taking more than ' +\ 571*288bf522SAndroid Build Coastguard Worker 'certain time. Unlike errortime, the result will not be rejected in' +\ 572*288bf522SAndroid Build Coastguard Worker 'averaging. Format is key1=time1,key2=time2...') 573*288bf522SAndroid Build Coastguard Worker parser.add_argument('-b', '--bootchart', dest='bootchart', 574*288bf522SAndroid Build Coastguard Worker action='store_true', 575*288bf522SAndroid Build Coastguard Worker help='collect bootchart from the device.', ) 576*288bf522SAndroid Build Coastguard Worker parser.add_argument('-y', '--systrace', dest='systrace', 577*288bf522SAndroid Build Coastguard Worker action='store_true', 578*288bf522SAndroid Build Coastguard Worker help='collect systrace from the device. kernel trace should be already enabled', ) 579*288bf522SAndroid Build Coastguard Worker parser.add_argument('-W', '--carwatchdog', dest='carwatchdog', action='store_true', 580*288bf522SAndroid Build Coastguard Worker help='collect carwatchdog boot stats') 581*288bf522SAndroid Build Coastguard Worker parser.add_argument('-G', '--buffersize', dest='buffersize', action='store', type=str, 582*288bf522SAndroid Build Coastguard Worker default=None, 583*288bf522SAndroid Build Coastguard Worker help='set logcat buffersize') 584*288bf522SAndroid Build Coastguard Worker return parser.parse_args() 585*288bf522SAndroid Build Coastguard Worker 586*288bf522SAndroid Build Coastguard Workerdef handle_zygote_event(zygote_pids, events, event, line): 587*288bf522SAndroid Build Coastguard Worker words = line.split() 588*288bf522SAndroid Build Coastguard Worker if len(words) > 1: 589*288bf522SAndroid Build Coastguard Worker pid = int(words[1]) 590*288bf522SAndroid Build Coastguard Worker if len(zygote_pids) == 2: 591*288bf522SAndroid Build Coastguard Worker if pid == zygote_pids[1]: # secondary 592*288bf522SAndroid Build Coastguard Worker event = event + "-secondary" 593*288bf522SAndroid Build Coastguard Worker elif len(zygote_pids) == 1: 594*288bf522SAndroid Build Coastguard Worker if zygote_pids[0] != pid: # new pid, need to decide if old ones were secondary 595*288bf522SAndroid Build Coastguard Worker primary_pid = min(pid, zygote_pids[0]) 596*288bf522SAndroid Build Coastguard Worker secondary_pid = max(pid, zygote_pids[0]) 597*288bf522SAndroid Build Coastguard Worker zygote_pids.pop() 598*288bf522SAndroid Build Coastguard Worker zygote_pids.append(primary_pid) 599*288bf522SAndroid Build Coastguard Worker zygote_pids.append(secondary_pid) 600*288bf522SAndroid Build Coastguard Worker if pid == primary_pid: # old one was secondary: 601*288bf522SAndroid Build Coastguard Worker move_to_secondary = [] 602*288bf522SAndroid Build Coastguard Worker for k, l in events.items(): 603*288bf522SAndroid Build Coastguard Worker if k.startswith("zygote"): 604*288bf522SAndroid Build Coastguard Worker move_to_secondary.append((k, l)) 605*288bf522SAndroid Build Coastguard Worker for item in move_to_secondary: 606*288bf522SAndroid Build Coastguard Worker del events[item[0]] 607*288bf522SAndroid Build Coastguard Worker if item[0].endswith("-secondary"): 608*288bf522SAndroid Build Coastguard Worker print("Secondary already exists for event %s while found new pid %d, primary %d "\ 609*288bf522SAndroid Build Coastguard Worker % (item[0], secondary_pid, primary_pid)) 610*288bf522SAndroid Build Coastguard Worker else: 611*288bf522SAndroid Build Coastguard Worker events[item[0] + "-secondary"] = item[1] 612*288bf522SAndroid Build Coastguard Worker else: 613*288bf522SAndroid Build Coastguard Worker event = event + "-secondary" 614*288bf522SAndroid Build Coastguard Worker else: 615*288bf522SAndroid Build Coastguard Worker zygote_pids.append(pid) 616*288bf522SAndroid Build Coastguard Worker events[event] = line 617*288bf522SAndroid Build Coastguard Worker 618*288bf522SAndroid Build Coastguard Workerdef update_name_if_already_exist(events, name): 619*288bf522SAndroid Build Coastguard Worker existing_event = events.get(name) 620*288bf522SAndroid Build Coastguard Worker i = 0 621*288bf522SAndroid Build Coastguard Worker new_name = name 622*288bf522SAndroid Build Coastguard Worker while existing_event: 623*288bf522SAndroid Build Coastguard Worker i += 1 624*288bf522SAndroid Build Coastguard Worker new_name = name + "_" + str(i) 625*288bf522SAndroid Build Coastguard Worker existing_event = events.get(new_name) 626*288bf522SAndroid Build Coastguard Worker return new_name 627*288bf522SAndroid Build Coastguard Worker 628*288bf522SAndroid Build Coastguard Workerdef collect_logcat_for_shutdown(capture_log_on_error, shutdown_events_pattern,\ 629*288bf522SAndroid Build Coastguard Worker log_capture_conditions): 630*288bf522SAndroid Build Coastguard Worker events = collections.OrderedDict() 631*288bf522SAndroid Build Coastguard Worker # shutdown does not have timing_events but calculated from checking Xyz - XyzDone / XyzTimeout 632*288bf522SAndroid Build Coastguard Worker timing_events = collections.OrderedDict() 633*288bf522SAndroid Build Coastguard Worker process = subprocess.Popen(ADB_CMD + ' logcat -b all -v epoch', shell=True, 634*288bf522SAndroid Build Coastguard Worker stdout=subprocess.PIPE) 635*288bf522SAndroid Build Coastguard Worker lines = [] 636*288bf522SAndroid Build Coastguard Worker capture_log = False 637*288bf522SAndroid Build Coastguard Worker shutdown_start_time = 0 638*288bf522SAndroid Build Coastguard Worker while True: 639*288bf522SAndroid Build Coastguard Worker line = process.stdout.readline() 640*288bf522SAndroid Build Coastguard Worker if not line: 641*288bf522SAndroid Build Coastguard Worker break 642*288bf522SAndroid Build Coastguard Worker line = line.decode('utf-8', 'ignore').lstrip().rstrip() 643*288bf522SAndroid Build Coastguard Worker lines.append(line) 644*288bf522SAndroid Build Coastguard Worker event = get_boot_event(line, shutdown_events_pattern) 645*288bf522SAndroid Build Coastguard Worker if not event: 646*288bf522SAndroid Build Coastguard Worker continue 647*288bf522SAndroid Build Coastguard Worker time = extract_a_time(line, TIME_LOGCAT, float) 648*288bf522SAndroid Build Coastguard Worker if time is None: 649*288bf522SAndroid Build Coastguard Worker print("cannot get time from: " + line) 650*288bf522SAndroid Build Coastguard Worker continue 651*288bf522SAndroid Build Coastguard Worker if shutdown_start_time == 0: 652*288bf522SAndroid Build Coastguard Worker shutdown_start_time = time 653*288bf522SAndroid Build Coastguard Worker time = time - shutdown_start_time 654*288bf522SAndroid Build Coastguard Worker events[event] = time 655*288bf522SAndroid Build Coastguard Worker time_limit1 = log_capture_conditions.get(event) 656*288bf522SAndroid Build Coastguard Worker if time_limit1 and time_limit1 <= time: 657*288bf522SAndroid Build Coastguard Worker capture_log = True 658*288bf522SAndroid Build Coastguard Worker pair_event = None 659*288bf522SAndroid Build Coastguard Worker if event.endswith('Done'): 660*288bf522SAndroid Build Coastguard Worker pair_event = event[:-4] 661*288bf522SAndroid Build Coastguard Worker elif event.endswith('Timeout'): 662*288bf522SAndroid Build Coastguard Worker pair_event = event[:-7] 663*288bf522SAndroid Build Coastguard Worker if capture_log_on_error: 664*288bf522SAndroid Build Coastguard Worker capture_log = True 665*288bf522SAndroid Build Coastguard Worker if not pair_event: 666*288bf522SAndroid Build Coastguard Worker continue 667*288bf522SAndroid Build Coastguard Worker start_time = events.get(pair_event) 668*288bf522SAndroid Build Coastguard Worker if not start_time: 669*288bf522SAndroid Build Coastguard Worker print("No start event for " + event) 670*288bf522SAndroid Build Coastguard Worker continue 671*288bf522SAndroid Build Coastguard Worker time_spent = time - start_time 672*288bf522SAndroid Build Coastguard Worker timing_event_name = pair_event + "Duration" 673*288bf522SAndroid Build Coastguard Worker timing_events[timing_event_name] = time_spent 674*288bf522SAndroid Build Coastguard Worker time_limit2 = log_capture_conditions.get(timing_event_name) 675*288bf522SAndroid Build Coastguard Worker if time_limit2 and time_limit2 <= time_spent: 676*288bf522SAndroid Build Coastguard Worker capture_log = True 677*288bf522SAndroid Build Coastguard Worker 678*288bf522SAndroid Build Coastguard Worker if capture_log: 679*288bf522SAndroid Build Coastguard Worker now = datetime.now() 680*288bf522SAndroid Build Coastguard Worker log_file = ("shutdownlog-error-%s.txt") % (now.strftime("%Y-%m-%d-%H-%M-%S")) 681*288bf522SAndroid Build Coastguard Worker print("Shutdown error, capture log to %s" % (log_file)) 682*288bf522SAndroid Build Coastguard Worker with open(log_file, 'w') as f: 683*288bf522SAndroid Build Coastguard Worker f.write('\n'.join(lines)) 684*288bf522SAndroid Build Coastguard Worker return events, timing_events 685*288bf522SAndroid Build Coastguard Worker 686*288bf522SAndroid Build Coastguard Workerdef log_timeout(time_left, stop_events, events, timing_events): 687*288bf522SAndroid Build Coastguard Worker print("timeout waiting for event, continue", time_left) 688*288bf522SAndroid Build Coastguard Worker print(" remaininig events {}, event {} timing events {}".\ 689*288bf522SAndroid Build Coastguard Worker format(stop_events, events, timing_events)) 690*288bf522SAndroid Build Coastguard Worker 691*288bf522SAndroid Build Coastguard Workerdef collect_events(search_events, command, timings, stop_events, 692*288bf522SAndroid Build Coastguard Worker collects_all_events, disable_timing_after_zygote): 693*288bf522SAndroid Build Coastguard Worker events = collections.OrderedDict() 694*288bf522SAndroid Build Coastguard Worker timing_events = {} 695*288bf522SAndroid Build Coastguard Worker 696*288bf522SAndroid Build Coastguard Worker data_available = stop_events is None 697*288bf522SAndroid Build Coastguard Worker zygote_pids = [] 698*288bf522SAndroid Build Coastguard Worker start_time = time.time() 699*288bf522SAndroid Build Coastguard Worker zygote_found = False 700*288bf522SAndroid Build Coastguard Worker line = None 701*288bf522SAndroid Build Coastguard Worker if collects_all_events: 702*288bf522SAndroid Build Coastguard Worker print("remaining stop_events:", stop_events) 703*288bf522SAndroid Build Coastguard Worker else: 704*288bf522SAndroid Build Coastguard Worker print("waiting for any of stop_events:", stop_events) 705*288bf522SAndroid Build Coastguard Worker init = True 706*288bf522SAndroid Build Coastguard Worker while True: 707*288bf522SAndroid Build Coastguard Worker if init: 708*288bf522SAndroid Build Coastguard Worker process = subprocess.Popen(command, shell=True, stdout=subprocess.PIPE) 709*288bf522SAndroid Build Coastguard Worker read_poll = select.poll() 710*288bf522SAndroid Build Coastguard Worker read_poll.register(process.stdout, select.POLLIN) 711*288bf522SAndroid Build Coastguard Worker init = False 712*288bf522SAndroid Build Coastguard Worker if len(stop_events) == 0: 713*288bf522SAndroid Build Coastguard Worker break 714*288bf522SAndroid Build Coastguard Worker time_left = start_time + max_wait_time - time.time() 715*288bf522SAndroid Build Coastguard Worker if time_left <= 0: 716*288bf522SAndroid Build Coastguard Worker log_timeout(time_left, stop_events, events, timing_events) 717*288bf522SAndroid Build Coastguard Worker break 718*288bf522SAndroid Build Coastguard Worker polled_events = read_poll.poll(time_left * 1000.0) 719*288bf522SAndroid Build Coastguard Worker # adb logcat subprocess is auto-terminated when the adb connection is lost. 720*288bf522SAndroid Build Coastguard Worker # Thus, check for the subprocess return code and reconnect to the device if 721*288bf522SAndroid Build Coastguard Worker # needed. Otherwise, the logcat events cannot be polled completely. 722*288bf522SAndroid Build Coastguard Worker if process.poll() is not None: 723*288bf522SAndroid Build Coastguard Worker print("adb might be disconnected?\nRetrying to connect.") 724*288bf522SAndroid Build Coastguard Worker run_adb_cmd('wait-for-device') 725*288bf522SAndroid Build Coastguard Worker print(" reconnected") 726*288bf522SAndroid Build Coastguard Worker init = True 727*288bf522SAndroid Build Coastguard Worker continue 728*288bf522SAndroid Build Coastguard Worker if len(polled_events) == 0: 729*288bf522SAndroid Build Coastguard Worker log_timeout(time_left, stop_events, events, timing_events) 730*288bf522SAndroid Build Coastguard Worker break 731*288bf522SAndroid Build Coastguard Worker for polled_event in polled_events: 732*288bf522SAndroid Build Coastguard Worker if polled_event[1] == select.POLLIN: 733*288bf522SAndroid Build Coastguard Worker line = process.stdout.readline().decode('utf-8', 'ignore') 734*288bf522SAndroid Build Coastguard Worker else: 735*288bf522SAndroid Build Coastguard Worker if polled_event[1] == select.POLLHUP: 736*288bf522SAndroid Build Coastguard Worker if len(stop_events) == 0: 737*288bf522SAndroid Build Coastguard Worker break; 738*288bf522SAndroid Build Coastguard Worker # adb connection lost 739*288bf522SAndroid Build Coastguard Worker print("poll error waiting for event, adb lost?") 740*288bf522SAndroid Build Coastguard Worker if time_left > 0: 741*288bf522SAndroid Build Coastguard Worker print("retry adb") 742*288bf522SAndroid Build Coastguard Worker run_adb_cmd('wait-for-device') 743*288bf522SAndroid Build Coastguard Worker print(" reconnected") 744*288bf522SAndroid Build Coastguard Worker init = True 745*288bf522SAndroid Build Coastguard Worker continue 746*288bf522SAndroid Build Coastguard Worker else: 747*288bf522SAndroid Build Coastguard Worker break 748*288bf522SAndroid Build Coastguard Worker if not data_available: 749*288bf522SAndroid Build Coastguard Worker print("Collecting data samples from '%s'. Please wait...\n" % command) 750*288bf522SAndroid Build Coastguard Worker data_available = True 751*288bf522SAndroid Build Coastguard Worker event = get_boot_event(line, search_events) 752*288bf522SAndroid Build Coastguard Worker if event: 753*288bf522SAndroid Build Coastguard Worker debug("event[{0}] captured: {1}".format(event, line)) 754*288bf522SAndroid Build Coastguard Worker if event == "starting_zygote": 755*288bf522SAndroid Build Coastguard Worker events[event] = line 756*288bf522SAndroid Build Coastguard Worker zygote_found = True 757*288bf522SAndroid Build Coastguard Worker elif event.startswith("zygote"): 758*288bf522SAndroid Build Coastguard Worker handle_zygote_event(zygote_pids, events, event, line) 759*288bf522SAndroid Build Coastguard Worker else: 760*288bf522SAndroid Build Coastguard Worker new_event = update_name_if_already_exist(events, event) 761*288bf522SAndroid Build Coastguard Worker events[new_event] = line 762*288bf522SAndroid Build Coastguard Worker if event in stop_events: 763*288bf522SAndroid Build Coastguard Worker if collects_all_events: 764*288bf522SAndroid Build Coastguard Worker stop_events.remove(event) 765*288bf522SAndroid Build Coastguard Worker print("remaining stop_events:", stop_events) 766*288bf522SAndroid Build Coastguard Worker else: 767*288bf522SAndroid Build Coastguard Worker # no need to wait for others 768*288bf522SAndroid Build Coastguard Worker stop_events = [] 769*288bf522SAndroid Build Coastguard Worker 770*288bf522SAndroid Build Coastguard Worker timing_event = get_boot_event(line, timings) 771*288bf522SAndroid Build Coastguard Worker if timing_event and (not disable_timing_after_zygote or not zygote_found): 772*288bf522SAndroid Build Coastguard Worker if timing_event not in timing_events: 773*288bf522SAndroid Build Coastguard Worker timing_events[timing_event] = [] 774*288bf522SAndroid Build Coastguard Worker timing_events[timing_event].append(line) 775*288bf522SAndroid Build Coastguard Worker debug("timing_event[{0}] captured: {1}".format(timing_event, line)) 776*288bf522SAndroid Build Coastguard Worker 777*288bf522SAndroid Build Coastguard Worker process.terminate() 778*288bf522SAndroid Build Coastguard Worker return events, timing_events 779*288bf522SAndroid Build Coastguard Worker 780*288bf522SAndroid Build Coastguard Workerdef fetch_boottime_property(): 781*288bf522SAndroid Build Coastguard Worker cmd = ADB_CMD + ' shell su root getprop' 782*288bf522SAndroid Build Coastguard Worker events = {} 783*288bf522SAndroid Build Coastguard Worker process = subprocess.Popen(cmd, shell=True, stdout=subprocess.PIPE) 784*288bf522SAndroid Build Coastguard Worker out = process.stdout 785*288bf522SAndroid Build Coastguard Worker pattern = re.compile(BOOT_PROP) 786*288bf522SAndroid Build Coastguard Worker pattern_bootloader = re.compile(BOOTLOADER_TIME_PROP) 787*288bf522SAndroid Build Coastguard Worker bootloader_time = 0.0 788*288bf522SAndroid Build Coastguard Worker for line in out: 789*288bf522SAndroid Build Coastguard Worker line = line.decode('utf-8', 'ignore') 790*288bf522SAndroid Build Coastguard Worker match = pattern.match(line) 791*288bf522SAndroid Build Coastguard Worker if match: 792*288bf522SAndroid Build Coastguard Worker if match.group(1).startswith("init."): 793*288bf522SAndroid Build Coastguard Worker events[match.group(1)] = float(match.group(2)) / 1000.0 #ms to s 794*288bf522SAndroid Build Coastguard Worker else: 795*288bf522SAndroid Build Coastguard Worker events[match.group(1)] = float(match.group(2)) / 1000000000.0 #ns to s 796*288bf522SAndroid Build Coastguard Worker match = pattern_bootloader.match(line) 797*288bf522SAndroid Build Coastguard Worker if match: 798*288bf522SAndroid Build Coastguard Worker items = match.group(1).split(",") 799*288bf522SAndroid Build Coastguard Worker for item in items: 800*288bf522SAndroid Build Coastguard Worker entry_pair = item.split(":") 801*288bf522SAndroid Build Coastguard Worker entry_name = entry_pair[0] 802*288bf522SAndroid Build Coastguard Worker time_spent = float(entry_pair[1]) / 1000 #ms to s 803*288bf522SAndroid Build Coastguard Worker if entry_name != "SW": 804*288bf522SAndroid Build Coastguard Worker bootloader_time = bootloader_time + time_spent 805*288bf522SAndroid Build Coastguard Worker ordered_event = collections.OrderedDict() 806*288bf522SAndroid Build Coastguard Worker if bootloader_time != 0.0: 807*288bf522SAndroid Build Coastguard Worker ordered_event["bootloader"] = bootloader_time 808*288bf522SAndroid Build Coastguard Worker for item in sorted(list(events.items()), key=operator.itemgetter(1)): 809*288bf522SAndroid Build Coastguard Worker ordered_event[item[0]] = item[1] 810*288bf522SAndroid Build Coastguard Worker return ordered_event 811*288bf522SAndroid Build Coastguard Worker 812*288bf522SAndroid Build Coastguard Worker 813*288bf522SAndroid Build Coastguard Workerdef get_boot_event(line, events): 814*288bf522SAndroid Build Coastguard Worker for event_key, event_pattern in events.items(): 815*288bf522SAndroid Build Coastguard Worker if event_pattern.search(line): 816*288bf522SAndroid Build Coastguard Worker return event_key 817*288bf522SAndroid Build Coastguard Worker return None 818*288bf522SAndroid Build Coastguard Worker 819*288bf522SAndroid Build Coastguard Workerdef extract_a_time(line, pattern, date_transform_function): 820*288bf522SAndroid Build Coastguard Worker found = re.findall(pattern, line) 821*288bf522SAndroid Build Coastguard Worker if len(found) > 0: 822*288bf522SAndroid Build Coastguard Worker return date_transform_function(found[0]) 823*288bf522SAndroid Build Coastguard Worker else: 824*288bf522SAndroid Build Coastguard Worker return None 825*288bf522SAndroid Build Coastguard Worker 826*288bf522SAndroid Build Coastguard Workerdef extract_time(events, pattern, date_transform_function): 827*288bf522SAndroid Build Coastguard Worker result = collections.OrderedDict() 828*288bf522SAndroid Build Coastguard Worker for event, data in events.items(): 829*288bf522SAndroid Build Coastguard Worker time = extract_a_time(data, pattern, date_transform_function) 830*288bf522SAndroid Build Coastguard Worker if time is not None: 831*288bf522SAndroid Build Coastguard Worker result[event] = time 832*288bf522SAndroid Build Coastguard Worker else: 833*288bf522SAndroid Build Coastguard Worker print("Failed to find time for event: ", event, data) 834*288bf522SAndroid Build Coastguard Worker return result 835*288bf522SAndroid Build Coastguard Worker 836*288bf522SAndroid Build Coastguard Worker 837*288bf522SAndroid Build Coastguard Workerdef do_reboot(serial, use_adb_reboot): 838*288bf522SAndroid Build Coastguard Worker # do not update time 839*288bf522SAndroid Build Coastguard Worker run_adb_cmd('shell settings put global auto_time 0') 840*288bf522SAndroid Build Coastguard Worker run_adb_cmd('shell settings put global auto_time_zone 0') 841*288bf522SAndroid Build Coastguard Worker original_devices = subprocess.check_output("adb devices", shell=True).decode('utf-8', 'ignore') 842*288bf522SAndroid Build Coastguard Worker if use_adb_reboot: 843*288bf522SAndroid Build Coastguard Worker print('Rebooting the device using adb reboot') 844*288bf522SAndroid Build Coastguard Worker run_adb_cmd('reboot') 845*288bf522SAndroid Build Coastguard Worker else: 846*288bf522SAndroid Build Coastguard Worker print('Rebooting the device using svc power reboot') 847*288bf522SAndroid Build Coastguard Worker run_adb_shell_cmd_as_root('svc power reboot') 848*288bf522SAndroid Build Coastguard Worker # Wait for the device to go away 849*288bf522SAndroid Build Coastguard Worker retry = 0 850*288bf522SAndroid Build Coastguard Worker while retry < 20: 851*288bf522SAndroid Build Coastguard Worker current_devices = subprocess.check_output("adb devices", shell=True).decode('utf-8', 'ignore') 852*288bf522SAndroid Build Coastguard Worker if original_devices != current_devices: 853*288bf522SAndroid Build Coastguard Worker if not serial or (serial and re.findall(serial + ".*offline", current_devices, re.MULTILINE)): 854*288bf522SAndroid Build Coastguard Worker return True 855*288bf522SAndroid Build Coastguard Worker time.sleep(1) 856*288bf522SAndroid Build Coastguard Worker retry += 1 857*288bf522SAndroid Build Coastguard Worker return False 858*288bf522SAndroid Build Coastguard Worker 859*288bf522SAndroid Build Coastguard Workerdef reboot(serial, use_stressfs, permissive, use_adb_reboot, adb_buffersize=None): 860*288bf522SAndroid Build Coastguard Worker if use_stressfs: 861*288bf522SAndroid Build Coastguard Worker print('Starting write to data partition') 862*288bf522SAndroid Build Coastguard Worker run_adb_shell_cmd('am start' +\ 863*288bf522SAndroid Build Coastguard Worker ' -n com.android.car.test.stressfs/.WritingActivity' +\ 864*288bf522SAndroid Build Coastguard Worker ' -a com.android.car.test.stressfs.START') 865*288bf522SAndroid Build Coastguard Worker # Give this app some time to start. 866*288bf522SAndroid Build Coastguard Worker time.sleep(1) 867*288bf522SAndroid Build Coastguard Worker if permissive: 868*288bf522SAndroid Build Coastguard Worker run_adb_shell_cmd_as_root('setenforce 0') 869*288bf522SAndroid Build Coastguard Worker 870*288bf522SAndroid Build Coastguard Worker retry = 0 871*288bf522SAndroid Build Coastguard Worker while retry < 5: 872*288bf522SAndroid Build Coastguard Worker if do_reboot(serial, use_adb_reboot): 873*288bf522SAndroid Build Coastguard Worker break 874*288bf522SAndroid Build Coastguard Worker retry += 1 875*288bf522SAndroid Build Coastguard Worker 876*288bf522SAndroid Build Coastguard Worker print('Waiting the device') 877*288bf522SAndroid Build Coastguard Worker run_adb_cmd('wait-for-device') 878*288bf522SAndroid Build Coastguard Worker print(' found a device') 879*288bf522SAndroid Build Coastguard Worker 880*288bf522SAndroid Build Coastguard Worker if adb_buffersize is not None: 881*288bf522SAndroid Build Coastguard Worker # increase the buffer size 882*288bf522SAndroid Build Coastguard Worker if run_adb_cmd('logcat -G {}'.format(adb_buffersize)) != 0: 883*288bf522SAndroid Build Coastguard Worker debug('Fail to set logcat buffer size as {}'.format(adb_buffersize)) 884*288bf522SAndroid Build Coastguard Worker 885*288bf522SAndroid Build Coastguard Worker''' 886*288bf522SAndroid Build Coastguard WorkerRuns adb command. If do_return_result is true then output of command is 887*288bf522SAndroid Build Coastguard Workerreturned otherwise an empty string is returned. 888*288bf522SAndroid Build Coastguard Worker''' 889*288bf522SAndroid Build Coastguard Workerdef run_adb_cmd(cmd, do_return_result=False): 890*288bf522SAndroid Build Coastguard Worker if do_return_result: 891*288bf522SAndroid Build Coastguard Worker return subprocess.check_output(ADB_CMD + ' ' + cmd, shell=True).decode('utf-8', 'ignore').strip() 892*288bf522SAndroid Build Coastguard Worker subprocess.call(ADB_CMD + ' ' + cmd, shell=True) 893*288bf522SAndroid Build Coastguard Worker return "" 894*288bf522SAndroid Build Coastguard Worker 895*288bf522SAndroid Build Coastguard Workerdef run_adb_shell_cmd(cmd, do_return_result=False): 896*288bf522SAndroid Build Coastguard Worker return run_adb_cmd('shell ' + cmd, do_return_result) 897*288bf522SAndroid Build Coastguard Worker 898*288bf522SAndroid Build Coastguard Workerdef run_adb_shell_cmd_as_root(cmd, do_return_result=False): 899*288bf522SAndroid Build Coastguard Worker return run_adb_shell_cmd('su root ' + cmd, do_return_result) 900*288bf522SAndroid Build Coastguard Worker 901*288bf522SAndroid Build Coastguard Workerdef logcat_time_func(offset_year): 902*288bf522SAndroid Build Coastguard Worker def f(date_str): 903*288bf522SAndroid Build Coastguard Worker ndate = datetime.datetime.strptime(str(offset_year) + '-' + 904*288bf522SAndroid Build Coastguard Worker date_str, '%Y-%m-%d %H:%M:%S.%f') 905*288bf522SAndroid Build Coastguard Worker return datetime_to_unix_time(ndate) 906*288bf522SAndroid Build Coastguard Worker return f 907*288bf522SAndroid Build Coastguard Worker 908*288bf522SAndroid Build Coastguard Workerdef datetime_to_unix_time(ndate): 909*288bf522SAndroid Build Coastguard Worker return time.mktime(ndate.timetuple()) + ndate.microsecond/1000000.0 910*288bf522SAndroid Build Coastguard Worker 911*288bf522SAndroid Build Coastguard Workerdef stddev(data): 912*288bf522SAndroid Build Coastguard Worker items_count = len(data) 913*288bf522SAndroid Build Coastguard Worker avg = sum(data) / items_count 914*288bf522SAndroid Build Coastguard Worker sq_diffs_sum = sum([(v - avg) ** 2 for v in data]) 915*288bf522SAndroid Build Coastguard Worker variance = sq_diffs_sum / items_count 916*288bf522SAndroid Build Coastguard Worker return math.sqrt(variance) 917*288bf522SAndroid Build Coastguard Worker 918*288bf522SAndroid Build Coastguard Workerdef grab_bootchart(boot_chart_file_path): 919*288bf522SAndroid Build Coastguard Worker subprocess.run("$ANDROID_BUILD_TOP/system/core/init/grab-bootchart.sh", shell=True, 920*288bf522SAndroid Build Coastguard Worker stdout=subprocess.DEVNULL) 921*288bf522SAndroid Build Coastguard Worker print("Saving boot chart as " + boot_chart_file_path + ".tgz") 922*288bf522SAndroid Build Coastguard Worker subprocess.call('cp /tmp/android-bootchart/bootchart.tgz ' + boot_chart_file_path + '.tgz', \ 923*288bf522SAndroid Build Coastguard Worker shell=True) 924*288bf522SAndroid Build Coastguard Worker subprocess.call('cp ./bootchart.png ' + boot_chart_file_path + '.png', shell=True) 925*288bf522SAndroid Build Coastguard Worker 926*288bf522SAndroid Build Coastguard Workerdef grab_systrace(systrace_file_path_prefix): 927*288bf522SAndroid Build Coastguard Worker trace_file = systrace_file_path_prefix + "_trace.txt" 928*288bf522SAndroid Build Coastguard Worker with open(trace_file, 'w') as f: 929*288bf522SAndroid Build Coastguard Worker f.write("TRACE:\n") 930*288bf522SAndroid Build Coastguard Worker run_adb_shell_cmd_as_root("cat /d/tracing/trace >> " + trace_file) 931*288bf522SAndroid Build Coastguard Worker html_file = systrace_file_path_prefix + ".html" 932*288bf522SAndroid Build Coastguard Worker subprocess.call("$ANDROID_BUILD_TOP/external/chromium-trace/systrace.py --from-file=" + trace_file + " -o " +\ 933*288bf522SAndroid Build Coastguard Worker html_file, shell=True) 934*288bf522SAndroid Build Coastguard Worker 935*288bf522SAndroid Build Coastguard Workerdef capture_build_info(out_dir, build_info_file_name): 936*288bf522SAndroid Build Coastguard Worker fingerprint = run_adb_shell_cmd('getprop ro.build.fingerprint', True) 937*288bf522SAndroid Build Coastguard Worker brand = run_adb_shell_cmd('getprop ro.product.brand', True) 938*288bf522SAndroid Build Coastguard Worker product = run_adb_shell_cmd('getprop ro.product.name', True) 939*288bf522SAndroid Build Coastguard Worker device = run_adb_shell_cmd('getprop ro.product.device', True) 940*288bf522SAndroid Build Coastguard Worker version_release = run_adb_shell_cmd('getprop ro.build.version.release', True) 941*288bf522SAndroid Build Coastguard Worker id = run_adb_shell_cmd('getprop ro.build.id', True) 942*288bf522SAndroid Build Coastguard Worker version_incremental = run_adb_shell_cmd('getprop ro.build.version.incremental', True) 943*288bf522SAndroid Build Coastguard Worker type = run_adb_shell_cmd('getprop ro.build.type', True) 944*288bf522SAndroid Build Coastguard Worker tags = run_adb_shell_cmd('getprop ro.build.tags', True) 945*288bf522SAndroid Build Coastguard Worker sdk = run_adb_shell_cmd('getprop ro.build.version.sdk', True) 946*288bf522SAndroid Build Coastguard Worker platform_minor = run_adb_shell_cmd('getprop ro.android.car.version.platform_minor', True) 947*288bf522SAndroid Build Coastguard Worker codename = run_adb_shell_cmd('getprop ro.build.version.codename', True) 948*288bf522SAndroid Build Coastguard Worker carwatchdog_collection_interval = run_adb_shell_cmd('getprop ro.carwatchdog.system_event_collection_interval', True) 949*288bf522SAndroid Build Coastguard Worker carwatchdog_post_event_duration = run_adb_shell_cmd('getprop ro.carwatchdog.post_system_event_duration', True) 950*288bf522SAndroid Build Coastguard Worker carwatchdog_top_n_category = run_adb_shell_cmd('getprop ro.carwatchdog.top_n_stats_per_category', True) 951*288bf522SAndroid Build Coastguard Worker carwatchdog_top_n_subcategory = run_adb_shell_cmd('getprop ro.carwatchdog.top_n_stats_per_subcategory', True) 952*288bf522SAndroid Build Coastguard Worker 953*288bf522SAndroid Build Coastguard Worker # TODO: Change file format to JSON to avoid custom parser 954*288bf522SAndroid Build Coastguard Worker build_info = [] 955*288bf522SAndroid Build Coastguard Worker build_info.append('Build information: ') 956*288bf522SAndroid Build Coastguard Worker build_info.append('-' * 20) 957*288bf522SAndroid Build Coastguard Worker build_info.append('fingerprint: ' + fingerprint) 958*288bf522SAndroid Build Coastguard Worker build_info.append('brand: ' + brand) 959*288bf522SAndroid Build Coastguard Worker build_info.append('product: ' + product) 960*288bf522SAndroid Build Coastguard Worker build_info.append('device: ' + device) 961*288bf522SAndroid Build Coastguard Worker build_info.append('version.release: ' + version_release) 962*288bf522SAndroid Build Coastguard Worker build_info.append('id: ' + id) 963*288bf522SAndroid Build Coastguard Worker build_info.append('version.incremental: ' + version_incremental) 964*288bf522SAndroid Build Coastguard Worker build_info.append('type: ' + type) 965*288bf522SAndroid Build Coastguard Worker build_info.append('tags: ' + tags) 966*288bf522SAndroid Build Coastguard Worker build_info.append('sdk: ' + sdk) 967*288bf522SAndroid Build Coastguard Worker build_info.append('platform minor version: ' + platform_minor) 968*288bf522SAndroid Build Coastguard Worker build_info.append('codename: ' + codename) 969*288bf522SAndroid Build Coastguard Worker build_info.append('carwatchdog collection interval (s): ' + carwatchdog_collection_interval) 970*288bf522SAndroid Build Coastguard Worker build_info.append('carwatchdog post event duration (s): ' + carwatchdog_post_event_duration) 971*288bf522SAndroid Build Coastguard Worker build_info.append('carwatchdog top N packages: ' + carwatchdog_top_n_category) 972*288bf522SAndroid Build Coastguard Worker build_info.append('carwatchdog top N processes: ' + carwatchdog_top_n_subcategory) 973*288bf522SAndroid Build Coastguard Worker 974*288bf522SAndroid Build Coastguard Worker build_info_str = '\n'.join(build_info) 975*288bf522SAndroid Build Coastguard Worker 976*288bf522SAndroid Build Coastguard Worker with open(out_dir + '/' + build_info_file_name, 'w') as f: 977*288bf522SAndroid Build Coastguard Worker f.write(build_info_str) 978*288bf522SAndroid Build Coastguard Worker 979*288bf522SAndroid Build Coastguard Workerdef generate_proto(dump_file, build_info_file, out_proto_file): 980*288bf522SAndroid Build Coastguard Worker subprocess.run("{} -f {} -b {} -d {}".format(CARWATCHDOG_PARSER_CMD, 981*288bf522SAndroid Build Coastguard Worker dump_file, 982*288bf522SAndroid Build Coastguard Worker build_info_file, 983*288bf522SAndroid Build Coastguard Worker out_proto_file), 984*288bf522SAndroid Build Coastguard Worker shell=True, stdout=subprocess.DEVNULL) 985*288bf522SAndroid Build Coastguard Worker 986*288bf522SAndroid Build Coastguard Workerdef grab_carwatchdog_bootstats(result_dir): 987*288bf522SAndroid Build Coastguard Worker carwatchdog_state = run_adb_shell_cmd_as_root('getprop init.svc.carwatchdogd', True) 988*288bf522SAndroid Build Coastguard Worker if carwatchdog_state != "running": 989*288bf522SAndroid Build Coastguard Worker print('carwatchdog (-d) flag set but CarWatchdog is not running on device') 990*288bf522SAndroid Build Coastguard Worker return 991*288bf522SAndroid Build Coastguard Worker elif not result_dir: 992*288bf522SAndroid Build Coastguard Worker print('carwatchdog needs the output directory to be specified.') 993*288bf522SAndroid Build Coastguard Worker return 994*288bf522SAndroid Build Coastguard Worker print("Capturing carwatchdog stats") 995*288bf522SAndroid Build Coastguard Worker build_info_file_name = "device_build_info.txt" 996*288bf522SAndroid Build Coastguard Worker capture_build_info(result_dir, build_info_file_name) 997*288bf522SAndroid Build Coastguard Worker 998*288bf522SAndroid Build Coastguard Worker # Capture CW dump and save dump to txt 999*288bf522SAndroid Build Coastguard Worker dump_file_name = result_dir + '/carwatchdog_dump.txt' 1000*288bf522SAndroid Build Coastguard Worker subprocess.call(CARWATCHDOG_DUMP_COMMAND + " > " + dump_file_name, shell=True) 1001*288bf522SAndroid Build Coastguard Worker 1002*288bf522SAndroid Build Coastguard Worker # Generate proto from dump 1003*288bf522SAndroid Build Coastguard Worker build_info_file_path = result_dir + '/' + build_info_file_name 1004*288bf522SAndroid Build Coastguard Worker out_proto_file_path = result_dir + '/carwatchdog_perf_stats_out.pb' 1005*288bf522SAndroid Build Coastguard Worker generate_proto(dump_file_name, build_info_file_path, out_proto_file_path) 1006*288bf522SAndroid Build Coastguard Worker 1007*288bf522SAndroid Build Coastguard Worker 1008*288bf522SAndroid Build Coastguard Workerif __name__ == '__main__': 1009*288bf522SAndroid Build Coastguard Worker main() 1010