xref: /aosp_15_r20/external/perfetto/tools/measure_tp_performance.py (revision 6dbdd20afdafa5e3ca9b8809fa73465d530080dc)
1*6dbdd20aSAndroid Build Coastguard Worker#!/usr/bin/env python3
2*6dbdd20aSAndroid Build Coastguard Worker# Copyright (C) 2021 The Android Open Source Project
3*6dbdd20aSAndroid Build Coastguard Worker#
4*6dbdd20aSAndroid Build Coastguard Worker# Licensed under the Apache License, Version 2.0 (the "License");
5*6dbdd20aSAndroid Build Coastguard Worker# you may not use this file except in compliance with the License.
6*6dbdd20aSAndroid Build Coastguard Worker# You may obtain a copy of the License at
7*6dbdd20aSAndroid Build Coastguard Worker#
8*6dbdd20aSAndroid Build Coastguard Worker#      http://www.apache.org/licenses/LICENSE-2.0
9*6dbdd20aSAndroid Build Coastguard Worker#
10*6dbdd20aSAndroid Build Coastguard Worker# Unless required by applicable law or agreed to in writing, software
11*6dbdd20aSAndroid Build Coastguard Worker# distributed under the License is distributed on an "AS IS" BASIS,
12*6dbdd20aSAndroid Build Coastguard Worker# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13*6dbdd20aSAndroid Build Coastguard Worker# See the License for the specific language governing permissions and
14*6dbdd20aSAndroid Build Coastguard Worker# limitations under the License.
15*6dbdd20aSAndroid Build Coastguard Worker
16*6dbdd20aSAndroid Build Coastguard Workerimport argparse
17*6dbdd20aSAndroid Build Coastguard Workerimport os
18*6dbdd20aSAndroid Build Coastguard Workerimport re
19*6dbdd20aSAndroid Build Coastguard Workerimport signal
20*6dbdd20aSAndroid Build Coastguard Workerimport sys
21*6dbdd20aSAndroid Build Coastguard Workerimport subprocess
22*6dbdd20aSAndroid Build Coastguard Worker
23*6dbdd20aSAndroid Build Coastguard Workerimport psutil
24*6dbdd20aSAndroid Build Coastguard Worker
25*6dbdd20aSAndroid Build Coastguard WorkerROOT_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
26*6dbdd20aSAndroid Build Coastguard Worker
27*6dbdd20aSAndroid Build Coastguard WorkerREGEX = re.compile(
28*6dbdd20aSAndroid Build Coastguard Worker    '.*Trace loaded: ([0-9.]+) MB in ([0-9.]+)s \(([0-9.]+) MB/s\)')
29*6dbdd20aSAndroid Build Coastguard Worker
30*6dbdd20aSAndroid Build Coastguard Worker
31*6dbdd20aSAndroid Build Coastguard Workerdef run_tp_until_ingestion(args, env):
32*6dbdd20aSAndroid Build Coastguard Worker  tp_args = [os.path.join(args.out, 'trace_processor_shell'), args.trace_file]
33*6dbdd20aSAndroid Build Coastguard Worker  if not args.ftrace_raw:
34*6dbdd20aSAndroid Build Coastguard Worker    tp_args.append('--no-ftrace-raw')
35*6dbdd20aSAndroid Build Coastguard Worker  tp_args.append('--dev')
36*6dbdd20aSAndroid Build Coastguard Worker  tp_args.append('--dev-flag drop-after-sort=true')
37*6dbdd20aSAndroid Build Coastguard Worker  tp = subprocess.Popen(
38*6dbdd20aSAndroid Build Coastguard Worker      tp_args,
39*6dbdd20aSAndroid Build Coastguard Worker      stdin=subprocess.PIPE,
40*6dbdd20aSAndroid Build Coastguard Worker      stdout=None if args.verbose else subprocess.DEVNULL,
41*6dbdd20aSAndroid Build Coastguard Worker      stderr=subprocess.PIPE,
42*6dbdd20aSAndroid Build Coastguard Worker      universal_newlines=True,
43*6dbdd20aSAndroid Build Coastguard Worker      env=env)
44*6dbdd20aSAndroid Build Coastguard Worker
45*6dbdd20aSAndroid Build Coastguard Worker  lines = []
46*6dbdd20aSAndroid Build Coastguard Worker  while True:
47*6dbdd20aSAndroid Build Coastguard Worker    line = tp.stderr.readline()
48*6dbdd20aSAndroid Build Coastguard Worker    if args.verbose:
49*6dbdd20aSAndroid Build Coastguard Worker      sys.stderr.write(line)
50*6dbdd20aSAndroid Build Coastguard Worker    lines.append(line)
51*6dbdd20aSAndroid Build Coastguard Worker
52*6dbdd20aSAndroid Build Coastguard Worker    match = REGEX.match(line)
53*6dbdd20aSAndroid Build Coastguard Worker    if match:
54*6dbdd20aSAndroid Build Coastguard Worker      break
55*6dbdd20aSAndroid Build Coastguard Worker
56*6dbdd20aSAndroid Build Coastguard Worker    if tp.poll():
57*6dbdd20aSAndroid Build Coastguard Worker      break
58*6dbdd20aSAndroid Build Coastguard Worker
59*6dbdd20aSAndroid Build Coastguard Worker  ret = tp.poll()
60*6dbdd20aSAndroid Build Coastguard Worker  fail = ret is not None and ret > 0
61*6dbdd20aSAndroid Build Coastguard Worker  if fail:
62*6dbdd20aSAndroid Build Coastguard Worker    print("Failed")
63*6dbdd20aSAndroid Build Coastguard Worker    for line in lines:
64*6dbdd20aSAndroid Build Coastguard Worker      sys.stderr.write(line)
65*6dbdd20aSAndroid Build Coastguard Worker  return tp, fail, match[2]
66*6dbdd20aSAndroid Build Coastguard Worker
67*6dbdd20aSAndroid Build Coastguard Worker
68*6dbdd20aSAndroid Build Coastguard Workerdef heap_profile_run(args, dump_at_max: bool):
69*6dbdd20aSAndroid Build Coastguard Worker  profile_args = [
70*6dbdd20aSAndroid Build Coastguard Worker      os.path.join(ROOT_DIR, 'tools', 'heap_profile'), '-i', '1', '-n',
71*6dbdd20aSAndroid Build Coastguard Worker      'trace_processor_shell', '--print-config'
72*6dbdd20aSAndroid Build Coastguard Worker  ]
73*6dbdd20aSAndroid Build Coastguard Worker  if dump_at_max:
74*6dbdd20aSAndroid Build Coastguard Worker    profile_args.append('--dump-at-max')
75*6dbdd20aSAndroid Build Coastguard Worker  config = subprocess.check_output(
76*6dbdd20aSAndroid Build Coastguard Worker      profile_args,
77*6dbdd20aSAndroid Build Coastguard Worker      stderr=subprocess.DEVNULL,
78*6dbdd20aSAndroid Build Coastguard Worker  )
79*6dbdd20aSAndroid Build Coastguard Worker
80*6dbdd20aSAndroid Build Coastguard Worker  out_file = os.path.join(
81*6dbdd20aSAndroid Build Coastguard Worker      args.result, args.result_prefix + ('max' if dump_at_max else 'rest'))
82*6dbdd20aSAndroid Build Coastguard Worker  perfetto_args = [
83*6dbdd20aSAndroid Build Coastguard Worker      os.path.join(args.out, 'perfetto'), '-c', '-', '--txt', '-o', out_file
84*6dbdd20aSAndroid Build Coastguard Worker  ]
85*6dbdd20aSAndroid Build Coastguard Worker  profile = subprocess.Popen(
86*6dbdd20aSAndroid Build Coastguard Worker      perfetto_args,
87*6dbdd20aSAndroid Build Coastguard Worker      stdin=subprocess.PIPE,
88*6dbdd20aSAndroid Build Coastguard Worker      stdout=None if args.verbose else subprocess.DEVNULL,
89*6dbdd20aSAndroid Build Coastguard Worker      stderr=None if args.verbose else subprocess.DEVNULL)
90*6dbdd20aSAndroid Build Coastguard Worker  profile.stdin.write(config)
91*6dbdd20aSAndroid Build Coastguard Worker  profile.stdin.close()
92*6dbdd20aSAndroid Build Coastguard Worker
93*6dbdd20aSAndroid Build Coastguard Worker  env = {
94*6dbdd20aSAndroid Build Coastguard Worker      'LD_PRELOAD': os.path.join(args.out, 'libheapprofd_glibc_preload.so'),
95*6dbdd20aSAndroid Build Coastguard Worker      'TRACE_PROCESSOR_NO_MMAP': '1',
96*6dbdd20aSAndroid Build Coastguard Worker      'PERFETTO_HEAPPROFD_BLOCKING_INIT': '1'
97*6dbdd20aSAndroid Build Coastguard Worker  }
98*6dbdd20aSAndroid Build Coastguard Worker  (tp, fail, _) = run_tp_until_ingestion(args, env)
99*6dbdd20aSAndroid Build Coastguard Worker
100*6dbdd20aSAndroid Build Coastguard Worker  profile.send_signal(signal.SIGINT)
101*6dbdd20aSAndroid Build Coastguard Worker  profile.wait()
102*6dbdd20aSAndroid Build Coastguard Worker
103*6dbdd20aSAndroid Build Coastguard Worker  tp.stdin.close()
104*6dbdd20aSAndroid Build Coastguard Worker  tp.wait()
105*6dbdd20aSAndroid Build Coastguard Worker
106*6dbdd20aSAndroid Build Coastguard Worker  if fail:
107*6dbdd20aSAndroid Build Coastguard Worker    os.remove(out_file)
108*6dbdd20aSAndroid Build Coastguard Worker
109*6dbdd20aSAndroid Build Coastguard Worker
110*6dbdd20aSAndroid Build Coastguard Workerdef regular_run(args):
111*6dbdd20aSAndroid Build Coastguard Worker  env = {'TRACE_PROCESSOR_NO_MMAP': '1'}
112*6dbdd20aSAndroid Build Coastguard Worker  (tp, fail, time) = run_tp_until_ingestion(args, env)
113*6dbdd20aSAndroid Build Coastguard Worker
114*6dbdd20aSAndroid Build Coastguard Worker  p = psutil.Process(tp.pid)
115*6dbdd20aSAndroid Build Coastguard Worker  mem = 0
116*6dbdd20aSAndroid Build Coastguard Worker  for m in p.memory_maps():
117*6dbdd20aSAndroid Build Coastguard Worker    mem += m.anonymous
118*6dbdd20aSAndroid Build Coastguard Worker
119*6dbdd20aSAndroid Build Coastguard Worker  tp.stdin.close()
120*6dbdd20aSAndroid Build Coastguard Worker  tp.wait()
121*6dbdd20aSAndroid Build Coastguard Worker
122*6dbdd20aSAndroid Build Coastguard Worker  print(f'Time taken: {time}s, Memory: {mem / 1024.0 / 1024.0}MB')
123*6dbdd20aSAndroid Build Coastguard Worker
124*6dbdd20aSAndroid Build Coastguard Worker
125*6dbdd20aSAndroid Build Coastguard Workerdef only_sort_run(args):
126*6dbdd20aSAndroid Build Coastguard Worker  env = {
127*6dbdd20aSAndroid Build Coastguard Worker      'TRACE_PROCESSOR_NO_MMAP': '1',
128*6dbdd20aSAndroid Build Coastguard Worker  }
129*6dbdd20aSAndroid Build Coastguard Worker  (tp, fail, time) = run_tp_until_ingestion(args, env)
130*6dbdd20aSAndroid Build Coastguard Worker
131*6dbdd20aSAndroid Build Coastguard Worker  tp.stdin.close()
132*6dbdd20aSAndroid Build Coastguard Worker  tp.wait()
133*6dbdd20aSAndroid Build Coastguard Worker
134*6dbdd20aSAndroid Build Coastguard Worker  print(f'Time taken: {time}s')
135*6dbdd20aSAndroid Build Coastguard Worker
136*6dbdd20aSAndroid Build Coastguard Worker
137*6dbdd20aSAndroid Build Coastguard Workerdef main():
138*6dbdd20aSAndroid Build Coastguard Worker  parser = argparse.ArgumentParser(
139*6dbdd20aSAndroid Build Coastguard Worker      description="This script measures the running time of "
140*6dbdd20aSAndroid Build Coastguard Worker      "ingesting a trace with trace processor as well as profiling "
141*6dbdd20aSAndroid Build Coastguard Worker      "trace processor's memory usage with heapprofd")
142*6dbdd20aSAndroid Build Coastguard Worker  parser.add_argument('--out', type=str, help='Out directory', required=True)
143*6dbdd20aSAndroid Build Coastguard Worker  parser.add_argument(
144*6dbdd20aSAndroid Build Coastguard Worker      '--result', type=str, help='Result directory', required=True)
145*6dbdd20aSAndroid Build Coastguard Worker  parser.add_argument(
146*6dbdd20aSAndroid Build Coastguard Worker      '--result-prefix', type=str, help='Result file prefix', required=True)
147*6dbdd20aSAndroid Build Coastguard Worker  parser.add_argument(
148*6dbdd20aSAndroid Build Coastguard Worker      '--ftrace-raw',
149*6dbdd20aSAndroid Build Coastguard Worker      action='store_true',
150*6dbdd20aSAndroid Build Coastguard Worker      help='Whether to ingest ftrace into raw table',
151*6dbdd20aSAndroid Build Coastguard Worker      default=False)
152*6dbdd20aSAndroid Build Coastguard Worker  parser.add_argument(
153*6dbdd20aSAndroid Build Coastguard Worker      '--kill-existing',
154*6dbdd20aSAndroid Build Coastguard Worker      action='store_true',
155*6dbdd20aSAndroid Build Coastguard Worker      help='Kill traced, perfetto_cmd and trace processor shell if running')
156*6dbdd20aSAndroid Build Coastguard Worker  parser.add_argument(
157*6dbdd20aSAndroid Build Coastguard Worker      '--verbose',
158*6dbdd20aSAndroid Build Coastguard Worker      action='store_true',
159*6dbdd20aSAndroid Build Coastguard Worker      help='Logs all stderr and stdout from subprocesses')
160*6dbdd20aSAndroid Build Coastguard Worker  parser.add_argument('trace_file', type=str, help='Path to trace')
161*6dbdd20aSAndroid Build Coastguard Worker  args = parser.parse_args()
162*6dbdd20aSAndroid Build Coastguard Worker
163*6dbdd20aSAndroid Build Coastguard Worker  if args.kill_existing:
164*6dbdd20aSAndroid Build Coastguard Worker    subprocess.run(['killall', 'traced'],
165*6dbdd20aSAndroid Build Coastguard Worker                   stdout=subprocess.DEVNULL,
166*6dbdd20aSAndroid Build Coastguard Worker                   stderr=subprocess.DEVNULL)
167*6dbdd20aSAndroid Build Coastguard Worker    subprocess.run(['killall', 'perfetto'],
168*6dbdd20aSAndroid Build Coastguard Worker                   stdout=subprocess.DEVNULL,
169*6dbdd20aSAndroid Build Coastguard Worker                   stderr=subprocess.DEVNULL)
170*6dbdd20aSAndroid Build Coastguard Worker    subprocess.run(['killall', 'trace_processor_shell'],
171*6dbdd20aSAndroid Build Coastguard Worker                   stdout=subprocess.DEVNULL,
172*6dbdd20aSAndroid Build Coastguard Worker                   stderr=subprocess.DEVNULL)
173*6dbdd20aSAndroid Build Coastguard Worker
174*6dbdd20aSAndroid Build Coastguard Worker  traced = subprocess.Popen([os.path.join(args.out, 'traced')],
175*6dbdd20aSAndroid Build Coastguard Worker                            stdout=None if args.verbose else subprocess.DEVNULL,
176*6dbdd20aSAndroid Build Coastguard Worker                            stderr=None if args.verbose else subprocess.DEVNULL)
177*6dbdd20aSAndroid Build Coastguard Worker  print('Heap profile dump at max')
178*6dbdd20aSAndroid Build Coastguard Worker  heap_profile_run(args, dump_at_max=True)
179*6dbdd20aSAndroid Build Coastguard Worker  print('Heap profile dump at resting')
180*6dbdd20aSAndroid Build Coastguard Worker  heap_profile_run(args, dump_at_max=False)
181*6dbdd20aSAndroid Build Coastguard Worker  print('Regular run')
182*6dbdd20aSAndroid Build Coastguard Worker  regular_run(args)
183*6dbdd20aSAndroid Build Coastguard Worker  print('Only sort run')
184*6dbdd20aSAndroid Build Coastguard Worker  only_sort_run(args)
185*6dbdd20aSAndroid Build Coastguard Worker
186*6dbdd20aSAndroid Build Coastguard Worker  traced.send_signal(signal.SIGINT)
187*6dbdd20aSAndroid Build Coastguard Worker  traced.wait()
188*6dbdd20aSAndroid Build Coastguard Worker
189*6dbdd20aSAndroid Build Coastguard Worker
190*6dbdd20aSAndroid Build Coastguard Workerif __name__ == "__main__":
191*6dbdd20aSAndroid Build Coastguard Worker  main()
192