xref: /aosp_15_r20/external/perfetto/tools/load_tool (revision 6dbdd20afdafa5e3ca9b8809fa73465d530080dc)
1*6dbdd20aSAndroid Build Coastguard Worker#!/usr/bin/env python
2*6dbdd20aSAndroid Build Coastguard Worker# Copyright (C) 2019 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 logging
18*6dbdd20aSAndroid Build Coastguard Workerimport os
19*6dbdd20aSAndroid Build Coastguard Workerimport sys
20*6dbdd20aSAndroid Build Coastguard Workerimport subprocess
21*6dbdd20aSAndroid Build Coastguard Workerimport tempfile
22*6dbdd20aSAndroid Build Coastguard Worker
23*6dbdd20aSAndroid Build Coastguard WorkerROOT_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
24*6dbdd20aSAndroid Build Coastguard WorkerADB_PATH = os.path.join(ROOT_DIR, 'buildtools/android_sdk/platform-tools/adb')
25*6dbdd20aSAndroid Build Coastguard Worker
26*6dbdd20aSAndroid Build Coastguard WorkerTEMPLATED_PERFETTO_CFG = '''
27*6dbdd20aSAndroid Build Coastguard Workerbuffers {{
28*6dbdd20aSAndroid Build Coastguard Worker  size_kb: 65536
29*6dbdd20aSAndroid Build Coastguard Worker  fill_policy: RING_BUFFER
30*6dbdd20aSAndroid Build Coastguard Worker}}
31*6dbdd20aSAndroid Build Coastguard Workerdata_sources {{
32*6dbdd20aSAndroid Build Coastguard Worker  config {{
33*6dbdd20aSAndroid Build Coastguard Worker    name: "linux.ftrace"
34*6dbdd20aSAndroid Build Coastguard Worker    target_buffer: 0
35*6dbdd20aSAndroid Build Coastguard Worker    ftrace_config {{
36*6dbdd20aSAndroid Build Coastguard Worker      ftrace_events: "sched_switch"
37*6dbdd20aSAndroid Build Coastguard Worker      buffer_size_kb: {buffer_size_kb}
38*6dbdd20aSAndroid Build Coastguard Worker      drain_period_ms: {drain_period_ms}
39*6dbdd20aSAndroid Build Coastguard Worker    }}
40*6dbdd20aSAndroid Build Coastguard Worker  }}
41*6dbdd20aSAndroid Build Coastguard Worker}}
42*6dbdd20aSAndroid Build Coastguard Workerduration_ms: 15000
43*6dbdd20aSAndroid Build Coastguard Worker'''
44*6dbdd20aSAndroid Build Coastguard Worker
45*6dbdd20aSAndroid Build Coastguard WorkerPERFETTO_PER_CPU_BUFFER_SIZE_KB_PARAMS = [
46*6dbdd20aSAndroid Build Coastguard Worker    128,
47*6dbdd20aSAndroid Build Coastguard Worker    256,
48*6dbdd20aSAndroid Build Coastguard Worker    512,
49*6dbdd20aSAndroid Build Coastguard Worker    1 * 1024,  # 1 MB
50*6dbdd20aSAndroid Build Coastguard Worker    2 * 1024,  # 2 MB
51*6dbdd20aSAndroid Build Coastguard Worker    4 * 1024,  # 4 MB
52*6dbdd20aSAndroid Build Coastguard Worker]
53*6dbdd20aSAndroid Build Coastguard Worker
54*6dbdd20aSAndroid Build Coastguard WorkerPERFETTO_DRAIN_RATE_MS_PARAMS = [
55*6dbdd20aSAndroid Build Coastguard Worker    100,
56*6dbdd20aSAndroid Build Coastguard Worker    240,
57*6dbdd20aSAndroid Build Coastguard Worker    500,
58*6dbdd20aSAndroid Build Coastguard Worker    1 * 1000,  # 1s
59*6dbdd20aSAndroid Build Coastguard Worker    2 * 1000,  # 2s
60*6dbdd20aSAndroid Build Coastguard Worker    5 * 1000,  # 5s
61*6dbdd20aSAndroid Build Coastguard Worker]
62*6dbdd20aSAndroid Build Coastguard Worker
63*6dbdd20aSAndroid Build Coastguard WorkerBUSY_THREADS_NUM_THREADS_PARAMS = [
64*6dbdd20aSAndroid Build Coastguard Worker    8,
65*6dbdd20aSAndroid Build Coastguard Worker    32,
66*6dbdd20aSAndroid Build Coastguard Worker    128,
67*6dbdd20aSAndroid Build Coastguard Worker]
68*6dbdd20aSAndroid Build Coastguard Worker
69*6dbdd20aSAndroid Build Coastguard WorkerBUSY_THREADS_DUTY_CYCLE_PARAMS = [
70*6dbdd20aSAndroid Build Coastguard Worker    10,
71*6dbdd20aSAndroid Build Coastguard Worker    100,
72*6dbdd20aSAndroid Build Coastguard Worker]
73*6dbdd20aSAndroid Build Coastguard Worker
74*6dbdd20aSAndroid Build Coastguard WorkerBUSY_THREADS_PERIOD_US_PARAMS = [
75*6dbdd20aSAndroid Build Coastguard Worker    500,
76*6dbdd20aSAndroid Build Coastguard Worker    1 * 1000,  # 1 ms
77*6dbdd20aSAndroid Build Coastguard Worker    10 * 1000,  # 10 ms
78*6dbdd20aSAndroid Build Coastguard Worker]
79*6dbdd20aSAndroid Build Coastguard Worker
80*6dbdd20aSAndroid Build Coastguard WorkerTRACE_PROCESSOR_QUERY = """
81*6dbdd20aSAndroid Build Coastguard WorkerSELECT
82*6dbdd20aSAndroid Build Coastguard Worker  a.value as num_sched,
83*6dbdd20aSAndroid Build Coastguard Worker  b.value as num_overrun
84*6dbdd20aSAndroid Build Coastguard WorkerFROM (
85*6dbdd20aSAndroid Build Coastguard Worker  SELECT COUNT(*) as value
86*6dbdd20aSAndroid Build Coastguard Worker  FROM sched
87*6dbdd20aSAndroid Build Coastguard Worker) as a, (
88*6dbdd20aSAndroid Build Coastguard Worker  SELECT SUM(value) as value
89*6dbdd20aSAndroid Build Coastguard Worker  FROM stats
90*6dbdd20aSAndroid Build Coastguard Worker  WHERE name = 'ftrace_cpu_overrun_end'
91*6dbdd20aSAndroid Build Coastguard Worker) as b
92*6dbdd20aSAndroid Build Coastguard Worker"""
93*6dbdd20aSAndroid Build Coastguard Worker
94*6dbdd20aSAndroid Build Coastguard Worker
95*6dbdd20aSAndroid Build Coastguard Workerdef AdbArgs(*args):
96*6dbdd20aSAndroid Build Coastguard Worker  cmd = [ADB_PATH] + list([str(x) for x in args])
97*6dbdd20aSAndroid Build Coastguard Worker  logging.debug('> adb ' + ' '.join([str(x) for x in args]))
98*6dbdd20aSAndroid Build Coastguard Worker  return cmd
99*6dbdd20aSAndroid Build Coastguard Worker
100*6dbdd20aSAndroid Build Coastguard Worker
101*6dbdd20aSAndroid Build Coastguard Workerdef AdbCall(*args):
102*6dbdd20aSAndroid Build Coastguard Worker  return subprocess.check_output(AdbArgs(*args)).decode('utf-8').rstrip()
103*6dbdd20aSAndroid Build Coastguard Worker
104*6dbdd20aSAndroid Build Coastguard Worker
105*6dbdd20aSAndroid Build Coastguard Workerdef SingleTraceRun(out_dir, prio_name, buffer_size_kb, drain_rate_ms,
106*6dbdd20aSAndroid Build Coastguard Worker                   num_threads, duty_cycle, period_us):
107*6dbdd20aSAndroid Build Coastguard Worker  busy_threads_args = AdbArgs('shell', '/data/local/tmp/busy_threads',
108*6dbdd20aSAndroid Build Coastguard Worker                              '--threads={}'.format(num_threads),
109*6dbdd20aSAndroid Build Coastguard Worker                              '--duty_cycle={}'.format(duty_cycle),
110*6dbdd20aSAndroid Build Coastguard Worker                              '--period_us={}'.format(period_us))
111*6dbdd20aSAndroid Build Coastguard Worker  perfetto_args = AdbArgs('shell', 'perfetto', '--txt', '-c', '-', '-o', '-')
112*6dbdd20aSAndroid Build Coastguard Worker
113*6dbdd20aSAndroid Build Coastguard Worker  # Create a file object to read the trace into.
114*6dbdd20aSAndroid Build Coastguard Worker  with tempfile.NamedTemporaryFile() as trace_file:
115*6dbdd20aSAndroid Build Coastguard Worker    logging.info(
116*6dbdd20aSAndroid Build Coastguard Worker        "Starting trace with parameters ({}, {}, {}, {}, {}, {})".format(
117*6dbdd20aSAndroid Build Coastguard Worker            prio_name, buffer_size_kb, drain_rate_ms, num_threads, duty_cycle,
118*6dbdd20aSAndroid Build Coastguard Worker            period_us))
119*6dbdd20aSAndroid Build Coastguard Worker
120*6dbdd20aSAndroid Build Coastguard Worker    # Start the busy threads running.
121*6dbdd20aSAndroid Build Coastguard Worker    busy_threads_handle = subprocess.Popen(busy_threads_args)
122*6dbdd20aSAndroid Build Coastguard Worker
123*6dbdd20aSAndroid Build Coastguard Worker    # Start the Perfetto trace.
124*6dbdd20aSAndroid Build Coastguard Worker    perfetto_handle = subprocess.Popen(
125*6dbdd20aSAndroid Build Coastguard Worker        perfetto_args, stdin=subprocess.PIPE, stdout=trace_file)
126*6dbdd20aSAndroid Build Coastguard Worker
127*6dbdd20aSAndroid Build Coastguard Worker    # Create the config with the parameters
128*6dbdd20aSAndroid Build Coastguard Worker    config = TEMPLATED_PERFETTO_CFG.format(
129*6dbdd20aSAndroid Build Coastguard Worker        buffer_size_kb=buffer_size_kb, drain_period_ms=drain_rate_ms)
130*6dbdd20aSAndroid Build Coastguard Worker
131*6dbdd20aSAndroid Build Coastguard Worker    # Send the config to the Perfetto binary and wait for response.
132*6dbdd20aSAndroid Build Coastguard Worker    perfetto_handle.stdin.write(config.encode())
133*6dbdd20aSAndroid Build Coastguard Worker    perfetto_handle.stdin.close()
134*6dbdd20aSAndroid Build Coastguard Worker    perfetto_ret = perfetto_handle.wait()
135*6dbdd20aSAndroid Build Coastguard Worker
136*6dbdd20aSAndroid Build Coastguard Worker    # Stop busy threads from running.
137*6dbdd20aSAndroid Build Coastguard Worker    busy_threads_handle.terminate()
138*6dbdd20aSAndroid Build Coastguard Worker
139*6dbdd20aSAndroid Build Coastguard Worker    # Return any errors from Perfetto.
140*6dbdd20aSAndroid Build Coastguard Worker    if perfetto_ret:
141*6dbdd20aSAndroid Build Coastguard Worker      raise subprocess.CalledProcessError(
142*6dbdd20aSAndroid Build Coastguard Worker          cmd=perfetto_args, returncode=perfetto_ret)
143*6dbdd20aSAndroid Build Coastguard Worker
144*6dbdd20aSAndroid Build Coastguard Worker    # TODO(lalitm): allow trace processor to take the query file from stdin
145*6dbdd20aSAndroid Build Coastguard Worker    # to prevent this hack from being required.
146*6dbdd20aSAndroid Build Coastguard Worker    with tempfile.NamedTemporaryFile() as trace_query_file:
147*6dbdd20aSAndroid Build Coastguard Worker      trace_query_file.file.write(TRACE_PROCESSOR_QUERY.encode())
148*6dbdd20aSAndroid Build Coastguard Worker      trace_query_file.file.flush()
149*6dbdd20aSAndroid Build Coastguard Worker
150*6dbdd20aSAndroid Build Coastguard Worker      # Run the trace processor on the config.
151*6dbdd20aSAndroid Build Coastguard Worker      tp_path = os.path.join(out_dir, 'trace_processor_shell')
152*6dbdd20aSAndroid Build Coastguard Worker      tp_out = subprocess.check_output(
153*6dbdd20aSAndroid Build Coastguard Worker          [tp_path, '-q', trace_query_file.name, trace_file.name])
154*6dbdd20aSAndroid Build Coastguard Worker
155*6dbdd20aSAndroid Build Coastguard Worker      # Get the CSV output from trace processor (stripping the header).
156*6dbdd20aSAndroid Build Coastguard Worker      [num_sched, num_overrun] = str(tp_out).split('\n')[1].split(',')
157*6dbdd20aSAndroid Build Coastguard Worker
158*6dbdd20aSAndroid Build Coastguard Worker    # Print the row to stdout.
159*6dbdd20aSAndroid Build Coastguard Worker    sys.stdout.write('"{}",{},{},{},{},{},{},{}\n'.format(
160*6dbdd20aSAndroid Build Coastguard Worker        prio_name, buffer_size_kb, drain_rate_ms, num_threads, duty_cycle,
161*6dbdd20aSAndroid Build Coastguard Worker        period_us, num_sched, num_overrun))
162*6dbdd20aSAndroid Build Coastguard Worker
163*6dbdd20aSAndroid Build Coastguard Worker
164*6dbdd20aSAndroid Build Coastguard Workerdef SinglePriorityRun(out_dir, prio_name):
165*6dbdd20aSAndroid Build Coastguard Worker  for buffer_size_kb in PERFETTO_PER_CPU_BUFFER_SIZE_KB_PARAMS:
166*6dbdd20aSAndroid Build Coastguard Worker    for drain_rate_ms in PERFETTO_DRAIN_RATE_MS_PARAMS:
167*6dbdd20aSAndroid Build Coastguard Worker      for num_threads in BUSY_THREADS_NUM_THREADS_PARAMS:
168*6dbdd20aSAndroid Build Coastguard Worker        for duty_cycle in BUSY_THREADS_DUTY_CYCLE_PARAMS:
169*6dbdd20aSAndroid Build Coastguard Worker          for period_us in BUSY_THREADS_PERIOD_US_PARAMS:
170*6dbdd20aSAndroid Build Coastguard Worker            SingleTraceRun(out_dir, prio_name, buffer_size_kb, drain_rate_ms,
171*6dbdd20aSAndroid Build Coastguard Worker                           num_threads, duty_cycle, period_us)
172*6dbdd20aSAndroid Build Coastguard Worker
173*6dbdd20aSAndroid Build Coastguard Worker
174*6dbdd20aSAndroid Build Coastguard Workerdef CycleTracedAndProbes():
175*6dbdd20aSAndroid Build Coastguard Worker  AdbCall('shell', 'stop', 'traced')
176*6dbdd20aSAndroid Build Coastguard Worker  AdbCall('shell', 'stop', 'traced_probes')
177*6dbdd20aSAndroid Build Coastguard Worker  AdbCall('shell', 'start', 'traced')
178*6dbdd20aSAndroid Build Coastguard Worker  AdbCall('shell', 'start', 'traced_probes')
179*6dbdd20aSAndroid Build Coastguard Worker  AdbCall('shell', 'sleep', '5')
180*6dbdd20aSAndroid Build Coastguard Worker  traced_pid = AdbCall('shell', 'pidof', 'traced')
181*6dbdd20aSAndroid Build Coastguard Worker  probes_pid = AdbCall('shell', 'pidof', 'traced_probes')
182*6dbdd20aSAndroid Build Coastguard Worker  assert (traced_pid is not None and probes_pid is not None)
183*6dbdd20aSAndroid Build Coastguard Worker  return (traced_pid, probes_pid)
184*6dbdd20aSAndroid Build Coastguard Worker
185*6dbdd20aSAndroid Build Coastguard Worker
186*6dbdd20aSAndroid Build Coastguard Workerdef Main():
187*6dbdd20aSAndroid Build Coastguard Worker  parser = argparse.ArgumentParser()
188*6dbdd20aSAndroid Build Coastguard Worker  parser.add_argument('linux_out_dir', help='out/android/')
189*6dbdd20aSAndroid Build Coastguard Worker  parser.add_argument('android_out_dir', help='out/android/')
190*6dbdd20aSAndroid Build Coastguard Worker  args = parser.parse_args()
191*6dbdd20aSAndroid Build Coastguard Worker
192*6dbdd20aSAndroid Build Coastguard Worker  # Root ourselves on the device.
193*6dbdd20aSAndroid Build Coastguard Worker  logging.info('Waiting for device and rooting ...')
194*6dbdd20aSAndroid Build Coastguard Worker  AdbCall('wait-for-device')
195*6dbdd20aSAndroid Build Coastguard Worker  AdbCall('root')
196*6dbdd20aSAndroid Build Coastguard Worker  AdbCall('wait-for-device')
197*6dbdd20aSAndroid Build Coastguard Worker
198*6dbdd20aSAndroid Build Coastguard Worker  # Push busy threads to device
199*6dbdd20aSAndroid Build Coastguard Worker  busy_threads_path = os.path.join(args.android_out_dir, 'busy_threads')
200*6dbdd20aSAndroid Build Coastguard Worker  AdbCall('shell', 'rm', '-rf', '/data/local/tmp/perfetto_load_test')
201*6dbdd20aSAndroid Build Coastguard Worker  AdbCall('shell', 'mkdir', '/data/local/tmp/perfetto_load_test')
202*6dbdd20aSAndroid Build Coastguard Worker  AdbCall('push', busy_threads_path, '/data/local/tmp/perfetto_load_test/')
203*6dbdd20aSAndroid Build Coastguard Worker
204*6dbdd20aSAndroid Build Coastguard Worker  # Stop and start traced and traced_probes
205*6dbdd20aSAndroid Build Coastguard Worker  (traced_pid, probes_pid) = CycleTracedAndProbes()
206*6dbdd20aSAndroid Build Coastguard Worker
207*6dbdd20aSAndroid Build Coastguard Worker  # Print the header for csv.
208*6dbdd20aSAndroid Build Coastguard Worker  sys.stdout.write('"{}","{}","{}","{}","{}","{}","{}","{}"\n'.format(
209*6dbdd20aSAndroid Build Coastguard Worker      'prio_name', 'buffer_size_kb', 'drain_rate_ms', 'num_threads',
210*6dbdd20aSAndroid Build Coastguard Worker      'duty_cycle', 'period_us', 'num_sched', 'num_overrun'))
211*6dbdd20aSAndroid Build Coastguard Worker
212*6dbdd20aSAndroid Build Coastguard Worker  # First, do a single run in all configurations without changing prio.
213*6dbdd20aSAndroid Build Coastguard Worker  SinglePriorityRun(args.linux_out_dir, 'Default')
214*6dbdd20aSAndroid Build Coastguard Worker
215*6dbdd20aSAndroid Build Coastguard Worker  # Stop and start traced and traced_probes
216*6dbdd20aSAndroid Build Coastguard Worker  (traced_pid, probes_pid) = CycleTracedAndProbes()
217*6dbdd20aSAndroid Build Coastguard Worker
218*6dbdd20aSAndroid Build Coastguard Worker  # Setup the nice values and check them.
219*6dbdd20aSAndroid Build Coastguard Worker  AdbCall('shell', 'renice', '-n', '-19', '-p', traced_pid)
220*6dbdd20aSAndroid Build Coastguard Worker  AdbCall('shell', 'renice', '-n', '-19', '-p', probes_pid)
221*6dbdd20aSAndroid Build Coastguard Worker  logging.debug(AdbCall('shell', 'cat', '/proc/{}/stat'.format(traced_pid)))
222*6dbdd20aSAndroid Build Coastguard Worker  logging.debug(AdbCall('shell', 'cat', '/proc/{}/stat'.format(probes_pid)))
223*6dbdd20aSAndroid Build Coastguard Worker
224*6dbdd20aSAndroid Build Coastguard Worker  # Do the run.
225*6dbdd20aSAndroid Build Coastguard Worker  SinglePriorityRun(args.linux_out_dir, '-19 Nice')
226*6dbdd20aSAndroid Build Coastguard Worker
227*6dbdd20aSAndroid Build Coastguard Worker  # Stop and start traced and traced_probes
228*6dbdd20aSAndroid Build Coastguard Worker  (traced_pid, probes_pid) = CycleTracedAndProbes()
229*6dbdd20aSAndroid Build Coastguard Worker
230*6dbdd20aSAndroid Build Coastguard Worker  # Then do a run with FIFO scheduling for traced and traced_probes.
231*6dbdd20aSAndroid Build Coastguard Worker  AdbCall('shell', 'chrt', '-f', '-p', traced_pid, '99')
232*6dbdd20aSAndroid Build Coastguard Worker  AdbCall('shell', 'chrt', '-f', '-p', probes_pid, '99')
233*6dbdd20aSAndroid Build Coastguard Worker  logging.debug(AdbCall('shell', 'chrt', '-p', traced_pid))
234*6dbdd20aSAndroid Build Coastguard Worker  logging.debug(AdbCall('shell', 'chrt', '-p', probes_pid))
235*6dbdd20aSAndroid Build Coastguard Worker
236*6dbdd20aSAndroid Build Coastguard Worker  # Do the run.
237*6dbdd20aSAndroid Build Coastguard Worker  SinglePriorityRun(args.linux_out_dir, 'FIFO')
238*6dbdd20aSAndroid Build Coastguard Worker
239*6dbdd20aSAndroid Build Coastguard Worker  # Stop and start traced and traced_probes
240*6dbdd20aSAndroid Build Coastguard Worker  (traced_pid, probes_pid) = CycleTracedAndProbes()
241*6dbdd20aSAndroid Build Coastguard Worker
242*6dbdd20aSAndroid Build Coastguard Worker  # Cleanup any pushed files, priorities etc.
243*6dbdd20aSAndroid Build Coastguard Worker  logging.info("Cleaning up test")
244*6dbdd20aSAndroid Build Coastguard Worker  AdbCall('shell', 'rm', '-rf', '/data/local/tmp/perfetto_load_test')
245*6dbdd20aSAndroid Build Coastguard Worker  logging.debug(AdbCall('shell', 'cat', '/proc/{}/stat'.format(traced_pid)))
246*6dbdd20aSAndroid Build Coastguard Worker  logging.debug(AdbCall('shell', 'cat', '/proc/{}/stat'.format(probes_pid)))
247*6dbdd20aSAndroid Build Coastguard Worker  AdbCall('unroot')
248*6dbdd20aSAndroid Build Coastguard Worker
249*6dbdd20aSAndroid Build Coastguard Worker  return 0
250*6dbdd20aSAndroid Build Coastguard Worker
251*6dbdd20aSAndroid Build Coastguard Worker
252*6dbdd20aSAndroid Build Coastguard Workerif __name__ == '__main__':
253*6dbdd20aSAndroid Build Coastguard Worker  logging.basicConfig(level=logging.INFO)
254*6dbdd20aSAndroid Build Coastguard Worker  sys.exit(Main())
255