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