10930ea88ef02f784044106c67b11f9b82afbda5dYabin Cui#!/usr/bin/env python
20930ea88ef02f784044106c67b11f9b82afbda5dYabin Cui#
30930ea88ef02f784044106c67b11f9b82afbda5dYabin Cui# Copyright (C) 2015 The Android Open Source Project
40930ea88ef02f784044106c67b11f9b82afbda5dYabin Cui#
50930ea88ef02f784044106c67b11f9b82afbda5dYabin Cui# Licensed under the Apache License, Version 2.0 (the "License");
60930ea88ef02f784044106c67b11f9b82afbda5dYabin Cui# you may not use this file except in compliance with the License.
70930ea88ef02f784044106c67b11f9b82afbda5dYabin Cui# You may obtain a copy of the License at
80930ea88ef02f784044106c67b11f9b82afbda5dYabin Cui#
90930ea88ef02f784044106c67b11f9b82afbda5dYabin Cui#      http://www.apache.org/licenses/LICENSE-2.0
100930ea88ef02f784044106c67b11f9b82afbda5dYabin Cui#
110930ea88ef02f784044106c67b11f9b82afbda5dYabin Cui# Unless required by applicable law or agreed to in writing, software
120930ea88ef02f784044106c67b11f9b82afbda5dYabin Cui# distributed under the License is distributed on an "AS IS" BASIS,
130930ea88ef02f784044106c67b11f9b82afbda5dYabin Cui# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
140930ea88ef02f784044106c67b11f9b82afbda5dYabin Cui# See the License for the specific language governing permissions and
150930ea88ef02f784044106c67b11f9b82afbda5dYabin Cui# limitations under the License.
160930ea88ef02f784044106c67b11f9b82afbda5dYabin Cui#
170930ea88ef02f784044106c67b11f9b82afbda5dYabin Cui"""Simpleperf runtest runner: run simpleperf runtests on host or on device.
180930ea88ef02f784044106c67b11f9b82afbda5dYabin Cui
19d4360f8c681a10d9d58173995aca2166aec65386Yabin CuiFor a simpleperf runtest like one_function test, it contains following steps:
20d4360f8c681a10d9d58173995aca2166aec65386Yabin Cui1. Run simpleperf record command to record simpleperf_runtest_one_function's
21d4360f8c681a10d9d58173995aca2166aec65386Yabin Cui   running samples, which is generated in perf.data.
22d4360f8c681a10d9d58173995aca2166aec65386Yabin Cui2. Run simpleperf report command to parse perf.data, generate perf.report.
23d4360f8c681a10d9d58173995aca2166aec65386Yabin Cui4. Parse perf.report and see if it matches expectation.
240930ea88ef02f784044106c67b11f9b82afbda5dYabin Cui
25d4360f8c681a10d9d58173995aca2166aec65386Yabin CuiThe information of all runtests is stored in runtest.conf.
260930ea88ef02f784044106c67b11f9b82afbda5dYabin Cui"""
270930ea88ef02f784044106c67b11f9b82afbda5dYabin Cui
280930ea88ef02f784044106c67b11f9b82afbda5dYabin Cuiimport re
290930ea88ef02f784044106c67b11f9b82afbda5dYabin Cuiimport subprocess
304a6c58dba06a907c2d687ff0983469c6abe640a7Yabin Cuiimport sys
310930ea88ef02f784044106c67b11f9b82afbda5dYabin Cuiimport xml.etree.ElementTree as ET
320930ea88ef02f784044106c67b11f9b82afbda5dYabin Cui
330930ea88ef02f784044106c67b11f9b82afbda5dYabin Cui
34d4360f8c681a10d9d58173995aca2166aec65386Yabin Cuiclass CallTreeNode(object):
35d4360f8c681a10d9d58173995aca2166aec65386Yabin Cui
36d4360f8c681a10d9d58173995aca2166aec65386Yabin Cui  def __init__(self, name):
37d4360f8c681a10d9d58173995aca2166aec65386Yabin Cui    self.name = name
38d4360f8c681a10d9d58173995aca2166aec65386Yabin Cui    self.children = []
39d4360f8c681a10d9d58173995aca2166aec65386Yabin Cui
40d4360f8c681a10d9d58173995aca2166aec65386Yabin Cui  def add_child(self, child):
41d4360f8c681a10d9d58173995aca2166aec65386Yabin Cui    self.children.append(child)
42d4360f8c681a10d9d58173995aca2166aec65386Yabin Cui
43d4360f8c681a10d9d58173995aca2166aec65386Yabin Cui  def __str__(self):
44d4360f8c681a10d9d58173995aca2166aec65386Yabin Cui    return 'CallTreeNode:\n' + '\n'.join(self._dump(1))
45d4360f8c681a10d9d58173995aca2166aec65386Yabin Cui
46d4360f8c681a10d9d58173995aca2166aec65386Yabin Cui  def _dump(self, indent):
47d4360f8c681a10d9d58173995aca2166aec65386Yabin Cui    indent_str = '  ' * indent
48d4360f8c681a10d9d58173995aca2166aec65386Yabin Cui    strs = [indent_str + self.name]
49d4360f8c681a10d9d58173995aca2166aec65386Yabin Cui    for child in self.children:
50d4360f8c681a10d9d58173995aca2166aec65386Yabin Cui      strs.extend(child._dump(indent + 1))
51d4360f8c681a10d9d58173995aca2166aec65386Yabin Cui    return strs
52d4360f8c681a10d9d58173995aca2166aec65386Yabin Cui
53d4360f8c681a10d9d58173995aca2166aec65386Yabin Cui
540930ea88ef02f784044106c67b11f9b82afbda5dYabin Cuiclass Symbol(object):
550930ea88ef02f784044106c67b11f9b82afbda5dYabin Cui
56d4360f8c681a10d9d58173995aca2166aec65386Yabin Cui  def __init__(self, name, comm, overhead, children_overhead):
570930ea88ef02f784044106c67b11f9b82afbda5dYabin Cui    self.name = name
580930ea88ef02f784044106c67b11f9b82afbda5dYabin Cui    self.comm = comm
590930ea88ef02f784044106c67b11f9b82afbda5dYabin Cui    self.overhead = overhead
60d4360f8c681a10d9d58173995aca2166aec65386Yabin Cui    # children_overhead is the overhead sum of this symbol and functions
61d4360f8c681a10d9d58173995aca2166aec65386Yabin Cui    # called by this symbol.
62d4360f8c681a10d9d58173995aca2166aec65386Yabin Cui    self.children_overhead = children_overhead
63d4360f8c681a10d9d58173995aca2166aec65386Yabin Cui    self.call_tree = None
64d4360f8c681a10d9d58173995aca2166aec65386Yabin Cui
65d4360f8c681a10d9d58173995aca2166aec65386Yabin Cui  def set_call_tree(self, call_tree):
66d4360f8c681a10d9d58173995aca2166aec65386Yabin Cui    self.call_tree = call_tree
670930ea88ef02f784044106c67b11f9b82afbda5dYabin Cui
680930ea88ef02f784044106c67b11f9b82afbda5dYabin Cui  def __str__(self):
69d4360f8c681a10d9d58173995aca2166aec65386Yabin Cui    strs = []
70d4360f8c681a10d9d58173995aca2166aec65386Yabin Cui    strs.append('Symbol name=%s comm=%s overhead=%f children_overhead=%f' % (
71d4360f8c681a10d9d58173995aca2166aec65386Yabin Cui        self.name, self.comm, self.overhead, self.children_overhead))
72d4360f8c681a10d9d58173995aca2166aec65386Yabin Cui    if self.call_tree:
73d4360f8c681a10d9d58173995aca2166aec65386Yabin Cui      strs.append('\t%s' % self.call_tree)
74d4360f8c681a10d9d58173995aca2166aec65386Yabin Cui    return '\n'.join(strs)
750930ea88ef02f784044106c67b11f9b82afbda5dYabin Cui
760930ea88ef02f784044106c67b11f9b82afbda5dYabin Cui
770930ea88ef02f784044106c67b11f9b82afbda5dYabin Cuiclass SymbolOverheadRequirement(object):
780930ea88ef02f784044106c67b11f9b82afbda5dYabin Cui
794a6c58dba06a907c2d687ff0983469c6abe640a7Yabin Cui  def __init__(self, symbol_name=None, comm=None, min_overhead=None,
800930ea88ef02f784044106c67b11f9b82afbda5dYabin Cui               max_overhead=None):
810930ea88ef02f784044106c67b11f9b82afbda5dYabin Cui    self.symbol_name = symbol_name
820930ea88ef02f784044106c67b11f9b82afbda5dYabin Cui    self.comm = comm
830930ea88ef02f784044106c67b11f9b82afbda5dYabin Cui    self.min_overhead = min_overhead
840930ea88ef02f784044106c67b11f9b82afbda5dYabin Cui    self.max_overhead = max_overhead
850930ea88ef02f784044106c67b11f9b82afbda5dYabin Cui
860930ea88ef02f784044106c67b11f9b82afbda5dYabin Cui  def __str__(self):
870930ea88ef02f784044106c67b11f9b82afbda5dYabin Cui    strs = []
884a6c58dba06a907c2d687ff0983469c6abe640a7Yabin Cui    strs.append('SymbolOverheadRequirement')
894a6c58dba06a907c2d687ff0983469c6abe640a7Yabin Cui    if self.symbol_name is not None:
904a6c58dba06a907c2d687ff0983469c6abe640a7Yabin Cui      strs.append('symbol_name=%s' % self.symbol_name)
910930ea88ef02f784044106c67b11f9b82afbda5dYabin Cui    if self.comm is not None:
920930ea88ef02f784044106c67b11f9b82afbda5dYabin Cui      strs.append('comm=%s' % self.comm)
930930ea88ef02f784044106c67b11f9b82afbda5dYabin Cui    if self.min_overhead is not None:
940930ea88ef02f784044106c67b11f9b82afbda5dYabin Cui      strs.append('min_overhead=%f' % self.min_overhead)
950930ea88ef02f784044106c67b11f9b82afbda5dYabin Cui    if self.max_overhead is not None:
960930ea88ef02f784044106c67b11f9b82afbda5dYabin Cui      strs.append('max_overhead=%f' % self.max_overhead)
970930ea88ef02f784044106c67b11f9b82afbda5dYabin Cui    return ' '.join(strs)
980930ea88ef02f784044106c67b11f9b82afbda5dYabin Cui
990930ea88ef02f784044106c67b11f9b82afbda5dYabin Cui  def is_match(self, symbol):
1004a6c58dba06a907c2d687ff0983469c6abe640a7Yabin Cui    if self.symbol_name is not None:
1014a6c58dba06a907c2d687ff0983469c6abe640a7Yabin Cui      if self.symbol_name != symbol.name:
1024a6c58dba06a907c2d687ff0983469c6abe640a7Yabin Cui        return False
1030930ea88ef02f784044106c67b11f9b82afbda5dYabin Cui    if self.comm is not None:
1040930ea88ef02f784044106c67b11f9b82afbda5dYabin Cui      if self.comm != symbol.comm:
1050930ea88ef02f784044106c67b11f9b82afbda5dYabin Cui        return False
1060930ea88ef02f784044106c67b11f9b82afbda5dYabin Cui    return True
1070930ea88ef02f784044106c67b11f9b82afbda5dYabin Cui
108d4360f8c681a10d9d58173995aca2166aec65386Yabin Cui  def check_overhead(self, overhead):
1090930ea88ef02f784044106c67b11f9b82afbda5dYabin Cui    if self.min_overhead is not None:
110d4360f8c681a10d9d58173995aca2166aec65386Yabin Cui      if self.min_overhead > overhead:
1110930ea88ef02f784044106c67b11f9b82afbda5dYabin Cui        return False
1120930ea88ef02f784044106c67b11f9b82afbda5dYabin Cui    if self.max_overhead is not None:
113d4360f8c681a10d9d58173995aca2166aec65386Yabin Cui      if self.max_overhead < overhead:
114d4360f8c681a10d9d58173995aca2166aec65386Yabin Cui        return False
115d4360f8c681a10d9d58173995aca2166aec65386Yabin Cui    return True
116d4360f8c681a10d9d58173995aca2166aec65386Yabin Cui
117d4360f8c681a10d9d58173995aca2166aec65386Yabin Cui
118d4360f8c681a10d9d58173995aca2166aec65386Yabin Cuiclass SymbolRelationRequirement(object):
119d4360f8c681a10d9d58173995aca2166aec65386Yabin Cui
120d4360f8c681a10d9d58173995aca2166aec65386Yabin Cui  def __init__(self, symbol_name, comm=None):
121d4360f8c681a10d9d58173995aca2166aec65386Yabin Cui    self.symbol_name = symbol_name
122d4360f8c681a10d9d58173995aca2166aec65386Yabin Cui    self.comm = comm
123d4360f8c681a10d9d58173995aca2166aec65386Yabin Cui    self.children = []
124d4360f8c681a10d9d58173995aca2166aec65386Yabin Cui
125d4360f8c681a10d9d58173995aca2166aec65386Yabin Cui  def add_child(self, child):
126d4360f8c681a10d9d58173995aca2166aec65386Yabin Cui    self.children.append(child)
127d4360f8c681a10d9d58173995aca2166aec65386Yabin Cui
128d4360f8c681a10d9d58173995aca2166aec65386Yabin Cui  def __str__(self):
129d4360f8c681a10d9d58173995aca2166aec65386Yabin Cui    return 'SymbolRelationRequirement:\n' + '\n'.join(self._dump(1))
130d4360f8c681a10d9d58173995aca2166aec65386Yabin Cui
131d4360f8c681a10d9d58173995aca2166aec65386Yabin Cui  def _dump(self, indent):
132d4360f8c681a10d9d58173995aca2166aec65386Yabin Cui    indent_str = '  ' * indent
133d4360f8c681a10d9d58173995aca2166aec65386Yabin Cui    strs = [indent_str + self.symbol_name +
134d4360f8c681a10d9d58173995aca2166aec65386Yabin Cui            (' ' + self.comm if self.comm else '')]
135d4360f8c681a10d9d58173995aca2166aec65386Yabin Cui    for child in self.children:
136d4360f8c681a10d9d58173995aca2166aec65386Yabin Cui      strs.extend(child._dump(indent + 1))
137d4360f8c681a10d9d58173995aca2166aec65386Yabin Cui    return strs
138d4360f8c681a10d9d58173995aca2166aec65386Yabin Cui
139d4360f8c681a10d9d58173995aca2166aec65386Yabin Cui  def is_match(self, symbol):
140d4360f8c681a10d9d58173995aca2166aec65386Yabin Cui    if symbol.name != self.symbol_name:
141d4360f8c681a10d9d58173995aca2166aec65386Yabin Cui      return False
142d4360f8c681a10d9d58173995aca2166aec65386Yabin Cui    if self.comm is not None:
143d4360f8c681a10d9d58173995aca2166aec65386Yabin Cui      if symbol.comm != self.comm:
144d4360f8c681a10d9d58173995aca2166aec65386Yabin Cui        return False
145d4360f8c681a10d9d58173995aca2166aec65386Yabin Cui    return True
146d4360f8c681a10d9d58173995aca2166aec65386Yabin Cui
147d4360f8c681a10d9d58173995aca2166aec65386Yabin Cui  def check_relation(self, call_tree):
148d4360f8c681a10d9d58173995aca2166aec65386Yabin Cui    if not call_tree:
149d4360f8c681a10d9d58173995aca2166aec65386Yabin Cui      return False
150d4360f8c681a10d9d58173995aca2166aec65386Yabin Cui    if self.symbol_name != call_tree.name:
151d4360f8c681a10d9d58173995aca2166aec65386Yabin Cui      return False
152d4360f8c681a10d9d58173995aca2166aec65386Yabin Cui    for child in self.children:
153d4360f8c681a10d9d58173995aca2166aec65386Yabin Cui      child_matched = False
154d4360f8c681a10d9d58173995aca2166aec65386Yabin Cui      for node in call_tree.children:
155d4360f8c681a10d9d58173995aca2166aec65386Yabin Cui        if child.check_relation(node):
156d4360f8c681a10d9d58173995aca2166aec65386Yabin Cui          child_matched = True
157d4360f8c681a10d9d58173995aca2166aec65386Yabin Cui          break
158d4360f8c681a10d9d58173995aca2166aec65386Yabin Cui      if not child_matched:
1590930ea88ef02f784044106c67b11f9b82afbda5dYabin Cui        return False
1600930ea88ef02f784044106c67b11f9b82afbda5dYabin Cui    return True
1610930ea88ef02f784044106c67b11f9b82afbda5dYabin Cui
1620930ea88ef02f784044106c67b11f9b82afbda5dYabin Cui
1630930ea88ef02f784044106c67b11f9b82afbda5dYabin Cuiclass Test(object):
1640930ea88ef02f784044106c67b11f9b82afbda5dYabin Cui
165d4360f8c681a10d9d58173995aca2166aec65386Yabin Cui  def __init__(
166d4360f8c681a10d9d58173995aca2166aec65386Yabin Cui          self,
167d4360f8c681a10d9d58173995aca2166aec65386Yabin Cui          test_name,
168d4360f8c681a10d9d58173995aca2166aec65386Yabin Cui          executable_name,
1694a6c58dba06a907c2d687ff0983469c6abe640a7Yabin Cui          report_options,
170d4360f8c681a10d9d58173995aca2166aec65386Yabin Cui          symbol_overhead_requirements,
171d4360f8c681a10d9d58173995aca2166aec65386Yabin Cui          symbol_children_overhead_requirements,
172d4360f8c681a10d9d58173995aca2166aec65386Yabin Cui          symbol_relation_requirements):
1730930ea88ef02f784044106c67b11f9b82afbda5dYabin Cui    self.test_name = test_name
1740930ea88ef02f784044106c67b11f9b82afbda5dYabin Cui    self.executable_name = executable_name
1754a6c58dba06a907c2d687ff0983469c6abe640a7Yabin Cui    self.report_options = report_options
1760930ea88ef02f784044106c67b11f9b82afbda5dYabin Cui    self.symbol_overhead_requirements = symbol_overhead_requirements
177d4360f8c681a10d9d58173995aca2166aec65386Yabin Cui    self.symbol_children_overhead_requirements = (
178d4360f8c681a10d9d58173995aca2166aec65386Yabin Cui        symbol_children_overhead_requirements)
179d4360f8c681a10d9d58173995aca2166aec65386Yabin Cui    self.symbol_relation_requirements = symbol_relation_requirements
1800930ea88ef02f784044106c67b11f9b82afbda5dYabin Cui
1810930ea88ef02f784044106c67b11f9b82afbda5dYabin Cui  def __str__(self):
1820930ea88ef02f784044106c67b11f9b82afbda5dYabin Cui    strs = []
1830930ea88ef02f784044106c67b11f9b82afbda5dYabin Cui    strs.append('Test test_name=%s' % self.test_name)
1840930ea88ef02f784044106c67b11f9b82afbda5dYabin Cui    strs.append('\texecutable_name=%s' % self.executable_name)
1854a6c58dba06a907c2d687ff0983469c6abe640a7Yabin Cui    strs.append('\treport_options=%s' % (' '.join(self.report_options)))
186d4360f8c681a10d9d58173995aca2166aec65386Yabin Cui    strs.append('\tsymbol_overhead_requirements:')
187d4360f8c681a10d9d58173995aca2166aec65386Yabin Cui    for req in self.symbol_overhead_requirements:
188d4360f8c681a10d9d58173995aca2166aec65386Yabin Cui      strs.append('\t\t%s' % req)
189d4360f8c681a10d9d58173995aca2166aec65386Yabin Cui    strs.append('\tsymbol_children_overhead_requirements:')
190d4360f8c681a10d9d58173995aca2166aec65386Yabin Cui    for req in self.symbol_children_overhead_requirements:
191d4360f8c681a10d9d58173995aca2166aec65386Yabin Cui      strs.append('\t\t%s' % req)
192d4360f8c681a10d9d58173995aca2166aec65386Yabin Cui    strs.append('\tsymbol_relation_requirements:')
193d4360f8c681a10d9d58173995aca2166aec65386Yabin Cui    for req in self.symbol_relation_requirements:
194d4360f8c681a10d9d58173995aca2166aec65386Yabin Cui      strs.append('\t\t%s' % req)
1950930ea88ef02f784044106c67b11f9b82afbda5dYabin Cui    return '\n'.join(strs)
1960930ea88ef02f784044106c67b11f9b82afbda5dYabin Cui
1970930ea88ef02f784044106c67b11f9b82afbda5dYabin Cui
1980930ea88ef02f784044106c67b11f9b82afbda5dYabin Cuidef load_config_file(config_file):
1990930ea88ef02f784044106c67b11f9b82afbda5dYabin Cui  tests = []
2000930ea88ef02f784044106c67b11f9b82afbda5dYabin Cui  tree = ET.parse(config_file)
2010930ea88ef02f784044106c67b11f9b82afbda5dYabin Cui  root = tree.getroot()
2020930ea88ef02f784044106c67b11f9b82afbda5dYabin Cui  assert root.tag == 'runtests'
2030930ea88ef02f784044106c67b11f9b82afbda5dYabin Cui  for test in root:
2040930ea88ef02f784044106c67b11f9b82afbda5dYabin Cui    assert test.tag == 'test'
2050930ea88ef02f784044106c67b11f9b82afbda5dYabin Cui    test_name = test.attrib['name']
2060930ea88ef02f784044106c67b11f9b82afbda5dYabin Cui    executable_name = None
2074a6c58dba06a907c2d687ff0983469c6abe640a7Yabin Cui    report_options = []
2080930ea88ef02f784044106c67b11f9b82afbda5dYabin Cui    symbol_overhead_requirements = []
209d4360f8c681a10d9d58173995aca2166aec65386Yabin Cui    symbol_children_overhead_requirements = []
210d4360f8c681a10d9d58173995aca2166aec65386Yabin Cui    symbol_relation_requirements = []
2110930ea88ef02f784044106c67b11f9b82afbda5dYabin Cui    for test_item in test:
2120930ea88ef02f784044106c67b11f9b82afbda5dYabin Cui      if test_item.tag == 'executable':
2130930ea88ef02f784044106c67b11f9b82afbda5dYabin Cui        executable_name = test_item.attrib['name']
2144a6c58dba06a907c2d687ff0983469c6abe640a7Yabin Cui      elif test_item.tag == 'report':
2154a6c58dba06a907c2d687ff0983469c6abe640a7Yabin Cui        report_options = test_item.attrib['option'].split()
216d4360f8c681a10d9d58173995aca2166aec65386Yabin Cui      elif (test_item.tag == 'symbol_overhead' or
217d4360f8c681a10d9d58173995aca2166aec65386Yabin Cui              test_item.tag == 'symbol_children_overhead'):
2180930ea88ef02f784044106c67b11f9b82afbda5dYabin Cui        for symbol_item in test_item:
2190930ea88ef02f784044106c67b11f9b82afbda5dYabin Cui          assert symbol_item.tag == 'symbol'
2204a6c58dba06a907c2d687ff0983469c6abe640a7Yabin Cui          symbol_name = None
2214a6c58dba06a907c2d687ff0983469c6abe640a7Yabin Cui          if 'name' in symbol_item.attrib:
2224a6c58dba06a907c2d687ff0983469c6abe640a7Yabin Cui            symbol_name = symbol_item.attrib['name']
2230930ea88ef02f784044106c67b11f9b82afbda5dYabin Cui          comm = None
2240930ea88ef02f784044106c67b11f9b82afbda5dYabin Cui          if 'comm' in symbol_item.attrib:
2250930ea88ef02f784044106c67b11f9b82afbda5dYabin Cui            comm = symbol_item.attrib['comm']
2260930ea88ef02f784044106c67b11f9b82afbda5dYabin Cui          overhead_min = None
2270930ea88ef02f784044106c67b11f9b82afbda5dYabin Cui          if 'min' in symbol_item.attrib:
2280930ea88ef02f784044106c67b11f9b82afbda5dYabin Cui            overhead_min = float(symbol_item.attrib['min'])
2290930ea88ef02f784044106c67b11f9b82afbda5dYabin Cui          overhead_max = None
2300930ea88ef02f784044106c67b11f9b82afbda5dYabin Cui          if 'max' in symbol_item.attrib:
2310930ea88ef02f784044106c67b11f9b82afbda5dYabin Cui            overhead_max = float(symbol_item.attrib['max'])
2320930ea88ef02f784044106c67b11f9b82afbda5dYabin Cui
233d4360f8c681a10d9d58173995aca2166aec65386Yabin Cui          if test_item.tag == 'symbol_overhead':
234d4360f8c681a10d9d58173995aca2166aec65386Yabin Cui            symbol_overhead_requirements.append(
235d4360f8c681a10d9d58173995aca2166aec65386Yabin Cui                SymbolOverheadRequirement(
236d4360f8c681a10d9d58173995aca2166aec65386Yabin Cui                    symbol_name,
237d4360f8c681a10d9d58173995aca2166aec65386Yabin Cui                    comm,
238d4360f8c681a10d9d58173995aca2166aec65386Yabin Cui                    overhead_min,
239d4360f8c681a10d9d58173995aca2166aec65386Yabin Cui                    overhead_max)
240d4360f8c681a10d9d58173995aca2166aec65386Yabin Cui            )
241d4360f8c681a10d9d58173995aca2166aec65386Yabin Cui          else:
242d4360f8c681a10d9d58173995aca2166aec65386Yabin Cui            symbol_children_overhead_requirements.append(
243d4360f8c681a10d9d58173995aca2166aec65386Yabin Cui                SymbolOverheadRequirement(
244d4360f8c681a10d9d58173995aca2166aec65386Yabin Cui                    symbol_name,
245d4360f8c681a10d9d58173995aca2166aec65386Yabin Cui                    comm,
246d4360f8c681a10d9d58173995aca2166aec65386Yabin Cui                    overhead_min,
247d4360f8c681a10d9d58173995aca2166aec65386Yabin Cui                    overhead_max))
248d4360f8c681a10d9d58173995aca2166aec65386Yabin Cui      elif test_item.tag == 'symbol_callgraph_relation':
249d4360f8c681a10d9d58173995aca2166aec65386Yabin Cui        for symbol_item in test_item:
250d4360f8c681a10d9d58173995aca2166aec65386Yabin Cui          req = load_symbol_relation_requirement(symbol_item)
251d4360f8c681a10d9d58173995aca2166aec65386Yabin Cui          symbol_relation_requirements.append(req)
2520930ea88ef02f784044106c67b11f9b82afbda5dYabin Cui
2530930ea88ef02f784044106c67b11f9b82afbda5dYabin Cui    tests.append(
254d4360f8c681a10d9d58173995aca2166aec65386Yabin Cui        Test(
255d4360f8c681a10d9d58173995aca2166aec65386Yabin Cui            test_name,
256d4360f8c681a10d9d58173995aca2166aec65386Yabin Cui            executable_name,
2574a6c58dba06a907c2d687ff0983469c6abe640a7Yabin Cui            report_options,
258d4360f8c681a10d9d58173995aca2166aec65386Yabin Cui            symbol_overhead_requirements,
259d4360f8c681a10d9d58173995aca2166aec65386Yabin Cui            symbol_children_overhead_requirements,
260d4360f8c681a10d9d58173995aca2166aec65386Yabin Cui            symbol_relation_requirements))
2610930ea88ef02f784044106c67b11f9b82afbda5dYabin Cui  return tests
2620930ea88ef02f784044106c67b11f9b82afbda5dYabin Cui
2630930ea88ef02f784044106c67b11f9b82afbda5dYabin Cui
264d4360f8c681a10d9d58173995aca2166aec65386Yabin Cuidef load_symbol_relation_requirement(symbol_item):
265d4360f8c681a10d9d58173995aca2166aec65386Yabin Cui  symbol_name = symbol_item.attrib['name']
266d4360f8c681a10d9d58173995aca2166aec65386Yabin Cui  comm = None
267d4360f8c681a10d9d58173995aca2166aec65386Yabin Cui  if 'comm' in symbol_item.attrib:
268d4360f8c681a10d9d58173995aca2166aec65386Yabin Cui    comm = symbol_item.attrib['comm']
269d4360f8c681a10d9d58173995aca2166aec65386Yabin Cui  req = SymbolRelationRequirement(symbol_name, comm)
270d4360f8c681a10d9d58173995aca2166aec65386Yabin Cui  for item in symbol_item:
271d4360f8c681a10d9d58173995aca2166aec65386Yabin Cui    child_req = load_symbol_relation_requirement(item)
272d4360f8c681a10d9d58173995aca2166aec65386Yabin Cui    req.add_child(child_req)
273d4360f8c681a10d9d58173995aca2166aec65386Yabin Cui  return req
274d4360f8c681a10d9d58173995aca2166aec65386Yabin Cui
275d4360f8c681a10d9d58173995aca2166aec65386Yabin Cui
2760930ea88ef02f784044106c67b11f9b82afbda5dYabin Cuiclass Runner(object):
2770930ea88ef02f784044106c67b11f9b82afbda5dYabin Cui
2780930ea88ef02f784044106c67b11f9b82afbda5dYabin Cui  def __init__(self, perf_path):
2790930ea88ef02f784044106c67b11f9b82afbda5dYabin Cui    self.perf_path = perf_path
2800930ea88ef02f784044106c67b11f9b82afbda5dYabin Cui
281d4360f8c681a10d9d58173995aca2166aec65386Yabin Cui  def record(self, test_executable_name, record_file, additional_options=[]):
282d4360f8c681a10d9d58173995aca2166aec65386Yabin Cui    call_args = [self.perf_path,
283d4360f8c681a10d9d58173995aca2166aec65386Yabin Cui                 'record'] + additional_options + ['-e',
284d4360f8c681a10d9d58173995aca2166aec65386Yabin Cui                                                   'cpu-cycles:u',
285d4360f8c681a10d9d58173995aca2166aec65386Yabin Cui                                                   '-o',
286d4360f8c681a10d9d58173995aca2166aec65386Yabin Cui                                                   record_file,
287d4360f8c681a10d9d58173995aca2166aec65386Yabin Cui                                                   test_executable_name]
2880930ea88ef02f784044106c67b11f9b82afbda5dYabin Cui    self._call(call_args)
2890930ea88ef02f784044106c67b11f9b82afbda5dYabin Cui
290d4360f8c681a10d9d58173995aca2166aec65386Yabin Cui  def report(self, record_file, report_file, additional_options=[]):
291d4360f8c681a10d9d58173995aca2166aec65386Yabin Cui    call_args = [self.perf_path,
292d4360f8c681a10d9d58173995aca2166aec65386Yabin Cui                 'report'] + additional_options + ['-i',
293d4360f8c681a10d9d58173995aca2166aec65386Yabin Cui                                                   record_file]
2940930ea88ef02f784044106c67b11f9b82afbda5dYabin Cui    self._call(call_args, report_file)
2950930ea88ef02f784044106c67b11f9b82afbda5dYabin Cui
2960930ea88ef02f784044106c67b11f9b82afbda5dYabin Cui  def _call(self, args, output_file=None):
2970930ea88ef02f784044106c67b11f9b82afbda5dYabin Cui    pass
2980930ea88ef02f784044106c67b11f9b82afbda5dYabin Cui
2990930ea88ef02f784044106c67b11f9b82afbda5dYabin Cui
3000930ea88ef02f784044106c67b11f9b82afbda5dYabin Cuiclass HostRunner(Runner):
3010930ea88ef02f784044106c67b11f9b82afbda5dYabin Cui
3020930ea88ef02f784044106c67b11f9b82afbda5dYabin Cui  """Run perf test on host."""
3030930ea88ef02f784044106c67b11f9b82afbda5dYabin Cui
3040930ea88ef02f784044106c67b11f9b82afbda5dYabin Cui  def _call(self, args, output_file=None):
3050930ea88ef02f784044106c67b11f9b82afbda5dYabin Cui    output_fh = None
3060930ea88ef02f784044106c67b11f9b82afbda5dYabin Cui    if output_file is not None:
3070930ea88ef02f784044106c67b11f9b82afbda5dYabin Cui      output_fh = open(output_file, 'w')
3080930ea88ef02f784044106c67b11f9b82afbda5dYabin Cui    subprocess.check_call(args, stdout=output_fh)
3090930ea88ef02f784044106c67b11f9b82afbda5dYabin Cui    if output_fh is not None:
3100930ea88ef02f784044106c67b11f9b82afbda5dYabin Cui      output_fh.close()
3110930ea88ef02f784044106c67b11f9b82afbda5dYabin Cui
3120930ea88ef02f784044106c67b11f9b82afbda5dYabin Cui
3130930ea88ef02f784044106c67b11f9b82afbda5dYabin Cuiclass DeviceRunner(Runner):
3140930ea88ef02f784044106c67b11f9b82afbda5dYabin Cui
3150930ea88ef02f784044106c67b11f9b82afbda5dYabin Cui  """Run perf test on device."""
3160930ea88ef02f784044106c67b11f9b82afbda5dYabin Cui
3170930ea88ef02f784044106c67b11f9b82afbda5dYabin Cui  def _call(self, args, output_file=None):
3180930ea88ef02f784044106c67b11f9b82afbda5dYabin Cui    output_fh = None
3190930ea88ef02f784044106c67b11f9b82afbda5dYabin Cui    if output_file is not None:
3200930ea88ef02f784044106c67b11f9b82afbda5dYabin Cui      output_fh = open(output_file, 'w')
3210930ea88ef02f784044106c67b11f9b82afbda5dYabin Cui    args_with_adb = ['adb', 'shell']
3220930ea88ef02f784044106c67b11f9b82afbda5dYabin Cui    args_with_adb.extend(args)
3230930ea88ef02f784044106c67b11f9b82afbda5dYabin Cui    subprocess.check_call(args_with_adb, stdout=output_fh)
3240930ea88ef02f784044106c67b11f9b82afbda5dYabin Cui    if output_fh is not None:
3250930ea88ef02f784044106c67b11f9b82afbda5dYabin Cui      output_fh.close()
3260930ea88ef02f784044106c67b11f9b82afbda5dYabin Cui
3270930ea88ef02f784044106c67b11f9b82afbda5dYabin Cui
3280930ea88ef02f784044106c67b11f9b82afbda5dYabin Cuiclass ReportAnalyzer(object):
3290930ea88ef02f784044106c67b11f9b82afbda5dYabin Cui
3300930ea88ef02f784044106c67b11f9b82afbda5dYabin Cui  """Check if perf.report matches expectation in Configuration."""
3310930ea88ef02f784044106c67b11f9b82afbda5dYabin Cui
332d4360f8c681a10d9d58173995aca2166aec65386Yabin Cui  def _read_report_file(self, report_file, has_callgraph):
333d4360f8c681a10d9d58173995aca2166aec65386Yabin Cui    fh = open(report_file, 'r')
334d4360f8c681a10d9d58173995aca2166aec65386Yabin Cui    lines = fh.readlines()
335d4360f8c681a10d9d58173995aca2166aec65386Yabin Cui    fh.close()
336d4360f8c681a10d9d58173995aca2166aec65386Yabin Cui
337d4360f8c681a10d9d58173995aca2166aec65386Yabin Cui    lines = [x.rstrip() for x in lines]
338d4360f8c681a10d9d58173995aca2166aec65386Yabin Cui    blank_line_index = -1
339d4360f8c681a10d9d58173995aca2166aec65386Yabin Cui    for i in range(len(lines)):
340d4360f8c681a10d9d58173995aca2166aec65386Yabin Cui      if not lines[i]:
341d4360f8c681a10d9d58173995aca2166aec65386Yabin Cui        blank_line_index = i
342d4360f8c681a10d9d58173995aca2166aec65386Yabin Cui    assert blank_line_index != -1
343d4360f8c681a10d9d58173995aca2166aec65386Yabin Cui    assert blank_line_index + 1 < len(lines)
344d4360f8c681a10d9d58173995aca2166aec65386Yabin Cui    title_line = lines[blank_line_index + 1]
345d4360f8c681a10d9d58173995aca2166aec65386Yabin Cui    report_item_lines = lines[blank_line_index + 2:]
346d4360f8c681a10d9d58173995aca2166aec65386Yabin Cui
347d4360f8c681a10d9d58173995aca2166aec65386Yabin Cui    if has_callgraph:
348d4360f8c681a10d9d58173995aca2166aec65386Yabin Cui      assert re.search(r'^Children\s+Self\s+Command.+Symbol$', title_line)
349d4360f8c681a10d9d58173995aca2166aec65386Yabin Cui    else:
350d4360f8c681a10d9d58173995aca2166aec65386Yabin Cui      assert re.search(r'^Overhead\s+Command.+Symbol$', title_line)
351d4360f8c681a10d9d58173995aca2166aec65386Yabin Cui
352d4360f8c681a10d9d58173995aca2166aec65386Yabin Cui    return self._parse_report_items(report_item_lines, has_callgraph)
353d4360f8c681a10d9d58173995aca2166aec65386Yabin Cui
354d4360f8c681a10d9d58173995aca2166aec65386Yabin Cui  def _parse_report_items(self, lines, has_callgraph):
3550930ea88ef02f784044106c67b11f9b82afbda5dYabin Cui    symbols = []
356d4360f8c681a10d9d58173995aca2166aec65386Yabin Cui    cur_symbol = None
357d4360f8c681a10d9d58173995aca2166aec65386Yabin Cui    call_tree_stack = {}
358d4360f8c681a10d9d58173995aca2166aec65386Yabin Cui    vertical_columns = []
359d4360f8c681a10d9d58173995aca2166aec65386Yabin Cui    last_node = None
360d4360f8c681a10d9d58173995aca2166aec65386Yabin Cui    last_depth = -1
361d4360f8c681a10d9d58173995aca2166aec65386Yabin Cui
362d4360f8c681a10d9d58173995aca2166aec65386Yabin Cui    for line in lines:
363d4360f8c681a10d9d58173995aca2166aec65386Yabin Cui      if not line:
364d4360f8c681a10d9d58173995aca2166aec65386Yabin Cui        continue
365d4360f8c681a10d9d58173995aca2166aec65386Yabin Cui      if not line[0].isspace():
366d4360f8c681a10d9d58173995aca2166aec65386Yabin Cui        if has_callgraph:
367d4360f8c681a10d9d58173995aca2166aec65386Yabin Cui          m = re.search(r'^([\d\.]+)%\s+([\d\.]+)%\s+(\S+).*\s+(\S+)$', line)
368d4360f8c681a10d9d58173995aca2166aec65386Yabin Cui          children_overhead = float(m.group(1))
369d4360f8c681a10d9d58173995aca2166aec65386Yabin Cui          overhead = float(m.group(2))
370d4360f8c681a10d9d58173995aca2166aec65386Yabin Cui          comm = m.group(3)
371d4360f8c681a10d9d58173995aca2166aec65386Yabin Cui          symbol_name = m.group(4)
372d4360f8c681a10d9d58173995aca2166aec65386Yabin Cui          cur_symbol = Symbol(symbol_name, comm, overhead, children_overhead)
373d4360f8c681a10d9d58173995aca2166aec65386Yabin Cui          symbols.append(cur_symbol)
374d4360f8c681a10d9d58173995aca2166aec65386Yabin Cui        else:
375d4360f8c681a10d9d58173995aca2166aec65386Yabin Cui          m = re.search(r'^([\d\.]+)%\s+(\S+).*\s+(\S+)$', line)
376d4360f8c681a10d9d58173995aca2166aec65386Yabin Cui          overhead = float(m.group(1))
377d4360f8c681a10d9d58173995aca2166aec65386Yabin Cui          comm = m.group(2)
378d4360f8c681a10d9d58173995aca2166aec65386Yabin Cui          symbol_name = m.group(3)
379d4360f8c681a10d9d58173995aca2166aec65386Yabin Cui          cur_symbol = Symbol(symbol_name, comm, overhead, 0)
380d4360f8c681a10d9d58173995aca2166aec65386Yabin Cui          symbols.append(cur_symbol)
381d4360f8c681a10d9d58173995aca2166aec65386Yabin Cui        # Each report item can have different column depths.
382d4360f8c681a10d9d58173995aca2166aec65386Yabin Cui        vertical_columns = []
3830930ea88ef02f784044106c67b11f9b82afbda5dYabin Cui      else:
384d4360f8c681a10d9d58173995aca2166aec65386Yabin Cui        for i in range(len(line)):
385d4360f8c681a10d9d58173995aca2166aec65386Yabin Cui          if line[i] == '|':
386d4360f8c681a10d9d58173995aca2166aec65386Yabin Cui            if not vertical_columns or vertical_columns[-1] < i:
387d4360f8c681a10d9d58173995aca2166aec65386Yabin Cui              vertical_columns.append(i)
388d4360f8c681a10d9d58173995aca2166aec65386Yabin Cui
389d4360f8c681a10d9d58173995aca2166aec65386Yabin Cui        if not line.strip('| \t'):
3900930ea88ef02f784044106c67b11f9b82afbda5dYabin Cui          continue
391d4360f8c681a10d9d58173995aca2166aec65386Yabin Cui        if line.find('-') == -1:
392d4360f8c681a10d9d58173995aca2166aec65386Yabin Cui          function_name = line.strip('| \t')
393d4360f8c681a10d9d58173995aca2166aec65386Yabin Cui          node = CallTreeNode(function_name)
394d4360f8c681a10d9d58173995aca2166aec65386Yabin Cui          last_node.add_child(node)
395d4360f8c681a10d9d58173995aca2166aec65386Yabin Cui          last_node = node
396d4360f8c681a10d9d58173995aca2166aec65386Yabin Cui          call_tree_stack[last_depth] = node
397d4360f8c681a10d9d58173995aca2166aec65386Yabin Cui        else:
398d4360f8c681a10d9d58173995aca2166aec65386Yabin Cui          pos = line.find('-')
399d4360f8c681a10d9d58173995aca2166aec65386Yabin Cui          depth = -1
400d4360f8c681a10d9d58173995aca2166aec65386Yabin Cui          for i in range(len(vertical_columns)):
401d4360f8c681a10d9d58173995aca2166aec65386Yabin Cui            if pos >= vertical_columns[i]:
402d4360f8c681a10d9d58173995aca2166aec65386Yabin Cui              depth = i
403d4360f8c681a10d9d58173995aca2166aec65386Yabin Cui          assert depth != -1
404d4360f8c681a10d9d58173995aca2166aec65386Yabin Cui
405d4360f8c681a10d9d58173995aca2166aec65386Yabin Cui          line = line.strip('|- \t')
406d4360f8c681a10d9d58173995aca2166aec65386Yabin Cui          m = re.search(r'^[\d\.]+%[-\s]+(.+)$', line)
407d4360f8c681a10d9d58173995aca2166aec65386Yabin Cui          if m:
408d4360f8c681a10d9d58173995aca2166aec65386Yabin Cui            function_name = m.group(1)
409d4360f8c681a10d9d58173995aca2166aec65386Yabin Cui          else:
410d4360f8c681a10d9d58173995aca2166aec65386Yabin Cui            function_name = line
411d4360f8c681a10d9d58173995aca2166aec65386Yabin Cui
412d4360f8c681a10d9d58173995aca2166aec65386Yabin Cui          node = CallTreeNode(function_name)
413d4360f8c681a10d9d58173995aca2166aec65386Yabin Cui          if depth == 0:
414d4360f8c681a10d9d58173995aca2166aec65386Yabin Cui            cur_symbol.set_call_tree(node)
415d4360f8c681a10d9d58173995aca2166aec65386Yabin Cui
416d4360f8c681a10d9d58173995aca2166aec65386Yabin Cui          else:
417d4360f8c681a10d9d58173995aca2166aec65386Yabin Cui            call_tree_stack[depth - 1].add_child(node)
418d4360f8c681a10d9d58173995aca2166aec65386Yabin Cui          call_tree_stack[depth] = node
419d4360f8c681a10d9d58173995aca2166aec65386Yabin Cui          last_node = node
420d4360f8c681a10d9d58173995aca2166aec65386Yabin Cui          last_depth = depth
4210930ea88ef02f784044106c67b11f9b82afbda5dYabin Cui
4220930ea88ef02f784044106c67b11f9b82afbda5dYabin Cui    return symbols
4230930ea88ef02f784044106c67b11f9b82afbda5dYabin Cui
424d4360f8c681a10d9d58173995aca2166aec65386Yabin Cui  def check_report_file(self, test, report_file, has_callgraph):
425d4360f8c681a10d9d58173995aca2166aec65386Yabin Cui    symbols = self._read_report_file(report_file, has_callgraph)
426d4360f8c681a10d9d58173995aca2166aec65386Yabin Cui    if not self._check_symbol_overhead_requirements(test, symbols):
427d4360f8c681a10d9d58173995aca2166aec65386Yabin Cui      return False
428d4360f8c681a10d9d58173995aca2166aec65386Yabin Cui    if has_callgraph:
429d4360f8c681a10d9d58173995aca2166aec65386Yabin Cui      if not self._check_symbol_children_overhead_requirements(test, symbols):
430d4360f8c681a10d9d58173995aca2166aec65386Yabin Cui        return False
431d4360f8c681a10d9d58173995aca2166aec65386Yabin Cui      if not self._check_symbol_relation_requirements(test, symbols):
432d4360f8c681a10d9d58173995aca2166aec65386Yabin Cui        return False
433d4360f8c681a10d9d58173995aca2166aec65386Yabin Cui    return True
4340930ea88ef02f784044106c67b11f9b82afbda5dYabin Cui
435d4360f8c681a10d9d58173995aca2166aec65386Yabin Cui  def _check_symbol_overhead_requirements(self, test, symbols):
4360930ea88ef02f784044106c67b11f9b82afbda5dYabin Cui    result = True
4370930ea88ef02f784044106c67b11f9b82afbda5dYabin Cui    matched = [False] * len(test.symbol_overhead_requirements)
4384a6c58dba06a907c2d687ff0983469c6abe640a7Yabin Cui    matched_overhead = [0] * len(test.symbol_overhead_requirements)
4390930ea88ef02f784044106c67b11f9b82afbda5dYabin Cui    for symbol in symbols:
4400930ea88ef02f784044106c67b11f9b82afbda5dYabin Cui      for i in range(len(test.symbol_overhead_requirements)):
441d4360f8c681a10d9d58173995aca2166aec65386Yabin Cui        req = test.symbol_overhead_requirements[i]
442d4360f8c681a10d9d58173995aca2166aec65386Yabin Cui        if req.is_match(symbol):
4430930ea88ef02f784044106c67b11f9b82afbda5dYabin Cui          matched[i] = True
4444a6c58dba06a907c2d687ff0983469c6abe640a7Yabin Cui          matched_overhead[i] += symbol.overhead
4450930ea88ef02f784044106c67b11f9b82afbda5dYabin Cui    for i in range(len(matched)):
4460930ea88ef02f784044106c67b11f9b82afbda5dYabin Cui      if not matched[i]:
4470930ea88ef02f784044106c67b11f9b82afbda5dYabin Cui        print 'requirement (%s) has no matched symbol in test %s' % (
4480930ea88ef02f784044106c67b11f9b82afbda5dYabin Cui            test.symbol_overhead_requirements[i], test)
4490930ea88ef02f784044106c67b11f9b82afbda5dYabin Cui        result = False
4504a6c58dba06a907c2d687ff0983469c6abe640a7Yabin Cui      else:
4514a6c58dba06a907c2d687ff0983469c6abe640a7Yabin Cui        fulfilled = req.check_overhead(matched_overhead[i])
4524a6c58dba06a907c2d687ff0983469c6abe640a7Yabin Cui        if not fulfilled:
4534a6c58dba06a907c2d687ff0983469c6abe640a7Yabin Cui          print "Symbol (%s) doesn't match requirement (%s) in test %s" % (
4544a6c58dba06a907c2d687ff0983469c6abe640a7Yabin Cui              symbol, req, test)
4554a6c58dba06a907c2d687ff0983469c6abe640a7Yabin Cui          result = False
4560930ea88ef02f784044106c67b11f9b82afbda5dYabin Cui    return result
4570930ea88ef02f784044106c67b11f9b82afbda5dYabin Cui
458d4360f8c681a10d9d58173995aca2166aec65386Yabin Cui  def _check_symbol_children_overhead_requirements(self, test, symbols):
459d4360f8c681a10d9d58173995aca2166aec65386Yabin Cui    result = True
460d4360f8c681a10d9d58173995aca2166aec65386Yabin Cui    matched = [False] * len(test.symbol_children_overhead_requirements)
461d4360f8c681a10d9d58173995aca2166aec65386Yabin Cui    for symbol in symbols:
462d4360f8c681a10d9d58173995aca2166aec65386Yabin Cui      for i in range(len(test.symbol_children_overhead_requirements)):
463d4360f8c681a10d9d58173995aca2166aec65386Yabin Cui        req = test.symbol_children_overhead_requirements[i]
464d4360f8c681a10d9d58173995aca2166aec65386Yabin Cui        if req.is_match(symbol):
465d4360f8c681a10d9d58173995aca2166aec65386Yabin Cui          matched[i] = True
466d4360f8c681a10d9d58173995aca2166aec65386Yabin Cui          fulfilled = req.check_overhead(symbol.children_overhead)
467d4360f8c681a10d9d58173995aca2166aec65386Yabin Cui          if not fulfilled:
468d4360f8c681a10d9d58173995aca2166aec65386Yabin Cui            print "Symbol (%s) doesn't match requirement (%s) in test %s" % (
469d4360f8c681a10d9d58173995aca2166aec65386Yabin Cui                symbol, req, test)
470d4360f8c681a10d9d58173995aca2166aec65386Yabin Cui            result = False
471d4360f8c681a10d9d58173995aca2166aec65386Yabin Cui    for i in range(len(matched)):
472d4360f8c681a10d9d58173995aca2166aec65386Yabin Cui      if not matched[i]:
473d4360f8c681a10d9d58173995aca2166aec65386Yabin Cui        print 'requirement (%s) has no matched symbol in test %s' % (
474d4360f8c681a10d9d58173995aca2166aec65386Yabin Cui            test.symbol_children_overhead_requirements[i], test)
475d4360f8c681a10d9d58173995aca2166aec65386Yabin Cui        result = False
476d4360f8c681a10d9d58173995aca2166aec65386Yabin Cui    return result
477d4360f8c681a10d9d58173995aca2166aec65386Yabin Cui
478d4360f8c681a10d9d58173995aca2166aec65386Yabin Cui  def _check_symbol_relation_requirements(self, test, symbols):
479d4360f8c681a10d9d58173995aca2166aec65386Yabin Cui    result = True
480d4360f8c681a10d9d58173995aca2166aec65386Yabin Cui    matched = [False] * len(test.symbol_relation_requirements)
481d4360f8c681a10d9d58173995aca2166aec65386Yabin Cui    for symbol in symbols:
482d4360f8c681a10d9d58173995aca2166aec65386Yabin Cui      for i in range(len(test.symbol_relation_requirements)):
483d4360f8c681a10d9d58173995aca2166aec65386Yabin Cui        req = test.symbol_relation_requirements[i]
484d4360f8c681a10d9d58173995aca2166aec65386Yabin Cui        if req.is_match(symbol):
485d4360f8c681a10d9d58173995aca2166aec65386Yabin Cui          matched[i] = True
486d4360f8c681a10d9d58173995aca2166aec65386Yabin Cui          fulfilled = req.check_relation(symbol.call_tree)
487d4360f8c681a10d9d58173995aca2166aec65386Yabin Cui          if not fulfilled:
488d4360f8c681a10d9d58173995aca2166aec65386Yabin Cui            print "Symbol (%s) doesn't match requirement (%s) in test %s" % (
489d4360f8c681a10d9d58173995aca2166aec65386Yabin Cui                symbol, req, test)
490d4360f8c681a10d9d58173995aca2166aec65386Yabin Cui            result = False
491d4360f8c681a10d9d58173995aca2166aec65386Yabin Cui    for i in range(len(matched)):
492d4360f8c681a10d9d58173995aca2166aec65386Yabin Cui      if not matched[i]:
493d4360f8c681a10d9d58173995aca2166aec65386Yabin Cui        print 'requirement (%s) has no matched symbol in test %s' % (
494d4360f8c681a10d9d58173995aca2166aec65386Yabin Cui            test.symbol_relation_requirements[i], test)
495d4360f8c681a10d9d58173995aca2166aec65386Yabin Cui        result = False
496d4360f8c681a10d9d58173995aca2166aec65386Yabin Cui    return result
497d4360f8c681a10d9d58173995aca2166aec65386Yabin Cui
4980930ea88ef02f784044106c67b11f9b82afbda5dYabin Cui
4994a6c58dba06a907c2d687ff0983469c6abe640a7Yabin Cuidef runtest(host, device, normal, callgraph, selected_tests):
5000930ea88ef02f784044106c67b11f9b82afbda5dYabin Cui  tests = load_config_file('runtest.conf')
5010930ea88ef02f784044106c67b11f9b82afbda5dYabin Cui  host_runner = HostRunner('simpleperf')
5020930ea88ef02f784044106c67b11f9b82afbda5dYabin Cui  device_runner = DeviceRunner('simpleperf')
5030930ea88ef02f784044106c67b11f9b82afbda5dYabin Cui  report_analyzer = ReportAnalyzer()
5040930ea88ef02f784044106c67b11f9b82afbda5dYabin Cui  for test in tests:
5054a6c58dba06a907c2d687ff0983469c6abe640a7Yabin Cui    if selected_tests is not None:
5064a6c58dba06a907c2d687ff0983469c6abe640a7Yabin Cui      if test.test_name not in selected_tests:
5074a6c58dba06a907c2d687ff0983469c6abe640a7Yabin Cui        continue
5084a6c58dba06a907c2d687ff0983469c6abe640a7Yabin Cui    if host and normal:
5094a6c58dba06a907c2d687ff0983469c6abe640a7Yabin Cui      host_runner.record(test.executable_name, 'perf.data')
5104a6c58dba06a907c2d687ff0983469c6abe640a7Yabin Cui      host_runner.report('perf.data', 'perf.report',
5114a6c58dba06a907c2d687ff0983469c6abe640a7Yabin Cui                         additional_options = test.report_options)
5124a6c58dba06a907c2d687ff0983469c6abe640a7Yabin Cui      result = report_analyzer.check_report_file(
5134a6c58dba06a907c2d687ff0983469c6abe640a7Yabin Cui          test, 'perf.report', False)
5144a6c58dba06a907c2d687ff0983469c6abe640a7Yabin Cui      print 'test %s on host %s' % (
5154a6c58dba06a907c2d687ff0983469c6abe640a7Yabin Cui          test.test_name, 'Succeeded' if result else 'Failed')
5164a6c58dba06a907c2d687ff0983469c6abe640a7Yabin Cui      if not result:
5174a6c58dba06a907c2d687ff0983469c6abe640a7Yabin Cui        exit(1)
5184a6c58dba06a907c2d687ff0983469c6abe640a7Yabin Cui
5194a6c58dba06a907c2d687ff0983469c6abe640a7Yabin Cui    if device and normal:
5204a6c58dba06a907c2d687ff0983469c6abe640a7Yabin Cui      device_runner.record(test.executable_name, '/data/perf.data')
5214a6c58dba06a907c2d687ff0983469c6abe640a7Yabin Cui      device_runner.report('/data/perf.data', 'perf.report',
5224a6c58dba06a907c2d687ff0983469c6abe640a7Yabin Cui                           additional_options = test.report_options)
5234a6c58dba06a907c2d687ff0983469c6abe640a7Yabin Cui      result = report_analyzer.check_report_file(test, 'perf.report', False)
5244a6c58dba06a907c2d687ff0983469c6abe640a7Yabin Cui      print 'test %s on device %s' % (
5254a6c58dba06a907c2d687ff0983469c6abe640a7Yabin Cui          test.test_name, 'Succeeded' if result else 'Failed')
5264a6c58dba06a907c2d687ff0983469c6abe640a7Yabin Cui      if not result:
5274a6c58dba06a907c2d687ff0983469c6abe640a7Yabin Cui        exit(1)
5284a6c58dba06a907c2d687ff0983469c6abe640a7Yabin Cui
5294a6c58dba06a907c2d687ff0983469c6abe640a7Yabin Cui    if host and callgraph:
5304a6c58dba06a907c2d687ff0983469c6abe640a7Yabin Cui      host_runner.record(
5314a6c58dba06a907c2d687ff0983469c6abe640a7Yabin Cui          test.executable_name,
5324a6c58dba06a907c2d687ff0983469c6abe640a7Yabin Cui          'perf_g.data',
5334a6c58dba06a907c2d687ff0983469c6abe640a7Yabin Cui          additional_options=['-g'])
5344a6c58dba06a907c2d687ff0983469c6abe640a7Yabin Cui      host_runner.report(
5354a6c58dba06a907c2d687ff0983469c6abe640a7Yabin Cui          'perf_g.data',
5364a6c58dba06a907c2d687ff0983469c6abe640a7Yabin Cui          'perf_g.report',
5374a6c58dba06a907c2d687ff0983469c6abe640a7Yabin Cui          additional_options=['-g'] + test.report_options)
5384a6c58dba06a907c2d687ff0983469c6abe640a7Yabin Cui      result = report_analyzer.check_report_file(test, 'perf_g.report', True)
5394a6c58dba06a907c2d687ff0983469c6abe640a7Yabin Cui      print 'call-graph test %s on host %s' % (
5404a6c58dba06a907c2d687ff0983469c6abe640a7Yabin Cui          test.test_name, 'Succeeded' if result else 'Failed')
5414a6c58dba06a907c2d687ff0983469c6abe640a7Yabin Cui      if not result:
5424a6c58dba06a907c2d687ff0983469c6abe640a7Yabin Cui        exit(1)
5434a6c58dba06a907c2d687ff0983469c6abe640a7Yabin Cui
5444a6c58dba06a907c2d687ff0983469c6abe640a7Yabin Cui    if device and callgraph:
5454a6c58dba06a907c2d687ff0983469c6abe640a7Yabin Cui      device_runner.record(
5464a6c58dba06a907c2d687ff0983469c6abe640a7Yabin Cui          test.executable_name,
5474a6c58dba06a907c2d687ff0983469c6abe640a7Yabin Cui          '/data/perf_g.data',
5484a6c58dba06a907c2d687ff0983469c6abe640a7Yabin Cui          additional_options=['-g'])
5494a6c58dba06a907c2d687ff0983469c6abe640a7Yabin Cui      device_runner.report(
5504a6c58dba06a907c2d687ff0983469c6abe640a7Yabin Cui          '/data/perf_g.data',
5514a6c58dba06a907c2d687ff0983469c6abe640a7Yabin Cui          'perf_g.report',
5524a6c58dba06a907c2d687ff0983469c6abe640a7Yabin Cui          additional_options=['-g'] + test.report_options)
5534a6c58dba06a907c2d687ff0983469c6abe640a7Yabin Cui      result = report_analyzer.check_report_file(test, 'perf_g.report', True)
5544a6c58dba06a907c2d687ff0983469c6abe640a7Yabin Cui      print 'call-graph test %s on device %s' % (
5554a6c58dba06a907c2d687ff0983469c6abe640a7Yabin Cui          test.test_name, 'Succeeded' if result else 'Failed')
5564a6c58dba06a907c2d687ff0983469c6abe640a7Yabin Cui      if not result:
5574a6c58dba06a907c2d687ff0983469c6abe640a7Yabin Cui        exit(1)
558d4360f8c681a10d9d58173995aca2166aec65386Yabin Cui
5594a6c58dba06a907c2d687ff0983469c6abe640a7Yabin Cuidef main():
5604a6c58dba06a907c2d687ff0983469c6abe640a7Yabin Cui  host = True
5614a6c58dba06a907c2d687ff0983469c6abe640a7Yabin Cui  device = True
5624a6c58dba06a907c2d687ff0983469c6abe640a7Yabin Cui  normal = True
5634a6c58dba06a907c2d687ff0983469c6abe640a7Yabin Cui  callgraph = True
5644a6c58dba06a907c2d687ff0983469c6abe640a7Yabin Cui  selected_tests = None
5654a6c58dba06a907c2d687ff0983469c6abe640a7Yabin Cui  i = 1
5664a6c58dba06a907c2d687ff0983469c6abe640a7Yabin Cui  while i < len(sys.argv):
5674a6c58dba06a907c2d687ff0983469c6abe640a7Yabin Cui    if sys.argv[i] == '--host':
5684a6c58dba06a907c2d687ff0983469c6abe640a7Yabin Cui      host = True
5694a6c58dba06a907c2d687ff0983469c6abe640a7Yabin Cui      device = False
5704a6c58dba06a907c2d687ff0983469c6abe640a7Yabin Cui    elif sys.argv[i] == '--device':
5714a6c58dba06a907c2d687ff0983469c6abe640a7Yabin Cui      host = False
5724a6c58dba06a907c2d687ff0983469c6abe640a7Yabin Cui      device = True
5734a6c58dba06a907c2d687ff0983469c6abe640a7Yabin Cui    elif sys.argv[i] == '--normal':
5744a6c58dba06a907c2d687ff0983469c6abe640a7Yabin Cui      normal = True
5754a6c58dba06a907c2d687ff0983469c6abe640a7Yabin Cui      callgraph = False
5764a6c58dba06a907c2d687ff0983469c6abe640a7Yabin Cui    elif sys.argv[i] == '--callgraph':
5774a6c58dba06a907c2d687ff0983469c6abe640a7Yabin Cui      normal = False
5784a6c58dba06a907c2d687ff0983469c6abe640a7Yabin Cui      callgraph = True
5794a6c58dba06a907c2d687ff0983469c6abe640a7Yabin Cui    elif sys.argv[i] == '--test':
5804a6c58dba06a907c2d687ff0983469c6abe640a7Yabin Cui      if i < len(sys.argv):
5814a6c58dba06a907c2d687ff0983469c6abe640a7Yabin Cui        i += 1
5824a6c58dba06a907c2d687ff0983469c6abe640a7Yabin Cui        for test in sys.argv[i].split(','):
5834a6c58dba06a907c2d687ff0983469c6abe640a7Yabin Cui          if selected_tests is None:
5844a6c58dba06a907c2d687ff0983469c6abe640a7Yabin Cui            selected_tests = {}
5854a6c58dba06a907c2d687ff0983469c6abe640a7Yabin Cui          selected_tests[test] = True
5864a6c58dba06a907c2d687ff0983469c6abe640a7Yabin Cui    i += 1
5874a6c58dba06a907c2d687ff0983469c6abe640a7Yabin Cui  runtest(host, device, normal, callgraph, selected_tests)
5880930ea88ef02f784044106c67b11f9b82afbda5dYabin Cui
5890930ea88ef02f784044106c67b11f9b82afbda5dYabin Cuiif __name__ == '__main__':
5900930ea88ef02f784044106c67b11f9b82afbda5dYabin Cui  main()
591