xref: /aosp_15_r20/system/extras/ioblame/ioblame.py (revision 288bf5226967eb3dac5cce6c939ccc2a7f2b4fe5)
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