xref: /aosp_15_r20/system/extras/simpleperf/runtest/runtest.py (revision 288bf5226967eb3dac5cce6c939ccc2a7f2b4fe5)
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