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