1*288bf522SAndroid Build Coastguard Worker#!/usr/bin/env python 2*288bf522SAndroid Build Coastguard Worker# 3*288bf522SAndroid Build Coastguard Worker# Copyright (C) 2015 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"""Simpleperf runtest runner: run simpleperf runtests on host or on device. 18*288bf522SAndroid Build Coastguard Worker 19*288bf522SAndroid Build Coastguard WorkerFor a simpleperf runtest like one_function test, it contains following steps: 20*288bf522SAndroid Build Coastguard Worker1. Run simpleperf record command to record simpleperf_runtest_one_function's 21*288bf522SAndroid Build Coastguard Worker running samples, which is generated in perf.data. 22*288bf522SAndroid Build Coastguard Worker2. Run simpleperf report command to parse perf.data, generate perf.report. 23*288bf522SAndroid Build Coastguard Worker4. Parse perf.report and see if it matches expectation. 24*288bf522SAndroid Build Coastguard Worker 25*288bf522SAndroid Build Coastguard WorkerThe information of all runtests is stored in runtest.conf. 26*288bf522SAndroid Build Coastguard Worker""" 27*288bf522SAndroid Build Coastguard Worker 28*288bf522SAndroid Build Coastguard Workerimport os 29*288bf522SAndroid Build Coastguard Workerimport os.path 30*288bf522SAndroid Build Coastguard Workerimport re 31*288bf522SAndroid Build Coastguard Workerimport subprocess 32*288bf522SAndroid Build Coastguard Workerimport sys 33*288bf522SAndroid Build Coastguard Workerimport xml.etree.ElementTree as ET 34*288bf522SAndroid Build Coastguard Worker 35*288bf522SAndroid Build Coastguard Worker 36*288bf522SAndroid Build Coastguard Workerclass CallTreeNode(object): 37*288bf522SAndroid Build Coastguard Worker 38*288bf522SAndroid Build Coastguard Worker def __init__(self, name): 39*288bf522SAndroid Build Coastguard Worker self.name = name 40*288bf522SAndroid Build Coastguard Worker self.children = [] 41*288bf522SAndroid Build Coastguard Worker 42*288bf522SAndroid Build Coastguard Worker def add_child(self, child): 43*288bf522SAndroid Build Coastguard Worker self.children.append(child) 44*288bf522SAndroid Build Coastguard Worker 45*288bf522SAndroid Build Coastguard Worker def __str__(self): 46*288bf522SAndroid Build Coastguard Worker return 'CallTreeNode:\n' + '\n'.join(self._dump(1)) 47*288bf522SAndroid Build Coastguard Worker 48*288bf522SAndroid Build Coastguard Worker def _dump(self, indent): 49*288bf522SAndroid Build Coastguard Worker indent_str = ' ' * indent 50*288bf522SAndroid Build Coastguard Worker strs = [indent_str + self.name] 51*288bf522SAndroid Build Coastguard Worker for child in self.children: 52*288bf522SAndroid Build Coastguard Worker strs.extend(child._dump(indent + 1)) 53*288bf522SAndroid Build Coastguard Worker return strs 54*288bf522SAndroid Build Coastguard Worker 55*288bf522SAndroid Build Coastguard Worker 56*288bf522SAndroid Build Coastguard Workerclass Symbol(object): 57*288bf522SAndroid Build Coastguard Worker 58*288bf522SAndroid Build Coastguard Worker def __init__(self, name, comm, overhead, children_overhead): 59*288bf522SAndroid Build Coastguard Worker self.name = name 60*288bf522SAndroid Build Coastguard Worker self.comm = comm 61*288bf522SAndroid Build Coastguard Worker self.overhead = overhead 62*288bf522SAndroid Build Coastguard Worker # children_overhead is the overhead sum of this symbol and functions 63*288bf522SAndroid Build Coastguard Worker # called by this symbol. 64*288bf522SAndroid Build Coastguard Worker self.children_overhead = children_overhead 65*288bf522SAndroid Build Coastguard Worker self.call_tree = None 66*288bf522SAndroid Build Coastguard Worker 67*288bf522SAndroid Build Coastguard Worker def set_call_tree(self, call_tree): 68*288bf522SAndroid Build Coastguard Worker self.call_tree = call_tree 69*288bf522SAndroid Build Coastguard Worker 70*288bf522SAndroid Build Coastguard Worker def __str__(self): 71*288bf522SAndroid Build Coastguard Worker strs = [] 72*288bf522SAndroid Build Coastguard Worker strs.append('Symbol name=%s comm=%s overhead=%f children_overhead=%f' % ( 73*288bf522SAndroid Build Coastguard Worker self.name, self.comm, self.overhead, self.children_overhead)) 74*288bf522SAndroid Build Coastguard Worker if self.call_tree: 75*288bf522SAndroid Build Coastguard Worker strs.append('\t%s' % self.call_tree) 76*288bf522SAndroid Build Coastguard Worker return '\n'.join(strs) 77*288bf522SAndroid Build Coastguard Worker 78*288bf522SAndroid Build Coastguard Worker 79*288bf522SAndroid Build Coastguard Workerclass SymbolOverheadRequirement(object): 80*288bf522SAndroid Build Coastguard Worker 81*288bf522SAndroid Build Coastguard Worker def __init__(self, symbol_name=None, comm=None, min_overhead=None, 82*288bf522SAndroid Build Coastguard Worker max_overhead=None): 83*288bf522SAndroid Build Coastguard Worker self.symbol_name = symbol_name 84*288bf522SAndroid Build Coastguard Worker self.comm = comm 85*288bf522SAndroid Build Coastguard Worker self.min_overhead = min_overhead 86*288bf522SAndroid Build Coastguard Worker self.max_overhead = max_overhead 87*288bf522SAndroid Build Coastguard Worker 88*288bf522SAndroid Build Coastguard Worker def __str__(self): 89*288bf522SAndroid Build Coastguard Worker strs = [] 90*288bf522SAndroid Build Coastguard Worker strs.append('SymbolOverheadRequirement') 91*288bf522SAndroid Build Coastguard Worker if self.symbol_name is not None: 92*288bf522SAndroid Build Coastguard Worker strs.append('symbol_name=%s' % self.symbol_name) 93*288bf522SAndroid Build Coastguard Worker if self.comm is not None: 94*288bf522SAndroid Build Coastguard Worker strs.append('comm=%s' % self.comm) 95*288bf522SAndroid Build Coastguard Worker if self.min_overhead is not None: 96*288bf522SAndroid Build Coastguard Worker strs.append('min_overhead=%f' % self.min_overhead) 97*288bf522SAndroid Build Coastguard Worker if self.max_overhead is not None: 98*288bf522SAndroid Build Coastguard Worker strs.append('max_overhead=%f' % self.max_overhead) 99*288bf522SAndroid Build Coastguard Worker return ' '.join(strs) 100*288bf522SAndroid Build Coastguard Worker 101*288bf522SAndroid Build Coastguard Worker def is_match(self, symbol): 102*288bf522SAndroid Build Coastguard Worker if self.symbol_name is not None: 103*288bf522SAndroid Build Coastguard Worker if self.symbol_name != symbol.name: 104*288bf522SAndroid Build Coastguard Worker return False 105*288bf522SAndroid Build Coastguard Worker if self.comm is not None: 106*288bf522SAndroid Build Coastguard Worker if self.comm != symbol.comm: 107*288bf522SAndroid Build Coastguard Worker return False 108*288bf522SAndroid Build Coastguard Worker return True 109*288bf522SAndroid Build Coastguard Worker 110*288bf522SAndroid Build Coastguard Worker def check_overhead(self, overhead): 111*288bf522SAndroid Build Coastguard Worker if self.min_overhead is not None: 112*288bf522SAndroid Build Coastguard Worker if self.min_overhead > overhead: 113*288bf522SAndroid Build Coastguard Worker return False 114*288bf522SAndroid Build Coastguard Worker if self.max_overhead is not None: 115*288bf522SAndroid Build Coastguard Worker if self.max_overhead < overhead: 116*288bf522SAndroid Build Coastguard Worker return False 117*288bf522SAndroid Build Coastguard Worker return True 118*288bf522SAndroid Build Coastguard Worker 119*288bf522SAndroid Build Coastguard Worker 120*288bf522SAndroid Build Coastguard Workerclass SymbolRelationRequirement(object): 121*288bf522SAndroid Build Coastguard Worker 122*288bf522SAndroid Build Coastguard Worker def __init__(self, symbol_name, comm=None): 123*288bf522SAndroid Build Coastguard Worker self.symbol_name = symbol_name 124*288bf522SAndroid Build Coastguard Worker self.comm = comm 125*288bf522SAndroid Build Coastguard Worker self.children = [] 126*288bf522SAndroid Build Coastguard Worker 127*288bf522SAndroid Build Coastguard Worker def add_child(self, child): 128*288bf522SAndroid Build Coastguard Worker self.children.append(child) 129*288bf522SAndroid Build Coastguard Worker 130*288bf522SAndroid Build Coastguard Worker def __str__(self): 131*288bf522SAndroid Build Coastguard Worker return 'SymbolRelationRequirement:\n' + '\n'.join(self._dump(1)) 132*288bf522SAndroid Build Coastguard Worker 133*288bf522SAndroid Build Coastguard Worker def _dump(self, indent): 134*288bf522SAndroid Build Coastguard Worker indent_str = ' ' * indent 135*288bf522SAndroid Build Coastguard Worker strs = [indent_str + self.symbol_name + 136*288bf522SAndroid Build Coastguard Worker (' ' + self.comm if self.comm else '')] 137*288bf522SAndroid Build Coastguard Worker for child in self.children: 138*288bf522SAndroid Build Coastguard Worker strs.extend(child._dump(indent + 1)) 139*288bf522SAndroid Build Coastguard Worker return strs 140*288bf522SAndroid Build Coastguard Worker 141*288bf522SAndroid Build Coastguard Worker def is_match(self, symbol): 142*288bf522SAndroid Build Coastguard Worker if symbol.name != self.symbol_name: 143*288bf522SAndroid Build Coastguard Worker return False 144*288bf522SAndroid Build Coastguard Worker if self.comm is not None: 145*288bf522SAndroid Build Coastguard Worker if symbol.comm != self.comm: 146*288bf522SAndroid Build Coastguard Worker return False 147*288bf522SAndroid Build Coastguard Worker return True 148*288bf522SAndroid Build Coastguard Worker 149*288bf522SAndroid Build Coastguard Worker def check_relation(self, call_tree): 150*288bf522SAndroid Build Coastguard Worker if not call_tree: 151*288bf522SAndroid Build Coastguard Worker return False 152*288bf522SAndroid Build Coastguard Worker if self.symbol_name != call_tree.name: 153*288bf522SAndroid Build Coastguard Worker return False 154*288bf522SAndroid Build Coastguard Worker for child in self.children: 155*288bf522SAndroid Build Coastguard Worker child_matched = False 156*288bf522SAndroid Build Coastguard Worker for node in call_tree.children: 157*288bf522SAndroid Build Coastguard Worker if child.check_relation(node): 158*288bf522SAndroid Build Coastguard Worker child_matched = True 159*288bf522SAndroid Build Coastguard Worker break 160*288bf522SAndroid Build Coastguard Worker if not child_matched: 161*288bf522SAndroid Build Coastguard Worker return False 162*288bf522SAndroid Build Coastguard Worker return True 163*288bf522SAndroid Build Coastguard Worker 164*288bf522SAndroid Build Coastguard Worker 165*288bf522SAndroid Build Coastguard Workerclass Test(object): 166*288bf522SAndroid Build Coastguard Worker 167*288bf522SAndroid Build Coastguard Worker def __init__( 168*288bf522SAndroid Build Coastguard Worker self, 169*288bf522SAndroid Build Coastguard Worker test_name, 170*288bf522SAndroid Build Coastguard Worker executable_name, 171*288bf522SAndroid Build Coastguard Worker disable_host, 172*288bf522SAndroid Build Coastguard Worker record_options, 173*288bf522SAndroid Build Coastguard Worker report_options, 174*288bf522SAndroid Build Coastguard Worker symbol_overhead_requirements, 175*288bf522SAndroid Build Coastguard Worker symbol_children_overhead_requirements, 176*288bf522SAndroid Build Coastguard Worker symbol_relation_requirements): 177*288bf522SAndroid Build Coastguard Worker self.test_name = test_name 178*288bf522SAndroid Build Coastguard Worker self.executable_name = executable_name 179*288bf522SAndroid Build Coastguard Worker self.disable_host = disable_host 180*288bf522SAndroid Build Coastguard Worker self.record_options = record_options 181*288bf522SAndroid Build Coastguard Worker self.report_options = report_options 182*288bf522SAndroid Build Coastguard Worker self.symbol_overhead_requirements = symbol_overhead_requirements 183*288bf522SAndroid Build Coastguard Worker self.symbol_children_overhead_requirements = ( 184*288bf522SAndroid Build Coastguard Worker symbol_children_overhead_requirements) 185*288bf522SAndroid Build Coastguard Worker self.symbol_relation_requirements = symbol_relation_requirements 186*288bf522SAndroid Build Coastguard Worker 187*288bf522SAndroid Build Coastguard Worker def __str__(self): 188*288bf522SAndroid Build Coastguard Worker strs = [] 189*288bf522SAndroid Build Coastguard Worker strs.append('Test test_name=%s' % self.test_name) 190*288bf522SAndroid Build Coastguard Worker strs.append('\texecutable_name=%s' % self.executable_name) 191*288bf522SAndroid Build Coastguard Worker strs.append('\tdisable_host=%s' % self.disable_host) 192*288bf522SAndroid Build Coastguard Worker strs.append('\trecord_options=%s' % (' '.join(self.record_options))) 193*288bf522SAndroid Build Coastguard Worker strs.append('\treport_options=%s' % (' '.join(self.report_options))) 194*288bf522SAndroid Build Coastguard Worker strs.append('\tsymbol_overhead_requirements:') 195*288bf522SAndroid Build Coastguard Worker for req in self.symbol_overhead_requirements: 196*288bf522SAndroid Build Coastguard Worker strs.append('\t\t%s' % req) 197*288bf522SAndroid Build Coastguard Worker strs.append('\tsymbol_children_overhead_requirements:') 198*288bf522SAndroid Build Coastguard Worker for req in self.symbol_children_overhead_requirements: 199*288bf522SAndroid Build Coastguard Worker strs.append('\t\t%s' % req) 200*288bf522SAndroid Build Coastguard Worker strs.append('\tsymbol_relation_requirements:') 201*288bf522SAndroid Build Coastguard Worker for req in self.symbol_relation_requirements: 202*288bf522SAndroid Build Coastguard Worker strs.append('\t\t%s' % req) 203*288bf522SAndroid Build Coastguard Worker return '\n'.join(strs) 204*288bf522SAndroid Build Coastguard Worker 205*288bf522SAndroid Build Coastguard Worker 206*288bf522SAndroid Build Coastguard Workerdef load_config_file(config_file): 207*288bf522SAndroid Build Coastguard Worker tests = [] 208*288bf522SAndroid Build Coastguard Worker tree = ET.parse(config_file) 209*288bf522SAndroid Build Coastguard Worker root = tree.getroot() 210*288bf522SAndroid Build Coastguard Worker assert root.tag == 'runtests' 211*288bf522SAndroid Build Coastguard Worker for test in root: 212*288bf522SAndroid Build Coastguard Worker assert test.tag == 'test' 213*288bf522SAndroid Build Coastguard Worker test_name = test.attrib['name'] 214*288bf522SAndroid Build Coastguard Worker executable_name = None 215*288bf522SAndroid Build Coastguard Worker disable_host = False 216*288bf522SAndroid Build Coastguard Worker record_options = [] 217*288bf522SAndroid Build Coastguard Worker report_options = [] 218*288bf522SAndroid Build Coastguard Worker symbol_overhead_requirements = [] 219*288bf522SAndroid Build Coastguard Worker symbol_children_overhead_requirements = [] 220*288bf522SAndroid Build Coastguard Worker symbol_relation_requirements = [] 221*288bf522SAndroid Build Coastguard Worker for test_item in test: 222*288bf522SAndroid Build Coastguard Worker if test_item.tag == 'executable': 223*288bf522SAndroid Build Coastguard Worker executable_name = test_item.attrib['name'] 224*288bf522SAndroid Build Coastguard Worker elif test_item.tag == 'disable_host': 225*288bf522SAndroid Build Coastguard Worker disable_host = True 226*288bf522SAndroid Build Coastguard Worker elif test_item.tag == 'record': 227*288bf522SAndroid Build Coastguard Worker record_options = test_item.attrib['option'].split() 228*288bf522SAndroid Build Coastguard Worker elif test_item.tag == 'report': 229*288bf522SAndroid Build Coastguard Worker report_options = test_item.attrib['option'].split() 230*288bf522SAndroid Build Coastguard Worker elif (test_item.tag == 'symbol_overhead' or 231*288bf522SAndroid Build Coastguard Worker test_item.tag == 'symbol_children_overhead'): 232*288bf522SAndroid Build Coastguard Worker for symbol_item in test_item: 233*288bf522SAndroid Build Coastguard Worker assert symbol_item.tag == 'symbol' 234*288bf522SAndroid Build Coastguard Worker symbol_name = None 235*288bf522SAndroid Build Coastguard Worker if 'name' in symbol_item.attrib: 236*288bf522SAndroid Build Coastguard Worker symbol_name = symbol_item.attrib['name'] 237*288bf522SAndroid Build Coastguard Worker comm = None 238*288bf522SAndroid Build Coastguard Worker if 'comm' in symbol_item.attrib: 239*288bf522SAndroid Build Coastguard Worker comm = symbol_item.attrib['comm'] 240*288bf522SAndroid Build Coastguard Worker overhead_min = None 241*288bf522SAndroid Build Coastguard Worker if 'min' in symbol_item.attrib: 242*288bf522SAndroid Build Coastguard Worker overhead_min = float(symbol_item.attrib['min']) 243*288bf522SAndroid Build Coastguard Worker overhead_max = None 244*288bf522SAndroid Build Coastguard Worker if 'max' in symbol_item.attrib: 245*288bf522SAndroid Build Coastguard Worker overhead_max = float(symbol_item.attrib['max']) 246*288bf522SAndroid Build Coastguard Worker 247*288bf522SAndroid Build Coastguard Worker if test_item.tag == 'symbol_overhead': 248*288bf522SAndroid Build Coastguard Worker symbol_overhead_requirements.append( 249*288bf522SAndroid Build Coastguard Worker SymbolOverheadRequirement( 250*288bf522SAndroid Build Coastguard Worker symbol_name, 251*288bf522SAndroid Build Coastguard Worker comm, 252*288bf522SAndroid Build Coastguard Worker overhead_min, 253*288bf522SAndroid Build Coastguard Worker overhead_max) 254*288bf522SAndroid Build Coastguard Worker ) 255*288bf522SAndroid Build Coastguard Worker else: 256*288bf522SAndroid Build Coastguard Worker symbol_children_overhead_requirements.append( 257*288bf522SAndroid Build Coastguard Worker SymbolOverheadRequirement( 258*288bf522SAndroid Build Coastguard Worker symbol_name, 259*288bf522SAndroid Build Coastguard Worker comm, 260*288bf522SAndroid Build Coastguard Worker overhead_min, 261*288bf522SAndroid Build Coastguard Worker overhead_max)) 262*288bf522SAndroid Build Coastguard Worker elif test_item.tag == 'symbol_callgraph_relation': 263*288bf522SAndroid Build Coastguard Worker for symbol_item in test_item: 264*288bf522SAndroid Build Coastguard Worker req = load_symbol_relation_requirement(symbol_item) 265*288bf522SAndroid Build Coastguard Worker symbol_relation_requirements.append(req) 266*288bf522SAndroid Build Coastguard Worker 267*288bf522SAndroid Build Coastguard Worker tests.append( 268*288bf522SAndroid Build Coastguard Worker Test( 269*288bf522SAndroid Build Coastguard Worker test_name, 270*288bf522SAndroid Build Coastguard Worker executable_name, 271*288bf522SAndroid Build Coastguard Worker disable_host, 272*288bf522SAndroid Build Coastguard Worker record_options, 273*288bf522SAndroid Build Coastguard Worker report_options, 274*288bf522SAndroid Build Coastguard Worker symbol_overhead_requirements, 275*288bf522SAndroid Build Coastguard Worker symbol_children_overhead_requirements, 276*288bf522SAndroid Build Coastguard Worker symbol_relation_requirements)) 277*288bf522SAndroid Build Coastguard Worker return tests 278*288bf522SAndroid Build Coastguard Worker 279*288bf522SAndroid Build Coastguard Worker 280*288bf522SAndroid Build Coastguard Workerdef load_symbol_relation_requirement(symbol_item): 281*288bf522SAndroid Build Coastguard Worker symbol_name = symbol_item.attrib['name'] 282*288bf522SAndroid Build Coastguard Worker comm = None 283*288bf522SAndroid Build Coastguard Worker if 'comm' in symbol_item.attrib: 284*288bf522SAndroid Build Coastguard Worker comm = symbol_item.attrib['comm'] 285*288bf522SAndroid Build Coastguard Worker req = SymbolRelationRequirement(symbol_name, comm) 286*288bf522SAndroid Build Coastguard Worker for item in symbol_item: 287*288bf522SAndroid Build Coastguard Worker child_req = load_symbol_relation_requirement(item) 288*288bf522SAndroid Build Coastguard Worker req.add_child(child_req) 289*288bf522SAndroid Build Coastguard Worker return req 290*288bf522SAndroid Build Coastguard Worker 291*288bf522SAndroid Build Coastguard Worker 292*288bf522SAndroid Build Coastguard Workerclass Runner(object): 293*288bf522SAndroid Build Coastguard Worker 294*288bf522SAndroid Build Coastguard Worker def __init__(self, target, perf_path): 295*288bf522SAndroid Build Coastguard Worker self.target = target 296*288bf522SAndroid Build Coastguard Worker self.is32 = target.endswith('32') 297*288bf522SAndroid Build Coastguard Worker self.perf_path = perf_path 298*288bf522SAndroid Build Coastguard Worker self.use_callgraph = False 299*288bf522SAndroid Build Coastguard Worker self.sampler = 'cpu-cycles' 300*288bf522SAndroid Build Coastguard Worker 301*288bf522SAndroid Build Coastguard Worker def record(self, test_executable_name, record_file, additional_options=[]): 302*288bf522SAndroid Build Coastguard Worker call_args = [self.perf_path, 'record'] 303*288bf522SAndroid Build Coastguard Worker call_args += ['--duration', '2'] 304*288bf522SAndroid Build Coastguard Worker call_args += ['-e', '%s:u' % self.sampler] 305*288bf522SAndroid Build Coastguard Worker if self.use_callgraph: 306*288bf522SAndroid Build Coastguard Worker call_args += ['-f', '1000', '-g'] 307*288bf522SAndroid Build Coastguard Worker call_args += ['-o', record_file] 308*288bf522SAndroid Build Coastguard Worker call_args += additional_options 309*288bf522SAndroid Build Coastguard Worker test_executable_name += '32' if self.is32 else '64' 310*288bf522SAndroid Build Coastguard Worker call_args += [test_executable_name] 311*288bf522SAndroid Build Coastguard Worker self._call(call_args) 312*288bf522SAndroid Build Coastguard Worker 313*288bf522SAndroid Build Coastguard Worker def report(self, record_file, report_file, additional_options=[]): 314*288bf522SAndroid Build Coastguard Worker call_args = [self.perf_path, 'report'] 315*288bf522SAndroid Build Coastguard Worker call_args += ['-i', record_file] 316*288bf522SAndroid Build Coastguard Worker if self.use_callgraph: 317*288bf522SAndroid Build Coastguard Worker call_args += ['-g', 'callee'] 318*288bf522SAndroid Build Coastguard Worker call_args += additional_options 319*288bf522SAndroid Build Coastguard Worker self._call(call_args, report_file) 320*288bf522SAndroid Build Coastguard Worker 321*288bf522SAndroid Build Coastguard Worker def _call(self, args, output_file=None): 322*288bf522SAndroid Build Coastguard Worker pass 323*288bf522SAndroid Build Coastguard Worker 324*288bf522SAndroid Build Coastguard Worker 325*288bf522SAndroid Build Coastguard Workerclass HostRunner(Runner): 326*288bf522SAndroid Build Coastguard Worker 327*288bf522SAndroid Build Coastguard Worker """Run perf test on host.""" 328*288bf522SAndroid Build Coastguard Worker 329*288bf522SAndroid Build Coastguard Worker def __init__(self, target): 330*288bf522SAndroid Build Coastguard Worker perf_path = 'simpleperf32' if target.endswith('32') else 'simpleperf' 331*288bf522SAndroid Build Coastguard Worker super(HostRunner, self).__init__(target, perf_path) 332*288bf522SAndroid Build Coastguard Worker 333*288bf522SAndroid Build Coastguard Worker def _call(self, args, output_file=None): 334*288bf522SAndroid Build Coastguard Worker output_fh = None 335*288bf522SAndroid Build Coastguard Worker if output_file is not None: 336*288bf522SAndroid Build Coastguard Worker output_fh = open(output_file, 'w') 337*288bf522SAndroid Build Coastguard Worker subprocess.check_call(args, stdout=output_fh) 338*288bf522SAndroid Build Coastguard Worker if output_fh is not None: 339*288bf522SAndroid Build Coastguard Worker output_fh.close() 340*288bf522SAndroid Build Coastguard Worker 341*288bf522SAndroid Build Coastguard Worker 342*288bf522SAndroid Build Coastguard Workerclass DeviceRunner(Runner): 343*288bf522SAndroid Build Coastguard Worker 344*288bf522SAndroid Build Coastguard Worker """Run perf test on device.""" 345*288bf522SAndroid Build Coastguard Worker 346*288bf522SAndroid Build Coastguard Worker def __init__(self, target): 347*288bf522SAndroid Build Coastguard Worker self.tmpdir = '/data/local/tmp/' 348*288bf522SAndroid Build Coastguard Worker perf_path = 'simpleperf32' if target.endswith('32') else 'simpleperf' 349*288bf522SAndroid Build Coastguard Worker super(DeviceRunner, self).__init__(target, self.tmpdir + perf_path) 350*288bf522SAndroid Build Coastguard Worker self._download(os.environ['OUT'] + '/system/xbin/' + perf_path, self.tmpdir) 351*288bf522SAndroid Build Coastguard Worker 352*288bf522SAndroid Build Coastguard Worker def _call(self, args, output_file=None): 353*288bf522SAndroid Build Coastguard Worker output_fh = None 354*288bf522SAndroid Build Coastguard Worker if output_file is not None: 355*288bf522SAndroid Build Coastguard Worker output_fh = open(output_file, 'w') 356*288bf522SAndroid Build Coastguard Worker args_with_adb = ['adb', 'shell'] 357*288bf522SAndroid Build Coastguard Worker args_with_adb.append('export LD_LIBRARY_PATH=' + self.tmpdir + ' && ' + ' '.join(args)) 358*288bf522SAndroid Build Coastguard Worker subprocess.check_call(args_with_adb, stdout=output_fh) 359*288bf522SAndroid Build Coastguard Worker if output_fh is not None: 360*288bf522SAndroid Build Coastguard Worker output_fh.close() 361*288bf522SAndroid Build Coastguard Worker 362*288bf522SAndroid Build Coastguard Worker def _download(self, file, to_dir): 363*288bf522SAndroid Build Coastguard Worker args = ['adb', 'push', file, to_dir] 364*288bf522SAndroid Build Coastguard Worker subprocess.check_call(args) 365*288bf522SAndroid Build Coastguard Worker 366*288bf522SAndroid Build Coastguard Worker def record(self, test_executable_name, record_file, additional_options=[]): 367*288bf522SAndroid Build Coastguard Worker self._download(os.environ['OUT'] + '/system/bin/' + test_executable_name + 368*288bf522SAndroid Build Coastguard Worker ('32' if self.is32 else '64'), self.tmpdir) 369*288bf522SAndroid Build Coastguard Worker super(DeviceRunner, self).record(self.tmpdir + test_executable_name, 370*288bf522SAndroid Build Coastguard Worker self.tmpdir + record_file, 371*288bf522SAndroid Build Coastguard Worker additional_options) 372*288bf522SAndroid Build Coastguard Worker 373*288bf522SAndroid Build Coastguard Worker def report(self, record_file, report_file, additional_options=[]): 374*288bf522SAndroid Build Coastguard Worker super(DeviceRunner, self).report(self.tmpdir + record_file, 375*288bf522SAndroid Build Coastguard Worker report_file, 376*288bf522SAndroid Build Coastguard Worker additional_options) 377*288bf522SAndroid Build Coastguard Worker 378*288bf522SAndroid Build Coastguard Workerclass ReportAnalyzer(object): 379*288bf522SAndroid Build Coastguard Worker 380*288bf522SAndroid Build Coastguard Worker """Check if perf.report matches expectation in Configuration.""" 381*288bf522SAndroid Build Coastguard Worker 382*288bf522SAndroid Build Coastguard Worker def _read_report_file(self, report_file, has_callgraph): 383*288bf522SAndroid Build Coastguard Worker fh = open(report_file, 'r') 384*288bf522SAndroid Build Coastguard Worker lines = fh.readlines() 385*288bf522SAndroid Build Coastguard Worker fh.close() 386*288bf522SAndroid Build Coastguard Worker 387*288bf522SAndroid Build Coastguard Worker lines = [x.rstrip() for x in lines] 388*288bf522SAndroid Build Coastguard Worker blank_line_index = -1 389*288bf522SAndroid Build Coastguard Worker for i in range(len(lines)): 390*288bf522SAndroid Build Coastguard Worker if not lines[i]: 391*288bf522SAndroid Build Coastguard Worker blank_line_index = i 392*288bf522SAndroid Build Coastguard Worker assert blank_line_index != -1 393*288bf522SAndroid Build Coastguard Worker assert blank_line_index + 1 < len(lines) 394*288bf522SAndroid Build Coastguard Worker title_line = lines[blank_line_index + 1] 395*288bf522SAndroid Build Coastguard Worker report_item_lines = lines[blank_line_index + 2:] 396*288bf522SAndroid Build Coastguard Worker 397*288bf522SAndroid Build Coastguard Worker if has_callgraph: 398*288bf522SAndroid Build Coastguard Worker assert re.search(r'^Children\s+Self\s+Command.+Symbol$', title_line) 399*288bf522SAndroid Build Coastguard Worker else: 400*288bf522SAndroid Build Coastguard Worker assert re.search(r'^Overhead\s+Command.+Symbol$', title_line) 401*288bf522SAndroid Build Coastguard Worker 402*288bf522SAndroid Build Coastguard Worker return self._parse_report_items(report_item_lines, has_callgraph) 403*288bf522SAndroid Build Coastguard Worker 404*288bf522SAndroid Build Coastguard Worker def _parse_report_items(self, lines, has_callgraph): 405*288bf522SAndroid Build Coastguard Worker symbols = [] 406*288bf522SAndroid Build Coastguard Worker cur_symbol = None 407*288bf522SAndroid Build Coastguard Worker call_tree_stack = {} 408*288bf522SAndroid Build Coastguard Worker vertical_columns = [] 409*288bf522SAndroid Build Coastguard Worker last_node = None 410*288bf522SAndroid Build Coastguard Worker last_depth = -1 411*288bf522SAndroid Build Coastguard Worker 412*288bf522SAndroid Build Coastguard Worker for line in lines: 413*288bf522SAndroid Build Coastguard Worker if not line: 414*288bf522SAndroid Build Coastguard Worker continue 415*288bf522SAndroid Build Coastguard Worker if not line[0].isspace(): 416*288bf522SAndroid Build Coastguard Worker if has_callgraph: 417*288bf522SAndroid Build Coastguard Worker items = line.split(None, 6) 418*288bf522SAndroid Build Coastguard Worker assert len(items) == 7 419*288bf522SAndroid Build Coastguard Worker children_overhead = float(items[0][:-1]) 420*288bf522SAndroid Build Coastguard Worker overhead = float(items[1][:-1]) 421*288bf522SAndroid Build Coastguard Worker comm = items[2] 422*288bf522SAndroid Build Coastguard Worker symbol_name = items[6] 423*288bf522SAndroid Build Coastguard Worker cur_symbol = Symbol(symbol_name, comm, overhead, children_overhead) 424*288bf522SAndroid Build Coastguard Worker symbols.append(cur_symbol) 425*288bf522SAndroid Build Coastguard Worker else: 426*288bf522SAndroid Build Coastguard Worker items = line.split(None, 5) 427*288bf522SAndroid Build Coastguard Worker assert len(items) == 6 428*288bf522SAndroid Build Coastguard Worker overhead = float(items[0][:-1]) 429*288bf522SAndroid Build Coastguard Worker comm = items[1] 430*288bf522SAndroid Build Coastguard Worker symbol_name = items[5] 431*288bf522SAndroid Build Coastguard Worker cur_symbol = Symbol(symbol_name, comm, overhead, 0) 432*288bf522SAndroid Build Coastguard Worker symbols.append(cur_symbol) 433*288bf522SAndroid Build Coastguard Worker # Each report item can have different column depths. 434*288bf522SAndroid Build Coastguard Worker vertical_columns = [] 435*288bf522SAndroid Build Coastguard Worker else: 436*288bf522SAndroid Build Coastguard Worker for i in range(len(line)): 437*288bf522SAndroid Build Coastguard Worker if line[i] == '|': 438*288bf522SAndroid Build Coastguard Worker if not vertical_columns or vertical_columns[-1] < i: 439*288bf522SAndroid Build Coastguard Worker vertical_columns.append(i) 440*288bf522SAndroid Build Coastguard Worker 441*288bf522SAndroid Build Coastguard Worker if not line.strip('| \t'): 442*288bf522SAndroid Build Coastguard Worker continue 443*288bf522SAndroid Build Coastguard Worker if line.find('-') == -1: 444*288bf522SAndroid Build Coastguard Worker function_name = line.strip('| \t') 445*288bf522SAndroid Build Coastguard Worker node = CallTreeNode(function_name) 446*288bf522SAndroid Build Coastguard Worker last_node.add_child(node) 447*288bf522SAndroid Build Coastguard Worker last_node = node 448*288bf522SAndroid Build Coastguard Worker call_tree_stack[last_depth] = node 449*288bf522SAndroid Build Coastguard Worker else: 450*288bf522SAndroid Build Coastguard Worker pos = line.find('-') 451*288bf522SAndroid Build Coastguard Worker depth = -1 452*288bf522SAndroid Build Coastguard Worker for i in range(len(vertical_columns)): 453*288bf522SAndroid Build Coastguard Worker if pos >= vertical_columns[i]: 454*288bf522SAndroid Build Coastguard Worker depth = i 455*288bf522SAndroid Build Coastguard Worker assert depth != -1 456*288bf522SAndroid Build Coastguard Worker 457*288bf522SAndroid Build Coastguard Worker line = line.strip('|- \t') 458*288bf522SAndroid Build Coastguard Worker m = re.search(r'^[\d\.]+%[-\s]+(.+)$', line) 459*288bf522SAndroid Build Coastguard Worker if m: 460*288bf522SAndroid Build Coastguard Worker function_name = m.group(1) 461*288bf522SAndroid Build Coastguard Worker else: 462*288bf522SAndroid Build Coastguard Worker function_name = line 463*288bf522SAndroid Build Coastguard Worker 464*288bf522SAndroid Build Coastguard Worker node = CallTreeNode(function_name) 465*288bf522SAndroid Build Coastguard Worker if depth == 0: 466*288bf522SAndroid Build Coastguard Worker cur_symbol.set_call_tree(node) 467*288bf522SAndroid Build Coastguard Worker 468*288bf522SAndroid Build Coastguard Worker else: 469*288bf522SAndroid Build Coastguard Worker call_tree_stack[depth - 1].add_child(node) 470*288bf522SAndroid Build Coastguard Worker call_tree_stack[depth] = node 471*288bf522SAndroid Build Coastguard Worker last_node = node 472*288bf522SAndroid Build Coastguard Worker last_depth = depth 473*288bf522SAndroid Build Coastguard Worker 474*288bf522SAndroid Build Coastguard Worker return symbols 475*288bf522SAndroid Build Coastguard Worker 476*288bf522SAndroid Build Coastguard Worker def check_report_file(self, test, report_file, has_callgraph): 477*288bf522SAndroid Build Coastguard Worker symbols = self._read_report_file(report_file, has_callgraph) 478*288bf522SAndroid Build Coastguard Worker if not self._check_symbol_overhead_requirements(test, symbols): 479*288bf522SAndroid Build Coastguard Worker return False 480*288bf522SAndroid Build Coastguard Worker if has_callgraph: 481*288bf522SAndroid Build Coastguard Worker if not self._check_symbol_children_overhead_requirements(test, symbols): 482*288bf522SAndroid Build Coastguard Worker return False 483*288bf522SAndroid Build Coastguard Worker if not self._check_symbol_relation_requirements(test, symbols): 484*288bf522SAndroid Build Coastguard Worker return False 485*288bf522SAndroid Build Coastguard Worker return True 486*288bf522SAndroid Build Coastguard Worker 487*288bf522SAndroid Build Coastguard Worker def _check_symbol_overhead_requirements(self, test, symbols): 488*288bf522SAndroid Build Coastguard Worker result = True 489*288bf522SAndroid Build Coastguard Worker matched = [False] * len(test.symbol_overhead_requirements) 490*288bf522SAndroid Build Coastguard Worker matched_overhead = [0] * len(test.symbol_overhead_requirements) 491*288bf522SAndroid Build Coastguard Worker for symbol in symbols: 492*288bf522SAndroid Build Coastguard Worker for i in range(len(test.symbol_overhead_requirements)): 493*288bf522SAndroid Build Coastguard Worker req = test.symbol_overhead_requirements[i] 494*288bf522SAndroid Build Coastguard Worker if req.is_match(symbol): 495*288bf522SAndroid Build Coastguard Worker matched[i] = True 496*288bf522SAndroid Build Coastguard Worker matched_overhead[i] += symbol.overhead 497*288bf522SAndroid Build Coastguard Worker for i in range(len(matched)): 498*288bf522SAndroid Build Coastguard Worker if not matched[i]: 499*288bf522SAndroid Build Coastguard Worker print 'requirement (%s) has no matched symbol in test %s' % ( 500*288bf522SAndroid Build Coastguard Worker test.symbol_overhead_requirements[i], test) 501*288bf522SAndroid Build Coastguard Worker result = False 502*288bf522SAndroid Build Coastguard Worker else: 503*288bf522SAndroid Build Coastguard Worker fulfilled = req.check_overhead(matched_overhead[i]) 504*288bf522SAndroid Build Coastguard Worker if not fulfilled: 505*288bf522SAndroid Build Coastguard Worker print "Symbol (%s) doesn't match requirement (%s) in test %s" % ( 506*288bf522SAndroid Build Coastguard Worker symbol, req, test) 507*288bf522SAndroid Build Coastguard Worker result = False 508*288bf522SAndroid Build Coastguard Worker return result 509*288bf522SAndroid Build Coastguard Worker 510*288bf522SAndroid Build Coastguard Worker def _check_symbol_children_overhead_requirements(self, test, symbols): 511*288bf522SAndroid Build Coastguard Worker result = True 512*288bf522SAndroid Build Coastguard Worker matched = [False] * len(test.symbol_children_overhead_requirements) 513*288bf522SAndroid Build Coastguard Worker for symbol in symbols: 514*288bf522SAndroid Build Coastguard Worker for i in range(len(test.symbol_children_overhead_requirements)): 515*288bf522SAndroid Build Coastguard Worker req = test.symbol_children_overhead_requirements[i] 516*288bf522SAndroid Build Coastguard Worker if req.is_match(symbol): 517*288bf522SAndroid Build Coastguard Worker matched[i] = True 518*288bf522SAndroid Build Coastguard Worker fulfilled = req.check_overhead(symbol.children_overhead) 519*288bf522SAndroid Build Coastguard Worker if not fulfilled: 520*288bf522SAndroid Build Coastguard Worker print "Symbol (%s) doesn't match requirement (%s) in test %s" % ( 521*288bf522SAndroid Build Coastguard Worker symbol, req, test) 522*288bf522SAndroid Build Coastguard Worker result = False 523*288bf522SAndroid Build Coastguard Worker for i in range(len(matched)): 524*288bf522SAndroid Build Coastguard Worker if not matched[i]: 525*288bf522SAndroid Build Coastguard Worker print 'requirement (%s) has no matched symbol in test %s' % ( 526*288bf522SAndroid Build Coastguard Worker test.symbol_children_overhead_requirements[i], test) 527*288bf522SAndroid Build Coastguard Worker result = False 528*288bf522SAndroid Build Coastguard Worker return result 529*288bf522SAndroid Build Coastguard Worker 530*288bf522SAndroid Build Coastguard Worker def _check_symbol_relation_requirements(self, test, symbols): 531*288bf522SAndroid Build Coastguard Worker result = True 532*288bf522SAndroid Build Coastguard Worker matched = [False] * len(test.symbol_relation_requirements) 533*288bf522SAndroid Build Coastguard Worker for symbol in symbols: 534*288bf522SAndroid Build Coastguard Worker for i in range(len(test.symbol_relation_requirements)): 535*288bf522SAndroid Build Coastguard Worker req = test.symbol_relation_requirements[i] 536*288bf522SAndroid Build Coastguard Worker if req.is_match(symbol): 537*288bf522SAndroid Build Coastguard Worker matched[i] = True 538*288bf522SAndroid Build Coastguard Worker fulfilled = req.check_relation(symbol.call_tree) 539*288bf522SAndroid Build Coastguard Worker if not fulfilled: 540*288bf522SAndroid Build Coastguard Worker print "Symbol (%s) doesn't match requirement (%s) in test %s" % ( 541*288bf522SAndroid Build Coastguard Worker symbol, req, test) 542*288bf522SAndroid Build Coastguard Worker result = False 543*288bf522SAndroid Build Coastguard Worker for i in range(len(matched)): 544*288bf522SAndroid Build Coastguard Worker if not matched[i]: 545*288bf522SAndroid Build Coastguard Worker print 'requirement (%s) has no matched symbol in test %s' % ( 546*288bf522SAndroid Build Coastguard Worker test.symbol_relation_requirements[i], test) 547*288bf522SAndroid Build Coastguard Worker result = False 548*288bf522SAndroid Build Coastguard Worker return result 549*288bf522SAndroid Build Coastguard Worker 550*288bf522SAndroid Build Coastguard Worker 551*288bf522SAndroid Build Coastguard Workerdef build_runner(target, use_callgraph, sampler): 552*288bf522SAndroid Build Coastguard Worker if target == 'host32' and use_callgraph: 553*288bf522SAndroid Build Coastguard Worker print "Current 64bit linux host doesn't support `simpleperf32 record -g`" 554*288bf522SAndroid Build Coastguard Worker return None 555*288bf522SAndroid Build Coastguard Worker if target.startswith('host'): 556*288bf522SAndroid Build Coastguard Worker runner = HostRunner(target) 557*288bf522SAndroid Build Coastguard Worker else: 558*288bf522SAndroid Build Coastguard Worker runner = DeviceRunner(target) 559*288bf522SAndroid Build Coastguard Worker runner.use_callgraph = use_callgraph 560*288bf522SAndroid Build Coastguard Worker runner.sampler = sampler 561*288bf522SAndroid Build Coastguard Worker return runner 562*288bf522SAndroid Build Coastguard Worker 563*288bf522SAndroid Build Coastguard Worker 564*288bf522SAndroid Build Coastguard Workerdef test_with_runner(runner, tests): 565*288bf522SAndroid Build Coastguard Worker report_analyzer = ReportAnalyzer() 566*288bf522SAndroid Build Coastguard Worker for test in tests: 567*288bf522SAndroid Build Coastguard Worker if test.disable_host and runner.target.startswith('host'): 568*288bf522SAndroid Build Coastguard Worker print('Skip test %s on %s' % (test.test_name, runner.target)) 569*288bf522SAndroid Build Coastguard Worker continue 570*288bf522SAndroid Build Coastguard Worker runner.record(test.executable_name, 'perf.data', additional_options = test.record_options) 571*288bf522SAndroid Build Coastguard Worker runner.report('perf.data', 'perf.report', additional_options = test.report_options) 572*288bf522SAndroid Build Coastguard Worker result = report_analyzer.check_report_file(test, 'perf.report', runner.use_callgraph) 573*288bf522SAndroid Build Coastguard Worker str = 'test %s on %s ' % (test.test_name, runner.target) 574*288bf522SAndroid Build Coastguard Worker if runner.use_callgraph: 575*288bf522SAndroid Build Coastguard Worker str += 'with call graph ' 576*288bf522SAndroid Build Coastguard Worker str += 'using %s ' % runner.sampler 577*288bf522SAndroid Build Coastguard Worker str += ' Succeeded' if result else 'Failed' 578*288bf522SAndroid Build Coastguard Worker print str 579*288bf522SAndroid Build Coastguard Worker if not result: 580*288bf522SAndroid Build Coastguard Worker exit(1) 581*288bf522SAndroid Build Coastguard Worker 582*288bf522SAndroid Build Coastguard Worker 583*288bf522SAndroid Build Coastguard Workerdef runtest(target_options, use_callgraph_options, sampler_options, selected_tests): 584*288bf522SAndroid Build Coastguard Worker tests = load_config_file(os.path.dirname(os.path.realpath(__file__)) + \ 585*288bf522SAndroid Build Coastguard Worker '/runtest.conf') 586*288bf522SAndroid Build Coastguard Worker if selected_tests is not None: 587*288bf522SAndroid Build Coastguard Worker new_tests = [] 588*288bf522SAndroid Build Coastguard Worker for test in tests: 589*288bf522SAndroid Build Coastguard Worker if test.test_name in selected_tests: 590*288bf522SAndroid Build Coastguard Worker new_tests.append(test) 591*288bf522SAndroid Build Coastguard Worker tests = new_tests 592*288bf522SAndroid Build Coastguard Worker for target in target_options: 593*288bf522SAndroid Build Coastguard Worker for use_callgraph in use_callgraph_options: 594*288bf522SAndroid Build Coastguard Worker for sampler in sampler_options: 595*288bf522SAndroid Build Coastguard Worker runner = build_runner(target, use_callgraph, sampler) 596*288bf522SAndroid Build Coastguard Worker if runner is not None: 597*288bf522SAndroid Build Coastguard Worker test_with_runner(runner, tests) 598*288bf522SAndroid Build Coastguard Worker 599*288bf522SAndroid Build Coastguard Worker 600*288bf522SAndroid Build Coastguard Workerdef main(): 601*288bf522SAndroid Build Coastguard Worker target_options = ['host64', 'host32', 'device64', 'device32'] 602*288bf522SAndroid Build Coastguard Worker use_callgraph_options = [False, True] 603*288bf522SAndroid Build Coastguard Worker sampler_options = ['cpu-cycles'] 604*288bf522SAndroid Build Coastguard Worker selected_tests = None 605*288bf522SAndroid Build Coastguard Worker i = 1 606*288bf522SAndroid Build Coastguard Worker while i < len(sys.argv): 607*288bf522SAndroid Build Coastguard Worker if sys.argv[i] == '--host': 608*288bf522SAndroid Build Coastguard Worker target_options = ['host64', 'host32'] 609*288bf522SAndroid Build Coastguard Worker elif sys.argv[i] == '--device': 610*288bf522SAndroid Build Coastguard Worker target_options = ['device64', 'device32'] 611*288bf522SAndroid Build Coastguard Worker elif sys.argv[i] == '--normal': 612*288bf522SAndroid Build Coastguard Worker use_callgraph_options = [False] 613*288bf522SAndroid Build Coastguard Worker elif sys.argv[i] == '--callgraph': 614*288bf522SAndroid Build Coastguard Worker use_callgraph_options = [True] 615*288bf522SAndroid Build Coastguard Worker elif sys.argv[i] == '--test': 616*288bf522SAndroid Build Coastguard Worker if i < len(sys.argv): 617*288bf522SAndroid Build Coastguard Worker i += 1 618*288bf522SAndroid Build Coastguard Worker for test in sys.argv[i].split(','): 619*288bf522SAndroid Build Coastguard Worker if selected_tests is None: 620*288bf522SAndroid Build Coastguard Worker selected_tests = {} 621*288bf522SAndroid Build Coastguard Worker selected_tests[test] = True 622*288bf522SAndroid Build Coastguard Worker i += 1 623*288bf522SAndroid Build Coastguard Worker runtest(target_options, use_callgraph_options, sampler_options, selected_tests) 624*288bf522SAndroid Build Coastguard Worker 625*288bf522SAndroid Build Coastguard Workerif __name__ == '__main__': 626*288bf522SAndroid Build Coastguard Worker main() 627