1*288bf522SAndroid Build Coastguard Worker#!/usr/bin/env python 2*288bf522SAndroid Build Coastguard Worker# 3*288bf522SAndroid Build Coastguard Worker# Copyright (C) 2022 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"""Reports disk I/O usage by UID/Package, process, and file level breakdowns.""" 18*288bf522SAndroid Build Coastguard Worker 19*288bf522SAndroid Build Coastguard Workerfrom datetime import datetime 20*288bf522SAndroid Build Coastguard Workerfrom collections import namedtuple 21*288bf522SAndroid Build Coastguard Worker 22*288bf522SAndroid Build Coastguard Workerimport androidFsParser 23*288bf522SAndroid Build Coastguard Workerimport argparse 24*288bf522SAndroid Build Coastguard Workerimport collections 25*288bf522SAndroid Build Coastguard Workerimport os 26*288bf522SAndroid Build Coastguard Workerimport psutil 27*288bf522SAndroid Build Coastguard Workerimport re 28*288bf522SAndroid Build Coastguard Workerimport signal 29*288bf522SAndroid Build Coastguard Workerimport subprocess 30*288bf522SAndroid Build Coastguard Workerimport sys 31*288bf522SAndroid Build Coastguard Workerimport threading 32*288bf522SAndroid Build Coastguard Workerimport time 33*288bf522SAndroid Build Coastguard Workerimport uidProcessMapper 34*288bf522SAndroid Build Coastguard Worker 35*288bf522SAndroid Build Coastguard Worker# ex) lrwxrwxrwx 1 root root 16 1970-01-06 13:22 userdata -> /dev/block/sda14 36*288bf522SAndroid Build Coastguard WorkerRE_LS_BLOCK_DEVICE = r"\S+\s[0-9]+\s\S+\s\S+\s+[0-9]+\s[0-9\-]+\s[0-9]+\:[0-9]+\suserdata\s\-\>\s\/dev\/block\/(\S+)" 37*288bf522SAndroid Build Coastguard Worker 38*288bf522SAndroid Build Coastguard Worker# ex) 1002 246373245 418936352 1818624 0 0 0 0 0 0 0 39*288bf522SAndroid Build Coastguard WorkerRE_UID_IO_STATS_LINE = r"([0-9]+)\s([0-9]+)\s([0-9]+)\s([0-9]+)\s([0-9]+)\s([0-9]+)\s([0-9]+)\s([0-9]+)\s([0-9]+)\s([0-9]+)\s([0-9]+)" 40*288bf522SAndroid Build Coastguard Worker 41*288bf522SAndroid Build Coastguard Worker# ex) 253 5 dm-5 3117 0 354656 3324 0 0 0 0 0 2696 3324 0 0 0 0 42*288bf522SAndroid Build Coastguard WorkerRE_DISK_STATS_LINE = r"\s+([0-9]+)\s+([0-9]+)\s([a-z\-0-9]+)\s([0-9]+)\s([0-9]+)\s([0-9]+)\s([0-9]+)\s([0-9]+)\s([0-9]+)\s([0-9]+)\s([0-9]+)\s([0-9]+)\s([0-9]+)\s([0-9]+)\s([0-9]+)\s([0-9]+)\s([0-9]+)\s([0-9]+)" 43*288bf522SAndroid Build Coastguard Worker 44*288bf522SAndroid Build Coastguard WorkerADB_CMD = "adb" 45*288bf522SAndroid Build Coastguard Worker 46*288bf522SAndroid Build Coastguard WorkerTEMP_TRACE_FILE = "temp_trace_file.txt" 47*288bf522SAndroid Build Coastguard WorkerCARWATCHDOG_DUMP = "carwatchdog_dump.txt" 48*288bf522SAndroid Build Coastguard WorkerOUTPUT_FILE = "ioblame_out.txt" 49*288bf522SAndroid Build Coastguard Worker 50*288bf522SAndroid Build Coastguard WorkerWATCHDOG_BUFFER_SECS = 600 51*288bf522SAndroid Build Coastguard Worker 52*288bf522SAndroid Build Coastguard WorkerDID_RECEIVE_SIGINT = False 53*288bf522SAndroid Build Coastguard Worker 54*288bf522SAndroid Build Coastguard Worker 55*288bf522SAndroid Build Coastguard Workerdef signal_handler(sig, frame): 56*288bf522SAndroid Build Coastguard Worker global DID_RECEIVE_SIGINT 57*288bf522SAndroid Build Coastguard Worker DID_RECEIVE_SIGINT = True 58*288bf522SAndroid Build Coastguard Worker print("Received signal interrupt") 59*288bf522SAndroid Build Coastguard Worker 60*288bf522SAndroid Build Coastguard Worker 61*288bf522SAndroid Build Coastguard Workerdef init_arguments(): 62*288bf522SAndroid Build Coastguard Worker parser = argparse.ArgumentParser( 63*288bf522SAndroid Build Coastguard Worker description="Collect and process f2fs traces") 64*288bf522SAndroid Build Coastguard Worker parser.add_argument( 65*288bf522SAndroid Build Coastguard Worker "-s", 66*288bf522SAndroid Build Coastguard Worker "--serial", 67*288bf522SAndroid Build Coastguard Worker dest="serial", 68*288bf522SAndroid Build Coastguard Worker action="store", 69*288bf522SAndroid Build Coastguard Worker help="Android device serial number") 70*288bf522SAndroid Build Coastguard Worker parser.add_argument( 71*288bf522SAndroid Build Coastguard Worker "-r", 72*288bf522SAndroid Build Coastguard Worker "--trace_reads", 73*288bf522SAndroid Build Coastguard Worker default=False, 74*288bf522SAndroid Build Coastguard Worker action="store_true", 75*288bf522SAndroid Build Coastguard Worker dest="traceReads", 76*288bf522SAndroid Build Coastguard Worker help="Trace f2fs_dataread_start") 77*288bf522SAndroid Build Coastguard Worker parser.add_argument( 78*288bf522SAndroid Build Coastguard Worker "-w", 79*288bf522SAndroid Build Coastguard Worker "--trace_writes", 80*288bf522SAndroid Build Coastguard Worker default=False, 81*288bf522SAndroid Build Coastguard Worker action="store_true", 82*288bf522SAndroid Build Coastguard Worker dest="traceWrites", 83*288bf522SAndroid Build Coastguard Worker help="Trace f2fs_datawrite_start") 84*288bf522SAndroid Build Coastguard Worker parser.add_argument( 85*288bf522SAndroid Build Coastguard Worker "-d", 86*288bf522SAndroid Build Coastguard Worker "--trace_duration", 87*288bf522SAndroid Build Coastguard Worker type=int, 88*288bf522SAndroid Build Coastguard Worker default=3600, 89*288bf522SAndroid Build Coastguard Worker dest="traceDuration", 90*288bf522SAndroid Build Coastguard Worker help="Total trace duration in seconds") 91*288bf522SAndroid Build Coastguard Worker parser.add_argument( 92*288bf522SAndroid Build Coastguard Worker "-i", 93*288bf522SAndroid Build Coastguard Worker "--sampling_interval", 94*288bf522SAndroid Build Coastguard Worker type=int, 95*288bf522SAndroid Build Coastguard Worker default=300, 96*288bf522SAndroid Build Coastguard Worker dest="samplingInterval", 97*288bf522SAndroid Build Coastguard Worker help="Sampling interval in seconds for CarWatchdog collection (applicable only on" 98*288bf522SAndroid Build Coastguard Worker " automotive form-factor") 99*288bf522SAndroid Build Coastguard Worker parser.add_argument( 100*288bf522SAndroid Build Coastguard Worker "-o", 101*288bf522SAndroid Build Coastguard Worker "--output_directory", 102*288bf522SAndroid Build Coastguard Worker type=dir_path, 103*288bf522SAndroid Build Coastguard Worker default=os.getcwd(), 104*288bf522SAndroid Build Coastguard Worker dest="outputDir", 105*288bf522SAndroid Build Coastguard Worker help="Output directory") 106*288bf522SAndroid Build Coastguard Worker 107*288bf522SAndroid Build Coastguard Worker return parser.parse_args() 108*288bf522SAndroid Build Coastguard Worker 109*288bf522SAndroid Build Coastguard Worker 110*288bf522SAndroid Build Coastguard Workerdef verify_arguments(args): 111*288bf522SAndroid Build Coastguard Worker if args.serial is not None: 112*288bf522SAndroid Build Coastguard Worker global ADB_CMD 113*288bf522SAndroid Build Coastguard Worker ADB_CMD = "%s %s" % ("adb -s", args.serial) 114*288bf522SAndroid Build Coastguard Worker if not args.traceReads and not args.traceWrites: 115*288bf522SAndroid Build Coastguard Worker raise argparse.ArgumentTypeError( 116*288bf522SAndroid Build Coastguard Worker "Must provide at least one of the --trace_reads or --trace_writes options" 117*288bf522SAndroid Build Coastguard Worker ) 118*288bf522SAndroid Build Coastguard Worker 119*288bf522SAndroid Build Coastguard Worker 120*288bf522SAndroid Build Coastguard Workerdef dir_path(path): 121*288bf522SAndroid Build Coastguard Worker if os.path.isdir(path): 122*288bf522SAndroid Build Coastguard Worker return path 123*288bf522SAndroid Build Coastguard Worker else: 124*288bf522SAndroid Build Coastguard Worker raise argparse.ArgumentTypeError( 125*288bf522SAndroid Build Coastguard Worker "{} is not a valid directory path".format(path)) 126*288bf522SAndroid Build Coastguard Worker 127*288bf522SAndroid Build Coastguard Worker 128*288bf522SAndroid Build Coastguard Workerdef run_adb_cmd(cmd): 129*288bf522SAndroid Build Coastguard Worker r = subprocess.check_output(ADB_CMD + " " + cmd, shell=True) 130*288bf522SAndroid Build Coastguard Worker return r.decode("utf-8") 131*288bf522SAndroid Build Coastguard Worker 132*288bf522SAndroid Build Coastguard Worker 133*288bf522SAndroid Build Coastguard Workerdef run_adb_shell_cmd(cmd): 134*288bf522SAndroid Build Coastguard Worker return run_adb_cmd("shell " + cmd) 135*288bf522SAndroid Build Coastguard Worker 136*288bf522SAndroid Build Coastguard Worker 137*288bf522SAndroid Build Coastguard Workerdef run_adb_shell_cmd_strip_output(cmd): 138*288bf522SAndroid Build Coastguard Worker return run_adb_cmd("shell " + cmd).strip() 139*288bf522SAndroid Build Coastguard Worker 140*288bf522SAndroid Build Coastguard Worker 141*288bf522SAndroid Build Coastguard Workerdef run_adb_shell_cmd_ignore_err(cmd): 142*288bf522SAndroid Build Coastguard Worker try: 143*288bf522SAndroid Build Coastguard Worker r = subprocess.run( 144*288bf522SAndroid Build Coastguard Worker ADB_CMD + " shell " + cmd, shell=True, capture_output=True) 145*288bf522SAndroid Build Coastguard Worker return r.stdout.decode("utf-8") 146*288bf522SAndroid Build Coastguard Worker except Exception: 147*288bf522SAndroid Build Coastguard Worker return "" 148*288bf522SAndroid Build Coastguard Worker 149*288bf522SAndroid Build Coastguard Worker 150*288bf522SAndroid Build Coastguard Workerdef run_shell_cmd(cmd): 151*288bf522SAndroid Build Coastguard Worker return subprocess.check_output(cmd, shell=True) 152*288bf522SAndroid Build Coastguard Worker 153*288bf522SAndroid Build Coastguard Worker 154*288bf522SAndroid Build Coastguard Workerdef run_bg_adb_shell_cmd(cmd): 155*288bf522SAndroid Build Coastguard Worker return subprocess.Popen(ADB_CMD + " shell " + cmd, shell=True) 156*288bf522SAndroid Build Coastguard Worker 157*288bf522SAndroid Build Coastguard Worker 158*288bf522SAndroid Build Coastguard Workerdef run_bg_shell_cmd(cmd): 159*288bf522SAndroid Build Coastguard Worker return subprocess.Popen(cmd, shell=True) 160*288bf522SAndroid Build Coastguard Worker 161*288bf522SAndroid Build Coastguard Worker 162*288bf522SAndroid Build Coastguard Workerdef get_block_dev(): 163*288bf522SAndroid Build Coastguard Worker model = run_adb_shell_cmd_strip_output( 164*288bf522SAndroid Build Coastguard Worker "'getprop ro.product.name' | sed \'s/[ \\t\\r\\n]*$//\'") 165*288bf522SAndroid Build Coastguard Worker print("Found %s Device" % model) 166*288bf522SAndroid Build Coastguard Worker 167*288bf522SAndroid Build Coastguard Worker if "emu" in model: 168*288bf522SAndroid Build Coastguard Worker return "vda" 169*288bf522SAndroid Build Coastguard Worker 170*288bf522SAndroid Build Coastguard Worker result = run_adb_shell_cmd_strip_output( 171*288bf522SAndroid Build Coastguard Worker "'ls -la /dev/block/bootdevice/by-name | grep userdata'") 172*288bf522SAndroid Build Coastguard Worker 173*288bf522SAndroid Build Coastguard Worker match = re.compile(RE_LS_BLOCK_DEVICE).match(result) 174*288bf522SAndroid Build Coastguard Worker if not match: 175*288bf522SAndroid Build Coastguard Worker print("Unknown Device {} -- trying Pixel config".format(model)) 176*288bf522SAndroid Build Coastguard Worker return "sda" 177*288bf522SAndroid Build Coastguard Worker 178*288bf522SAndroid Build Coastguard Worker return match.group(1) 179*288bf522SAndroid Build Coastguard Worker 180*288bf522SAndroid Build Coastguard Worker 181*288bf522SAndroid Build Coastguard Workerdef prep_to_do_something(): 182*288bf522SAndroid Build Coastguard Worker run_adb_shell_cmd("'echo 3 > /proc/sys/vm/drop_caches'") 183*288bf522SAndroid Build Coastguard Worker time.sleep(1) 184*288bf522SAndroid Build Coastguard Worker 185*288bf522SAndroid Build Coastguard Worker 186*288bf522SAndroid Build Coastguard Workerdef setup_tracepoints(shouldTraceReads, shouldTraceWrites): 187*288bf522SAndroid Build Coastguard Worker # This is a good point to check if the Android FS tracepoints are enabled in the 188*288bf522SAndroid Build Coastguard Worker # kernel or not 189*288bf522SAndroid Build Coastguard Worker isTraceEnabled = run_adb_shell_cmd( 190*288bf522SAndroid Build Coastguard Worker "'if [ -d /sys/kernel/tracing/events/f2fs ]; then echo 0; else echo 1; fi'" 191*288bf522SAndroid Build Coastguard Worker ) 192*288bf522SAndroid Build Coastguard Worker 193*288bf522SAndroid Build Coastguard Worker if isTraceEnabled == 0: 194*288bf522SAndroid Build Coastguard Worker raise RuntimeError("Android FS tracing is not enabled") 195*288bf522SAndroid Build Coastguard Worker 196*288bf522SAndroid Build Coastguard Worker run_adb_shell_cmd("'echo 0 > /sys/kernel/tracing/tracing_on;\ 197*288bf522SAndroid Build Coastguard Worker echo 0 > /sys/kernel/tracing/trace;\ 198*288bf522SAndroid Build Coastguard Worker echo 0 > /sys/kernel/tracing/events/ext4/enable;\ 199*288bf522SAndroid Build Coastguard Worker echo 0 > /sys/kernel/tracing/events/block/enable'") 200*288bf522SAndroid Build Coastguard Worker 201*288bf522SAndroid Build Coastguard Worker if shouldTraceReads: 202*288bf522SAndroid Build Coastguard Worker run_adb_shell_cmd( 203*288bf522SAndroid Build Coastguard Worker "'echo 1 > /sys/kernel/tracing/events/f2fs/f2fs_dataread_start/enable'" 204*288bf522SAndroid Build Coastguard Worker ) 205*288bf522SAndroid Build Coastguard Worker 206*288bf522SAndroid Build Coastguard Worker if shouldTraceWrites: 207*288bf522SAndroid Build Coastguard Worker run_adb_shell_cmd( 208*288bf522SAndroid Build Coastguard Worker "'echo 1 > /sys/kernel/tracing/events/f2fs/f2fs_datawrite_start/enable'" 209*288bf522SAndroid Build Coastguard Worker ) 210*288bf522SAndroid Build Coastguard Worker 211*288bf522SAndroid Build Coastguard Worker run_adb_shell_cmd("'echo 1 > /sys/kernel/tracing/tracing_on'") 212*288bf522SAndroid Build Coastguard Worker 213*288bf522SAndroid Build Coastguard Worker 214*288bf522SAndroid Build Coastguard Workerdef clear_tracing(shouldTraceReads, shouldTraceWrites): 215*288bf522SAndroid Build Coastguard Worker if shouldTraceReads: 216*288bf522SAndroid Build Coastguard Worker run_adb_shell_cmd( 217*288bf522SAndroid Build Coastguard Worker "'echo 0 > /sys/kernel/tracing/events/f2fs/f2fs_dataread_start/enable'" 218*288bf522SAndroid Build Coastguard Worker ) 219*288bf522SAndroid Build Coastguard Worker 220*288bf522SAndroid Build Coastguard Worker if shouldTraceWrites: 221*288bf522SAndroid Build Coastguard Worker run_adb_shell_cmd( 222*288bf522SAndroid Build Coastguard Worker "'echo 0 > /sys/kernel/tracing/events/f2fs/f2fs_datawrite_start/enable'" 223*288bf522SAndroid Build Coastguard Worker ) 224*288bf522SAndroid Build Coastguard Worker 225*288bf522SAndroid Build Coastguard Worker run_adb_shell_cmd("'echo 0 > /sys/kernel/tracing/tracing_on'") 226*288bf522SAndroid Build Coastguard Worker 227*288bf522SAndroid Build Coastguard Worker 228*288bf522SAndroid Build Coastguard Workerdef start_streaming_trace(traceFile): 229*288bf522SAndroid Build Coastguard Worker return run_bg_adb_shell_cmd( 230*288bf522SAndroid Build Coastguard Worker "'cat /sys/kernel/tracing/trace_pipe | grep -e f2fs_data -e f2fs_writepages'\ 231*288bf522SAndroid Build Coastguard Worker > {}".format(traceFile)) 232*288bf522SAndroid Build Coastguard Worker 233*288bf522SAndroid Build Coastguard Worker 234*288bf522SAndroid Build Coastguard Workerdef stop_streaming_trace(sub_proc): 235*288bf522SAndroid Build Coastguard Worker process = psutil.Process(sub_proc.pid) 236*288bf522SAndroid Build Coastguard Worker for child_proc in process.children(recursive=True): 237*288bf522SAndroid Build Coastguard Worker child_proc.kill() 238*288bf522SAndroid Build Coastguard Worker process.kill() 239*288bf522SAndroid Build Coastguard Worker 240*288bf522SAndroid Build Coastguard Worker 241*288bf522SAndroid Build Coastguard Workerclass carwatchdog_collection(threading.Thread): 242*288bf522SAndroid Build Coastguard Worker 243*288bf522SAndroid Build Coastguard Worker def __init__(self, traceDuration, samplingInterval): 244*288bf522SAndroid Build Coastguard Worker threading.Thread.__init__(self) 245*288bf522SAndroid Build Coastguard Worker self.traceDuration = traceDuration 246*288bf522SAndroid Build Coastguard Worker self.samplingInterval = samplingInterval 247*288bf522SAndroid Build Coastguard Worker 248*288bf522SAndroid Build Coastguard Worker def run(self): 249*288bf522SAndroid Build Coastguard Worker isBootCompleted = 0 250*288bf522SAndroid Build Coastguard Worker 251*288bf522SAndroid Build Coastguard Worker while isBootCompleted == 0: 252*288bf522SAndroid Build Coastguard Worker isBootCompleted = run_adb_shell_cmd_strip_output( 253*288bf522SAndroid Build Coastguard Worker "'getprop sys.boot_completed'") 254*288bf522SAndroid Build Coastguard Worker time.sleep(1) 255*288bf522SAndroid Build Coastguard Worker 256*288bf522SAndroid Build Coastguard Worker # Clean up previous state. 257*288bf522SAndroid Build Coastguard Worker run_adb_shell_cmd( 258*288bf522SAndroid Build Coastguard Worker "'dumpsys android.automotive.watchdog.ICarWatchdog/default\ 259*288bf522SAndroid Build Coastguard Worker --stop_perf &>/dev/null'") 260*288bf522SAndroid Build Coastguard Worker 261*288bf522SAndroid Build Coastguard Worker run_adb_shell_cmd( 262*288bf522SAndroid Build Coastguard Worker "'dumpsys android.automotive.watchdog.ICarWatchdog/default \ 263*288bf522SAndroid Build Coastguard Worker --start_perf --max_duration {} --interval {}'".format( 264*288bf522SAndroid Build Coastguard Worker self.traceDuration + WATCHDOG_BUFFER_SECS, self.samplingInterval)) 265*288bf522SAndroid Build Coastguard Worker 266*288bf522SAndroid Build Coastguard Worker 267*288bf522SAndroid Build Coastguard Workerdef stop_carwatchdog_collection(outputDir): 268*288bf522SAndroid Build Coastguard Worker run_adb_shell_cmd("'dumpsys android.automotive.watchdog.ICarWatchdog/default" 269*288bf522SAndroid Build Coastguard Worker " --stop_perf' > {}/{}".format(outputDir, CARWATCHDOG_DUMP)) 270*288bf522SAndroid Build Coastguard Worker 271*288bf522SAndroid Build Coastguard Worker 272*288bf522SAndroid Build Coastguard Workerdef do_something(outpuDir, traceDuration, samplingInterval, uidProcessMapperObj): 273*288bf522SAndroid Build Coastguard Worker buildChars = run_adb_shell_cmd_strip_output( 274*288bf522SAndroid Build Coastguard Worker "'getprop ro.build.characteristics'") 275*288bf522SAndroid Build Coastguard Worker 276*288bf522SAndroid Build Coastguard Worker carwatchdog_collection_thread = None 277*288bf522SAndroid Build Coastguard Worker if "automotive" in buildChars: 278*288bf522SAndroid Build Coastguard Worker carwatchdog_collection_thread = carwatchdog_collection( 279*288bf522SAndroid Build Coastguard Worker traceDuration, samplingInterval) 280*288bf522SAndroid Build Coastguard Worker carwatchdog_collection_thread.start() 281*288bf522SAndroid Build Coastguard Worker 282*288bf522SAndroid Build Coastguard Worker for i in range(1, traceDuration): 283*288bf522SAndroid Build Coastguard Worker if DID_RECEIVE_SIGINT: 284*288bf522SAndroid Build Coastguard Worker break 285*288bf522SAndroid Build Coastguard Worker now = time.process_time() 286*288bf522SAndroid Build Coastguard Worker read_uid_process_mapping(uidProcessMapperObj) 287*288bf522SAndroid Build Coastguard Worker taken = time.process_time() - now 288*288bf522SAndroid Build Coastguard Worker if (taken < 1): 289*288bf522SAndroid Build Coastguard Worker time.sleep(1 - taken) 290*288bf522SAndroid Build Coastguard Worker 291*288bf522SAndroid Build Coastguard Worker read_uid_package_mapping(uidProcessMapperObj) 292*288bf522SAndroid Build Coastguard Worker 293*288bf522SAndroid Build Coastguard Worker if "automotive" in buildChars: 294*288bf522SAndroid Build Coastguard Worker carwatchdog_collection_thread.join() 295*288bf522SAndroid Build Coastguard Worker stop_carwatchdog_collection(outpuDir) 296*288bf522SAndroid Build Coastguard Worker 297*288bf522SAndroid Build Coastguard Worker 298*288bf522SAndroid Build Coastguard Workerdef read_uid_process_mapping(uidProcessMapperObj): 299*288bf522SAndroid Build Coastguard Worker procStatusDump = run_adb_shell_cmd_ignore_err( 300*288bf522SAndroid Build Coastguard Worker "'cat /proc/*/status /proc/*/task/*/status 2> /dev/null'") 301*288bf522SAndroid Build Coastguard Worker 302*288bf522SAndroid Build Coastguard Worker uidProcessMapperObj.parse_proc_status_dump(procStatusDump) 303*288bf522SAndroid Build Coastguard Worker 304*288bf522SAndroid Build Coastguard Worker 305*288bf522SAndroid Build Coastguard Workerdef read_uid_package_mapping(uidProcessMapperObj): 306*288bf522SAndroid Build Coastguard Worker packageMappingDump = run_adb_shell_cmd_ignore_err( 307*288bf522SAndroid Build Coastguard Worker "'pm list packages -a -U | sort | uniq'") 308*288bf522SAndroid Build Coastguard Worker 309*288bf522SAndroid Build Coastguard Worker uidProcessMapperObj.parse_uid_package_dump(packageMappingDump) 310*288bf522SAndroid Build Coastguard Worker 311*288bf522SAndroid Build Coastguard Worker 312*288bf522SAndroid Build Coastguard Worker# Parser for "/proc/diskstats". 313*288bf522SAndroid Build Coastguard Workerclass DiskStats: 314*288bf522SAndroid Build Coastguard Worker 315*288bf522SAndroid Build Coastguard Worker def __init__(self, readIos, readSectors, writeIos, writeSectors): 316*288bf522SAndroid Build Coastguard Worker self.readIos = readIos 317*288bf522SAndroid Build Coastguard Worker self.readSectors = readSectors 318*288bf522SAndroid Build Coastguard Worker self.writeIos = writeIos 319*288bf522SAndroid Build Coastguard Worker self.writeSectors = writeSectors 320*288bf522SAndroid Build Coastguard Worker 321*288bf522SAndroid Build Coastguard Worker def delta(self, other): 322*288bf522SAndroid Build Coastguard Worker return DiskStats(self.readIos - other.readIos, 323*288bf522SAndroid Build Coastguard Worker self.readSectors - other.readSectors, 324*288bf522SAndroid Build Coastguard Worker self.writeIos - other.writeIos, 325*288bf522SAndroid Build Coastguard Worker self.writeSectors - other.writeSectors) 326*288bf522SAndroid Build Coastguard Worker 327*288bf522SAndroid Build Coastguard Worker def dump(self, shouldDumpReads, shouldDumpWrites, outputFile): 328*288bf522SAndroid Build Coastguard Worker if self.readIos is None or self.readIos is None or self.readIos is None\ 329*288bf522SAndroid Build Coastguard Worker or self.readIos is None: 330*288bf522SAndroid Build Coastguard Worker outputFile.write("Missing disk stats") 331*288bf522SAndroid Build Coastguard Worker return 332*288bf522SAndroid Build Coastguard Worker 333*288bf522SAndroid Build Coastguard Worker if (shouldDumpReads): 334*288bf522SAndroid Build Coastguard Worker outputFile.write("Total dev block reads: {} KB, IOs: {}\n".format( 335*288bf522SAndroid Build Coastguard Worker self.readSectors / 2, self.readIos)) 336*288bf522SAndroid Build Coastguard Worker 337*288bf522SAndroid Build Coastguard Worker if (shouldDumpWrites): 338*288bf522SAndroid Build Coastguard Worker outputFile.write("Total dev block writes: {} KB, IOs: {}\n".format( 339*288bf522SAndroid Build Coastguard Worker self.writeSectors / 2, self.writeIos)) 340*288bf522SAndroid Build Coastguard Worker 341*288bf522SAndroid Build Coastguard Worker 342*288bf522SAndroid Build Coastguard Workerdef get_disk_stats(blockDev): 343*288bf522SAndroid Build Coastguard Worker line = run_adb_shell_cmd( 344*288bf522SAndroid Build Coastguard Worker "'cat /proc/diskstats' | fgrep -w {}".format(blockDev)) 345*288bf522SAndroid Build Coastguard Worker matcher = re.compile(RE_DISK_STATS_LINE) 346*288bf522SAndroid Build Coastguard Worker match = matcher.match(line) 347*288bf522SAndroid Build Coastguard Worker 348*288bf522SAndroid Build Coastguard Worker if not match: 349*288bf522SAndroid Build Coastguard Worker return None 350*288bf522SAndroid Build Coastguard Worker 351*288bf522SAndroid Build Coastguard Worker readIos = int(match.group(4)) 352*288bf522SAndroid Build Coastguard Worker readSectors = int(match.group(6)) 353*288bf522SAndroid Build Coastguard Worker writeIos = int(match.group(8)) 354*288bf522SAndroid Build Coastguard Worker writeSectors = int(match.group(10)) 355*288bf522SAndroid Build Coastguard Worker 356*288bf522SAndroid Build Coastguard Worker return DiskStats(readIos, readSectors, writeIos, writeSectors) 357*288bf522SAndroid Build Coastguard Worker 358*288bf522SAndroid Build Coastguard Worker 359*288bf522SAndroid Build Coastguard WorkerIoBytes = namedtuple("IoBytes", "rdBytes wrBytes") 360*288bf522SAndroid Build Coastguard Worker 361*288bf522SAndroid Build Coastguard Worker 362*288bf522SAndroid Build Coastguard Worker# Parser for "/proc/uid_io/stats". 363*288bf522SAndroid Build Coastguard Workerclass UidIoStats: 364*288bf522SAndroid Build Coastguard Worker 365*288bf522SAndroid Build Coastguard Worker def __init__(self): 366*288bf522SAndroid Build Coastguard Worker self.uidIoStatsReMatcher = re.compile(RE_UID_IO_STATS_LINE) 367*288bf522SAndroid Build Coastguard Worker self.ioBytesByUid = {} # Key: UID, Value: IoBytes 368*288bf522SAndroid Build Coastguard Worker self.totalIoBytes = IoBytes(rdBytes=0, wrBytes=0) 369*288bf522SAndroid Build Coastguard Worker 370*288bf522SAndroid Build Coastguard Worker def parse(self, dump): 371*288bf522SAndroid Build Coastguard Worker totalRdBytes = 0 372*288bf522SAndroid Build Coastguard Worker totalWrBytes = 0 373*288bf522SAndroid Build Coastguard Worker for line in dump.split("\n"): 374*288bf522SAndroid Build Coastguard Worker (uid, ioBytes) = self.parse_uid_io_bytes(line) 375*288bf522SAndroid Build Coastguard Worker self.ioBytesByUid[uid] = ioBytes 376*288bf522SAndroid Build Coastguard Worker totalRdBytes += ioBytes.rdBytes 377*288bf522SAndroid Build Coastguard Worker totalWrBytes += ioBytes.wrBytes 378*288bf522SAndroid Build Coastguard Worker 379*288bf522SAndroid Build Coastguard Worker self.totalIoBytes = IoBytes(rdBytes=totalRdBytes, wrBytes=totalWrBytes) 380*288bf522SAndroid Build Coastguard Worker 381*288bf522SAndroid Build Coastguard Worker def parse_uid_io_bytes(self, line): 382*288bf522SAndroid Build Coastguard Worker match = self.uidIoStatsReMatcher.match(line) 383*288bf522SAndroid Build Coastguard Worker if not match: 384*288bf522SAndroid Build Coastguard Worker return None 385*288bf522SAndroid Build Coastguard Worker return (int(match.group(1)), 386*288bf522SAndroid Build Coastguard Worker IoBytes( 387*288bf522SAndroid Build Coastguard Worker rdBytes=(int(match.group(4)) + int(match.group(8))), 388*288bf522SAndroid Build Coastguard Worker wrBytes=(int(match.group(5)) + int(match.group(9))))) 389*288bf522SAndroid Build Coastguard Worker 390*288bf522SAndroid Build Coastguard Worker def delta(self, other): 391*288bf522SAndroid Build Coastguard Worker deltaStats = UidIoStats() 392*288bf522SAndroid Build Coastguard Worker deltaStats.totalIoBytes = IoBytes( 393*288bf522SAndroid Build Coastguard Worker rdBytes=self.totalIoBytes.rdBytes - other.totalIoBytes.rdBytes, 394*288bf522SAndroid Build Coastguard Worker wrBytes=self.totalIoBytes.wrBytes - other.totalIoBytes.wrBytes) 395*288bf522SAndroid Build Coastguard Worker 396*288bf522SAndroid Build Coastguard Worker for uid, ioBytes in self.ioBytesByUid.items(): 397*288bf522SAndroid Build Coastguard Worker if uid not in other.ioBytesByUid: 398*288bf522SAndroid Build Coastguard Worker deltaStats.ioBytesByUid[uid] = ioBytes 399*288bf522SAndroid Build Coastguard Worker continue 400*288bf522SAndroid Build Coastguard Worker otherIoBytes = other.ioBytesByUid[uid] 401*288bf522SAndroid Build Coastguard Worker rdBytes = ioBytes.rdBytes - otherIoBytes.rdBytes if ioBytes.rdBytes > otherIoBytes.rdBytes\ 402*288bf522SAndroid Build Coastguard Worker else 0 403*288bf522SAndroid Build Coastguard Worker wrBytes = ioBytes.wrBytes - otherIoBytes.wrBytes if ioBytes.wrBytes > otherIoBytes.wrBytes\ 404*288bf522SAndroid Build Coastguard Worker else 0 405*288bf522SAndroid Build Coastguard Worker deltaStats.ioBytesByUid[uid] = IoBytes(rdBytes=rdBytes, wrBytes=wrBytes) 406*288bf522SAndroid Build Coastguard Worker return deltaStats 407*288bf522SAndroid Build Coastguard Worker 408*288bf522SAndroid Build Coastguard Worker def dumpTotal(self, mode, outputFile): 409*288bf522SAndroid Build Coastguard Worker totalBytes = self.totalIoBytes.wrBytes if mode == "write" else self.totalIoBytes.rdBytes 410*288bf522SAndroid Build Coastguard Worker outputFile.write("Total system-wide {} KB: {}\n".format( 411*288bf522SAndroid Build Coastguard Worker mode, to_kib(totalBytes))) 412*288bf522SAndroid Build Coastguard Worker 413*288bf522SAndroid Build Coastguard Worker def dump(self, uidProcessMapperObj, mode, func, outputFile): 414*288bf522SAndroid Build Coastguard Worker sortedEntries = collections.OrderedDict( 415*288bf522SAndroid Build Coastguard Worker sorted( 416*288bf522SAndroid Build Coastguard Worker self.ioBytesByUid.items(), 417*288bf522SAndroid Build Coastguard Worker key=lambda item: item[1].wrBytes 418*288bf522SAndroid Build Coastguard Worker if mode == "write" else item[1].rdBytes, 419*288bf522SAndroid Build Coastguard Worker reverse=True)) 420*288bf522SAndroid Build Coastguard Worker totalEntries = len(sortedEntries) 421*288bf522SAndroid Build Coastguard Worker for i in range(totalEntries): 422*288bf522SAndroid Build Coastguard Worker uid, ioBytes = sortedEntries.popitem(last=False) 423*288bf522SAndroid Build Coastguard Worker totalBytes = ioBytes.wrBytes if mode == "write" else ioBytes.rdBytes 424*288bf522SAndroid Build Coastguard Worker if totalBytes < androidFsParser.MIN_PID_BYTES: 425*288bf522SAndroid Build Coastguard Worker continue 426*288bf522SAndroid Build Coastguard Worker uidInfo = uidProcessMapperObj.get_uid_info(uid) 427*288bf522SAndroid Build Coastguard Worker outputFile.write("{}, Total {} KB: {}\n".format(uidInfo.to_string(), mode, 428*288bf522SAndroid Build Coastguard Worker to_kib(totalBytes))) 429*288bf522SAndroid Build Coastguard Worker func(uid) 430*288bf522SAndroid Build Coastguard Worker outputFile.write("\n" + ("=" * 100) + "\n") 431*288bf522SAndroid Build Coastguard Worker if i < totalEntries - 1: 432*288bf522SAndroid Build Coastguard Worker outputFile.write("\n") 433*288bf522SAndroid Build Coastguard Worker 434*288bf522SAndroid Build Coastguard Worker 435*288bf522SAndroid Build Coastguard Workerdef get_uid_io_stats(): 436*288bf522SAndroid Build Coastguard Worker uidIoStatsDump = run_adb_shell_cmd_strip_output("'cat /proc/uid_io/stats'") 437*288bf522SAndroid Build Coastguard Worker uidIoStats = UidIoStats() 438*288bf522SAndroid Build Coastguard Worker uidIoStats.parse(uidIoStatsDump) 439*288bf522SAndroid Build Coastguard Worker return uidIoStats 440*288bf522SAndroid Build Coastguard Worker 441*288bf522SAndroid Build Coastguard Worker 442*288bf522SAndroid Build Coastguard Workerdef to_kib(bytes): 443*288bf522SAndroid Build Coastguard Worker return bytes / 1024 444*288bf522SAndroid Build Coastguard Worker 445*288bf522SAndroid Build Coastguard Worker 446*288bf522SAndroid Build Coastguard Workerdef main(argv): 447*288bf522SAndroid Build Coastguard Worker signal.signal(signal.SIGINT, signal_handler) 448*288bf522SAndroid Build Coastguard Worker 449*288bf522SAndroid Build Coastguard Worker args = init_arguments() 450*288bf522SAndroid Build Coastguard Worker verify_arguments(args) 451*288bf522SAndroid Build Coastguard Worker 452*288bf522SAndroid Build Coastguard Worker run_adb_cmd("root") 453*288bf522SAndroid Build Coastguard Worker buildDesc = run_adb_shell_cmd_strip_output("'getprop ro.build.description'") 454*288bf522SAndroid Build Coastguard Worker blockDev = get_block_dev() 455*288bf522SAndroid Build Coastguard Worker 456*288bf522SAndroid Build Coastguard Worker prep_to_do_something() 457*288bf522SAndroid Build Coastguard Worker setup_tracepoints(args.traceReads, args.traceWrites) 458*288bf522SAndroid Build Coastguard Worker diskStatsBefore = get_disk_stats(blockDev) 459*288bf522SAndroid Build Coastguard Worker uidIoStatsBefore = get_uid_io_stats() 460*288bf522SAndroid Build Coastguard Worker 461*288bf522SAndroid Build Coastguard Worker traceFile = "{}/{}".format(args.outputDir, TEMP_TRACE_FILE) 462*288bf522SAndroid Build Coastguard Worker 463*288bf522SAndroid Build Coastguard Worker startDateTime = datetime.now() 464*288bf522SAndroid Build Coastguard Worker proc = start_streaming_trace(traceFile) 465*288bf522SAndroid Build Coastguard Worker print("Started trace streaming") 466*288bf522SAndroid Build Coastguard Worker 467*288bf522SAndroid Build Coastguard Worker uidProcessMapperObj = uidProcessMapper.UidProcessMapper() 468*288bf522SAndroid Build Coastguard Worker do_something(args.outputDir, args.traceDuration, args.samplingInterval, 469*288bf522SAndroid Build Coastguard Worker uidProcessMapperObj) 470*288bf522SAndroid Build Coastguard Worker 471*288bf522SAndroid Build Coastguard Worker stop_streaming_trace(proc) 472*288bf522SAndroid Build Coastguard Worker endDateTime = datetime.now() 473*288bf522SAndroid Build Coastguard Worker print("Stopped trace streaming") 474*288bf522SAndroid Build Coastguard Worker 475*288bf522SAndroid Build Coastguard Worker clear_tracing(args.traceReads, args.traceWrites) 476*288bf522SAndroid Build Coastguard Worker 477*288bf522SAndroid Build Coastguard Worker diskStatsAfter = get_disk_stats(blockDev) 478*288bf522SAndroid Build Coastguard Worker uidIoStatsAfter = get_uid_io_stats() 479*288bf522SAndroid Build Coastguard Worker diskStatsDelta = diskStatsAfter.delta(diskStatsBefore) 480*288bf522SAndroid Build Coastguard Worker uidIoStatsDelta = uidIoStatsAfter.delta(uidIoStatsBefore) 481*288bf522SAndroid Build Coastguard Worker 482*288bf522SAndroid Build Coastguard Worker print("Completed device side collection") 483*288bf522SAndroid Build Coastguard Worker 484*288bf522SAndroid Build Coastguard Worker writeParser = androidFsParser.AndroidFsParser(androidFsParser.RE_WRITE_START, 485*288bf522SAndroid Build Coastguard Worker uidProcessMapperObj) 486*288bf522SAndroid Build Coastguard Worker readParser = androidFsParser.AndroidFsParser(androidFsParser.RE_READ_START, 487*288bf522SAndroid Build Coastguard Worker uidProcessMapperObj) 488*288bf522SAndroid Build Coastguard Worker with open(traceFile) as file: 489*288bf522SAndroid Build Coastguard Worker for line in file: 490*288bf522SAndroid Build Coastguard Worker if args.traceWrites and writeParser.parse(line): 491*288bf522SAndroid Build Coastguard Worker continue 492*288bf522SAndroid Build Coastguard Worker if args.traceReads: 493*288bf522SAndroid Build Coastguard Worker readParser.parse(line) 494*288bf522SAndroid Build Coastguard Worker 495*288bf522SAndroid Build Coastguard Worker outputFile = open("{}/{}".format(args.outputDir, OUTPUT_FILE), "w") 496*288bf522SAndroid Build Coastguard Worker outputFile.write("Collection datetime: {}, Total duration: {}\n".format( 497*288bf522SAndroid Build Coastguard Worker endDateTime, endDateTime - startDateTime)) 498*288bf522SAndroid Build Coastguard Worker outputFile.write("Build description: {}\n".format(buildDesc)) 499*288bf522SAndroid Build Coastguard Worker outputFile.write( 500*288bf522SAndroid Build Coastguard Worker "Minimum KB per process or UID: {}, Small file KB: {}\n\n".format( 501*288bf522SAndroid Build Coastguard Worker to_kib(androidFsParser.MIN_PID_BYTES), 502*288bf522SAndroid Build Coastguard Worker to_kib(androidFsParser.SMALL_FILE_BYTES))) 503*288bf522SAndroid Build Coastguard Worker 504*288bf522SAndroid Build Coastguard Worker diskStatsDelta.dump(args.traceReads, args.traceWrites, outputFile) 505*288bf522SAndroid Build Coastguard Worker 506*288bf522SAndroid Build Coastguard Worker if args.traceWrites: 507*288bf522SAndroid Build Coastguard Worker uidIoStatsDelta.dumpTotal("write", outputFile) 508*288bf522SAndroid Build Coastguard Worker writeParser.dumpTotal(outputFile) 509*288bf522SAndroid Build Coastguard Worker uidIoStatsDelta.dump(uidProcessMapperObj, "write", 510*288bf522SAndroid Build Coastguard Worker lambda uid: writeParser.dump(uid, outputFile), 511*288bf522SAndroid Build Coastguard Worker outputFile) 512*288bf522SAndroid Build Coastguard Worker 513*288bf522SAndroid Build Coastguard Worker if args.traceWrites and args.traceReads: 514*288bf522SAndroid Build Coastguard Worker outputFile.write("\n\n\n") 515*288bf522SAndroid Build Coastguard Worker 516*288bf522SAndroid Build Coastguard Worker if args.traceReads: 517*288bf522SAndroid Build Coastguard Worker uidIoStatsDelta.dumpTotal("read", outputFile) 518*288bf522SAndroid Build Coastguard Worker readParser.dumpTotal(outputFile) 519*288bf522SAndroid Build Coastguard Worker uidIoStatsDelta.dump(uidProcessMapperObj, "read", 520*288bf522SAndroid Build Coastguard Worker lambda uid: readParser.dump(uid, outputFile), 521*288bf522SAndroid Build Coastguard Worker outputFile) 522*288bf522SAndroid Build Coastguard Worker 523*288bf522SAndroid Build Coastguard Worker outputFile.close() 524*288bf522SAndroid Build Coastguard Worker run_shell_cmd("rm {}/{}".format(args.outputDir, TEMP_TRACE_FILE)) 525*288bf522SAndroid Build Coastguard Worker 526*288bf522SAndroid Build Coastguard Worker 527*288bf522SAndroid Build Coastguard Workerif __name__ == "__main__": 528*288bf522SAndroid Build Coastguard Worker main(sys.argv) 529