verify.py revision 13037:ae6f69952478
12SN/A#!/usr/bin/env python2 21762SN/A# 32SN/A# Copyright 2018 Google, Inc. 42SN/A# 52SN/A# Redistribution and use in source and binary forms, with or without 62SN/A# modification, are permitted provided that the following conditions are 72SN/A# met: redistributions of source code must retain the above copyright 82SN/A# notice, this list of conditions and the following disclaimer; 92SN/A# redistributions in binary form must reproduce the above copyright 102SN/A# notice, this list of conditions and the following disclaimer in the 112SN/A# documentation and/or other materials provided with the distribution; 122SN/A# neither the name of the copyright holders nor the names of its 132SN/A# contributors may be used to endorse or promote products derived from 142SN/A# this software without specific prior written permission. 152SN/A# 162SN/A# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 172SN/A# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 182SN/A# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 192SN/A# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 202SN/A# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 212SN/A# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 222SN/A# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 232SN/A# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 242SN/A# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 252SN/A# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 262SN/A# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 272665Ssaidi@eecs.umich.edu# 282760Sbinkertn@umich.edu# Authors: Gabe Black 292760Sbinkertn@umich.edu 302665Ssaidi@eecs.umich.edufrom __future__ import print_function 312SN/A 322SN/Aimport argparse 332SN/Aimport collections 34363SN/Aimport difflib 35363SN/Aimport functools 361354SN/Aimport inspect 372SN/Aimport itertools 382SN/Aimport json 392SN/Aimport multiprocessing.pool 402SN/Aimport os 412SN/Aimport re 422SN/Aimport subprocess 43363SN/Aimport sys 4456SN/A 451388SN/Ascript_path = os.path.abspath(inspect.getfile(inspect.currentframe())) 46217SN/Ascript_dir = os.path.dirname(script_path) 47363SN/Aconfig_path = os.path.join(script_dir, 'config.py') 4856SN/A 4956SN/Asystemc_rel_path = 'systemc' 5056SN/Atests_rel_path = os.path.join(systemc_rel_path, 'tests') 511638SN/Ajson_rel_path = os.path.join(tests_rel_path, 'tests.json') 5256SN/A 532SN/A 542356SN/A 552356SN/Adef scons(*args): 562356SN/A args = ['scons'] + list(args) 572SN/A subprocess.check_call(args) 582SN/A 594000Ssaidi@eecs.umich.edu 604000Ssaidi@eecs.umich.edu 614762Snate@binkert.orgclass Test(object): 624762Snate@binkert.org def __init__(self, target, suffix, build_dir, props): 634762Snate@binkert.org self.target = target 644762Snate@binkert.org self.suffix = suffix 654762Snate@binkert.org self.build_dir = build_dir 664762Snate@binkert.org self.props = {} 674762Snate@binkert.org 684762Snate@binkert.org for key, val in props.iteritems(): 694762Snate@binkert.org self.set_prop(key, val) 704762Snate@binkert.org 714762Snate@binkert.org def set_prop(self, key, val): 724762Snate@binkert.org setattr(self, key, val) 734762Snate@binkert.org self.props[key] = val 744762Snate@binkert.org 754762Snate@binkert.org def dir(self): 764762Snate@binkert.org return os.path.join(self.build_dir, tests_rel_path, self.path) 774762Snate@binkert.org 784762Snate@binkert.org def src_dir(self): 794762Snate@binkert.org return os.path.join(script_dir, self.path) 804762Snate@binkert.org 814762Snate@binkert.org def golden_dir(self): 824762Snate@binkert.org return os.path.join(self.src_dir(), 'golden') 834762Snate@binkert.org 844762Snate@binkert.org def bin(self): 854762Snate@binkert.org return '.'.join([self.name, self.suffix]) 864762Snate@binkert.org 874762Snate@binkert.org def full_path(self): 884762Snate@binkert.org return os.path.join(self.dir(), self.bin()) 894762Snate@binkert.org 907494Ssteve.reinhardt@amd.com def m5out_dir(self): 917494Ssteve.reinhardt@amd.com return os.path.join(self.dir(), 'm5out.' + self.suffix) 927494Ssteve.reinhardt@amd.com 937494Ssteve.reinhardt@amd.com def returncode_file(self): 947494Ssteve.reinhardt@amd.com return os.path.join(self.m5out_dir(), 'returncode') 957494Ssteve.reinhardt@amd.com 967494Ssteve.reinhardt@amd.com 977494Ssteve.reinhardt@amd.com 987490Ssteve.reinhardt@amd.comtest_phase_classes = {} 994762Snate@binkert.org 1004762Snate@binkert.orgclass TestPhaseMeta(type): 1014762Snate@binkert.org def __init__(cls, name, bases, d): 1024762Snate@binkert.org if not d.pop('abstract', False): 1034762Snate@binkert.org test_phase_classes[d['name']] = cls 1044762Snate@binkert.org 1054762Snate@binkert.org super(TestPhaseMeta, cls).__init__(name, bases, d) 1064762Snate@binkert.org 1074762Snate@binkert.orgclass TestPhaseBase(object): 1084762Snate@binkert.org __metaclass__ = TestPhaseMeta 1094762Snate@binkert.org abstract = True 1104762Snate@binkert.org 1114762Snate@binkert.org def __init__(self, main_args, *args): 1124762Snate@binkert.org self.main_args = main_args 1134762Snate@binkert.org self.args = args 1144762Snate@binkert.org 1154762Snate@binkert.org def __lt__(self, other): 1164762Snate@binkert.org return self.number < other.number 1174762Snate@binkert.org 1184762Snate@binkert.orgclass CompilePhase(TestPhaseBase): 1194762Snate@binkert.org name = 'compile' 1204762Snate@binkert.org number = 1 1214762Snate@binkert.org 1224762Snate@binkert.org def run(self, tests): 1234762Snate@binkert.org targets = list([test.full_path() for test in tests]) 1244762Snate@binkert.org scons_args = [ 'USE_SYSTEMC=1' ] + list(self.args) + targets 1254762Snate@binkert.org scons(*scons_args) 1264762Snate@binkert.org 1274762Snate@binkert.orgclass RunPhase(TestPhaseBase): 1284762Snate@binkert.org name = 'execute' 1294762Snate@binkert.org number = 2 1304762Snate@binkert.org 1314762Snate@binkert.org def run(self, tests): 1324762Snate@binkert.org parser = argparse.ArgumentParser() 1334762Snate@binkert.org parser.add_argument('--timeout', type=int, metavar='SECONDS', 1344762Snate@binkert.org help='Time limit for each run in seconds.', 1354762Snate@binkert.org default=0) 1364762Snate@binkert.org parser.add_argument('-j', type=int, default=1, 1374762Snate@binkert.org help='How many tests to run in parallel.') 1384762Snate@binkert.org args = parser.parse_args(self.args) 1394762Snate@binkert.org 1404762Snate@binkert.org timeout_cmd = [ 1414762Snate@binkert.org 'timeout', 1424762Snate@binkert.org '--kill-after', str(args.timeout * 2), 1434762Snate@binkert.org str(args.timeout) 1444762Snate@binkert.org ] 1454762Snate@binkert.org def run_test(test): 1464762Snate@binkert.org cmd = [] 1474762Snate@binkert.org if args.timeout: 1484762Snate@binkert.org cmd.extend(timeout_cmd) 1494762Snate@binkert.org cmd.extend([ 1504762Snate@binkert.org test.full_path(), 1514762Snate@binkert.org '-red', test.m5out_dir(), 1524762Snate@binkert.org '--listener-mode=off', 1534762Snate@binkert.org '--quiet', 1544762Snate@binkert.org config_path 1554762Snate@binkert.org ]) 1564762Snate@binkert.org # Ensure the output directory exists. 1574762Snate@binkert.org if not os.path.exists(test.m5out_dir()): 1584762Snate@binkert.org os.makedirs(test.m5out_dir()) 1594762Snate@binkert.org try: 1604762Snate@binkert.org subprocess.check_call(cmd) 1614762Snate@binkert.org except subprocess.CalledProcessError, error: 1624762Snate@binkert.org returncode = error.returncode 1634762Snate@binkert.org else: 1642287SN/A returncode = 0 1652287SN/A with open(test.returncode_file(), 'w') as rc: 1662287SN/A rc.write('%d\n' % returncode) 1671637SN/A 1682SN/A runnable = filter(lambda t: not t.compile_only, tests) 169395SN/A if args.j == 1: 1702SN/A map(run_test, runnable) 171217SN/A else: 1722SN/A tp = multiprocessing.pool.ThreadPool(args.j) 1732SN/A map(lambda t: tp.apply_async(run_test, (t,)), runnable) 1742SN/A tp.close() 175395SN/A tp.join() 1762SN/A 177217SN/Aclass Checker(object): 1782SN/A def __init__(self, ref, test, tag): 1792SN/A self.ref = ref 180217SN/A self.test = test 1812SN/A self.tag = tag 1826225Snate@binkert.org 1832SN/A def check(self): 184217SN/A with open(self.text) as test_f, open(self.ref) as ref_f: 185217SN/A return test_f.read() == ref_f.read() 186217SN/A 1872SN/Aclass LogChecker(Checker): 1882SN/A def merge_filts(*filts): 1894841Ssaidi@eecs.umich.edu filts = map(lambda f: '(' + f + ')', filts) 1904841Ssaidi@eecs.umich.edu filts = '|'.join(filts) 1916225Snate@binkert.org return re.compile(filts, flags=re.MULTILINE) 1924841Ssaidi@eecs.umich.edu 1936227Snate@binkert.org def warning_filt(num): 1944841Ssaidi@eecs.umich.edu return (r'^\nWarning: \(W{}\) .*\n(In file: .*\n)?' 1954841Ssaidi@eecs.umich.edu r'(In process: [\w.]* @ .*\n)?').format(num) 1964841Ssaidi@eecs.umich.edu 1976227Snate@binkert.org ref_filt = merge_filts( 1984841Ssaidi@eecs.umich.edu r'^\nInfo: /OSCI/SystemC: Simulation stopped by user.\n', 1994841Ssaidi@eecs.umich.edu r'^SystemC Simulation\n', 2004841Ssaidi@eecs.umich.edu warning_filt(540), 2014841Ssaidi@eecs.umich.edu warning_filt(569), 2024841Ssaidi@eecs.umich.edu warning_filt(571), 2034841Ssaidi@eecs.umich.edu r'^\nInfo: \(I804\) /IEEE_Std_1666/deprecated: ' + 2047948SAli.Saidi@ARM.com r'You can turn off(.*\n){7}' 2057948SAli.Saidi@ARM.com ) 2067948SAli.Saidi@ARM.com test_filt = merge_filts( 2077948SAli.Saidi@ARM.com r'^Global frequency set at \d* ticks per second\n' 2087948SAli.Saidi@ARM.com ) 2097948SAli.Saidi@ARM.com 2107948SAli.Saidi@ARM.com def __init__(self, ref, test, tag, out_dir): 2117948SAli.Saidi@ARM.com super(LogChecker, self).__init__(ref, test, tag) 2127948SAli.Saidi@ARM.com self.out_dir = out_dir 2137948SAli.Saidi@ARM.com 2147948SAli.Saidi@ARM.com def apply_filters(self, data, filts): 2157948SAli.Saidi@ARM.com re.sub(filt, '', data) 2167948SAli.Saidi@ARM.com 2177948SAli.Saidi@ARM.com def check(self): 2187948SAli.Saidi@ARM.com test_file = os.path.basename(self.test) 2197948SAli.Saidi@ARM.com ref_file = os.path.basename(self.ref) 2207948SAli.Saidi@ARM.com with open(self.test) as test_f, open(self.ref) as ref_f: 221217SN/A test = re.sub(self.test_filt, '', test_f.read()) 222217SN/A ref = re.sub(self.ref_filt, '', ref_f.read()) 223217SN/A diff_file = '.'.join([ref_file, 'diff']) 2246225Snate@binkert.org diff_path = os.path.join(self.out_dir, diff_file) 2252SN/A if test != ref: 2266225Snate@binkert.org with open(diff_path, 'w') as diff_f: 227237SN/A for line in difflib.unified_diff( 228217SN/A ref.splitlines(True), test.splitlines(True), 229217SN/A fromfile=ref_file, 2302SN/A tofile=test_file): 2312SN/A diff_f.write(line) 2326820SLisa.Hsu@amd.com return False 2336820SLisa.Hsu@amd.com else: 2346820SLisa.Hsu@amd.com if os.path.exists(diff_path): 2356820SLisa.Hsu@amd.com os.unlink(diff_path) 2366820SLisa.Hsu@amd.com return True 2376820SLisa.Hsu@amd.com 2386820SLisa.Hsu@amd.comclass GoldenDir(object): 2396820SLisa.Hsu@amd.com def __init__(self, path, platform): 2406820SLisa.Hsu@amd.com self.path = path 2416820SLisa.Hsu@amd.com self.platform = platform 2426820SLisa.Hsu@amd.com 2436820SLisa.Hsu@amd.com contents = os.listdir(path) 244217SN/A suffix = '.' + platform 245217SN/A suffixed = filter(lambda c: c.endswith(suffix), contents) 246217SN/A bases = map(lambda t: t[:-len(platform)], suffixed) 2476227Snate@binkert.org common = filter(lambda t: not t.startswith(tuple(bases)), contents) 248217SN/A 249217SN/A self.entries = {} 250217SN/A class Entry(object): 251217SN/A def __init__(self, e_path): 2526227Snate@binkert.org self.used = False 253217SN/A self.path = os.path.join(path, e_path) 254217SN/A 255217SN/A def use(self): 256217SN/A self.used = True 257217SN/A 258217SN/A for entry in contents: 259217SN/A self.entries[entry] = Entry(entry) 260217SN/A 261217SN/A def entry(self, name): 2626225Snate@binkert.org def match(n): 2636227Snate@binkert.org return (n == name) or n.startswith(name + '.') 264217SN/A matches = { n: e for n, e in self.entries.items() if match(n) } 2656225Snate@binkert.org 266237SN/A for match in matches.values(): 267217SN/A match.use() 268217SN/A 269217SN/A platform_name = '.'.join([ name, self.platform ]) 270217SN/A if platform_name in matches: 271217SN/A return matches[platform_name].path 272217SN/A if name in matches: 273217SN/A return matches[name].path 274217SN/A else: 275217SN/A return None 276217SN/A 277217SN/A def unused(self): 278217SN/A items = self.entries.items() 279217SN/A items = filter(lambda i: not i[1].used, items) 280217SN/A 281217SN/A items.sort() 282217SN/A sources = [] 283217SN/A i = 0 2846227Snate@binkert.org while i < len(items): 285217SN/A root = items[i][0] 286217SN/A sources.append(root) 287217SN/A i += 1 288217SN/A while i < len(items) and items[i][0].startswith(root): 2897576SAli.Saidi@ARM.com i += 1 290217SN/A return sources 291217SN/A 292217SN/Aclass VerifyPhase(TestPhaseBase): 293217SN/A name = 'verify' 294217SN/A number = 3 295217SN/A 296217SN/A def reset_status(self): 297217SN/A self._passed = [] 298217SN/A self._failed = {} 299217SN/A 300217SN/A def passed(self, test): 301217SN/A self._passed.append(test) 302217SN/A 303217SN/A def failed(self, test, cause, note=''): 3044841Ssaidi@eecs.umich.edu test.set_prop('note', note) 3054841Ssaidi@eecs.umich.edu self._failed.setdefault(cause, []).append(test) 3066225Snate@binkert.org 3076225Snate@binkert.org def print_status(self): 3084841Ssaidi@eecs.umich.edu total_passed = len(self._passed) 3096225Snate@binkert.org total_failed = sum(map(len, self._failed.values())) 3104841Ssaidi@eecs.umich.edu print() 3114841Ssaidi@eecs.umich.edu print('Passed: {passed:4} - Failed: {failed:4}'.format( 3124841Ssaidi@eecs.umich.edu passed=total_passed, failed=total_failed)) 3134841Ssaidi@eecs.umich.edu 3144841Ssaidi@eecs.umich.edu def write_result_file(self, path): 3154841Ssaidi@eecs.umich.edu results = { 3164841Ssaidi@eecs.umich.edu 'passed': map(lambda t: t.props, self._passed), 3174841Ssaidi@eecs.umich.edu 'failed': { 3184841Ssaidi@eecs.umich.edu cause: map(lambda t: t.props, tests) for 3194841Ssaidi@eecs.umich.edu cause, tests in self._failed.iteritems() 3204841Ssaidi@eecs.umich.edu } 3214841Ssaidi@eecs.umich.edu } 3224841Ssaidi@eecs.umich.edu with open(path, 'w') as rf: 3234841Ssaidi@eecs.umich.edu json.dump(results, rf) 3244841Ssaidi@eecs.umich.edu 3254841Ssaidi@eecs.umich.edu def print_results(self): 3266227Snate@binkert.org print() 3274841Ssaidi@eecs.umich.edu print('Passed:') 3284841Ssaidi@eecs.umich.edu for path in sorted(list([ t.path for t in self._passed ])): 3294841Ssaidi@eecs.umich.edu print(' ', path) 3304841Ssaidi@eecs.umich.edu 3317576SAli.Saidi@ARM.com print() 3324841Ssaidi@eecs.umich.edu print('Failed:') 3334841Ssaidi@eecs.umich.edu 3344841Ssaidi@eecs.umich.edu causes = [] 3354841Ssaidi@eecs.umich.edu for cause, tests in sorted(self._failed.items()): 3364841Ssaidi@eecs.umich.edu block = ' ' + cause.capitalize() + ':\n' 3374841Ssaidi@eecs.umich.edu for test in sorted(tests, key=lambda t: t.path): 3384841Ssaidi@eecs.umich.edu block += ' ' + test.path 3394841Ssaidi@eecs.umich.edu if test.note: 3404841Ssaidi@eecs.umich.edu block += ' - ' + test.note 3414841Ssaidi@eecs.umich.edu block += '\n' 3424841Ssaidi@eecs.umich.edu causes.append(block) 3434841Ssaidi@eecs.umich.edu 3444841Ssaidi@eecs.umich.edu print('\n'.join(causes)) 3454841Ssaidi@eecs.umich.edu 3467948SAli.Saidi@ARM.com def run(self, tests): 3477948SAli.Saidi@ARM.com parser = argparse.ArgumentParser() 3487948SAli.Saidi@ARM.com result_opts = parser.add_mutually_exclusive_group() 3497948SAli.Saidi@ARM.com result_opts.add_argument('--result-file', action='store_true', 3507948SAli.Saidi@ARM.com help='Create a results.json file in the current directory.') 3517948SAli.Saidi@ARM.com result_opts.add_argument('--result-file-at', metavar='PATH', 3527948SAli.Saidi@ARM.com help='Create a results json file at the given path.') 3537948SAli.Saidi@ARM.com parser.add_argument('--print-results', action='store_true', 3547948SAli.Saidi@ARM.com help='Print a list of tests that passed or failed') 3557948SAli.Saidi@ARM.com args = parser.parse_args(self.args) 3567948SAli.Saidi@ARM.com 3577948SAli.Saidi@ARM.com self.reset_status() 3587948SAli.Saidi@ARM.com 3597948SAli.Saidi@ARM.com runnable = filter(lambda t: not t.compile_only, tests) 3607948SAli.Saidi@ARM.com compile_only = filter(lambda t: t.compile_only, tests) 3617948SAli.Saidi@ARM.com 3627948SAli.Saidi@ARM.com for test in compile_only: 3637948SAli.Saidi@ARM.com if os.path.exists(test.full_path()): 3647948SAli.Saidi@ARM.com self.passed(test) 3657948SAli.Saidi@ARM.com else: 3667948SAli.Saidi@ARM.com self.failed(test, 'compile failed') 3677948SAli.Saidi@ARM.com 3687948SAli.Saidi@ARM.com for test in runnable: 3697948SAli.Saidi@ARM.com with open(test.returncode_file()) as rc: 3707948SAli.Saidi@ARM.com returncode = int(rc.read()) 3717948SAli.Saidi@ARM.com 3727948SAli.Saidi@ARM.com if returncode == 124: 3737948SAli.Saidi@ARM.com self.failed(test, 'time out') 3747948SAli.Saidi@ARM.com continue 3757948SAli.Saidi@ARM.com elif returncode != 0: 3767948SAli.Saidi@ARM.com self.failed(test, 'abort') 377237SN/A continue 3786225Snate@binkert.org 3796225Snate@binkert.org out_dir = test.m5out_dir() 380237SN/A 381237SN/A Diff = collections.namedtuple( 382237SN/A 'Diff', 'ref, test, tag, ref_filter') 383237SN/A 384237SN/A diffs = [] 385237SN/A 386237SN/A gd = GoldenDir(test.golden_dir(), 'linux64') 3875543Ssaidi@eecs.umich.edu 3885543Ssaidi@eecs.umich.edu missing = [] 3896225Snate@binkert.org log_file = '.'.join([test.name, 'log']) 3905543Ssaidi@eecs.umich.edu log_path = gd.entry(log_file) 3916225Snate@binkert.org simout_path = os.path.join(out_dir, 'simout') 3926225Snate@binkert.org if not os.path.exists(simout_path): 3936820SLisa.Hsu@amd.com missing.append('log output') 3946820SLisa.Hsu@amd.com elif log_path: 3956820SLisa.Hsu@amd.com diffs.append(LogChecker(log_path, simout_path, 3965543Ssaidi@eecs.umich.edu log_file, out_dir)) 3976225Snate@binkert.org 3986227Snate@binkert.org for name in gd.unused(): 3995543Ssaidi@eecs.umich.edu test_path = os.path.join(out_dir, name) 4006225Snate@binkert.org ref_path = gd.entry(name) 4016227Snate@binkert.org if not os.path.exists(test_path): 4025543Ssaidi@eecs.umich.edu missing.append(name) 4036225Snate@binkert.org else: 4046225Snate@binkert.org diffs.append(Checker(ref_path, test_path, name)) 4055543Ssaidi@eecs.umich.edu 4066225Snate@binkert.org if missing: 4077948SAli.Saidi@ARM.com self.failed(test, 'missing output', ' '.join(missing)) 4087948SAli.Saidi@ARM.com continue 4097948SAli.Saidi@ARM.com 4107948SAli.Saidi@ARM.com failed_diffs = filter(lambda d: not d.check(), diffs) 4117948SAli.Saidi@ARM.com if failed_diffs: 4127948SAli.Saidi@ARM.com tags = map(lambda d: d.tag, failed_diffs) 4137948SAli.Saidi@ARM.com self.failed(test, 'failed diffs', ' '.join(tags)) 414217SN/A continue 4157494Ssteve.reinhardt@amd.com 4161642SN/A self.passed(test) 4171642SN/A 4181642SN/A if args.print_results: 4191642SN/A self.print_results() 4201642SN/A 4211642SN/A self.print_status() 4221642SN/A 4231642SN/A result_path = None 4241642SN/A if args.result_file: 4251642SN/A result_path = os.path.join(os.getcwd(), 'results.json') 426219SN/A elif args.result_file_at: 4275992Snate@binkert.org result_path = args.result_file_at 4285992Snate@binkert.org 429217SN/A if result_path: 430217SN/A self.write_result_file(result_path) 431217SN/A 432395SN/A 433395SN/Aparser = argparse.ArgumentParser(description='SystemC test utility') 434395SN/A 435395SN/Aparser.add_argument('build_dir', metavar='BUILD_DIR', 436395SN/A help='The build directory (ie. build/ARM).') 4372SN/A 438395SN/Aparser.add_argument('--update-json', action='store_true', 439512SN/A help='Update the json manifest of tests.') 440510SN/A 441395SN/Aparser.add_argument('--flavor', choices=['debug', 'opt', 'fast'], 442395SN/A default='opt', 4432SN/A help='Flavor of binary to test.') 444395SN/A 445395SN/Aparser.add_argument('--list', action='store_true', 4462SN/A help='List the available tests') 447512SN/A 448395SN/Afilter_opts = parser.add_mutually_exclusive_group() 4492SN/Afilter_opts.add_argument('--filter', default='True', 450395SN/A help='Python expression which filters tests based ' 4512SN/A 'on their properties') 4522SN/Afilter_opts.add_argument('--filter-file', default=None, 4532SN/A type=argparse.FileType('r'), 454510SN/A help='Same as --filter, but read from a file') 4552SN/A 456395SN/Adef collect_phases(args): 4577864Ssteve.reinhardt@amd.com phase_groups = [list(g) for k, g in 458395SN/A itertools.groupby(args, lambda x: x != '--phase') if k] 459395SN/A main_args = parser.parse_args(phase_groups[0][1:]) 460395SN/A phases = [] 4612SN/A names = [] 4622SN/A for group in phase_groups[1:]: 4632SN/A name = group[0] 464395SN/A if name in names: 4652SN/A raise RuntimeException('Phase %s specified more than once' % name) 466395SN/A phase = test_phase_classes[name] 4677823Ssteve.reinhardt@amd.com phases.append(phase(main_args, *group[1:])) 4687823Ssteve.reinhardt@amd.com phases.sort() 4697823Ssteve.reinhardt@amd.com return main_args, phases 4702SN/A 471395SN/Amain_args, phases = collect_phases(sys.argv) 4722SN/A 4732SN/Aif len(phases) == 0: 4745739Snate@binkert.org phases = [ 4755739Snate@binkert.org CompilePhase(main_args), 4765739Snate@binkert.org RunPhase(main_args), 4775739Snate@binkert.org VerifyPhase(main_args) 4785739Snate@binkert.org ] 4795739Snate@binkert.org 4805739Snate@binkert.org 4815739Snate@binkert.org 4825739Snate@binkert.orgjson_path = os.path.join(main_args.build_dir, json_rel_path) 4836225Snate@binkert.org 4845739Snate@binkert.orgif main_args.update_json: 4855739Snate@binkert.org scons(os.path.join(json_path)) 4865739Snate@binkert.org 4875739Snate@binkert.orgwith open(json_path) as f: 4886225Snate@binkert.org test_data = json.load(f) 4895739Snate@binkert.org 4905739Snate@binkert.org if main_args.filter_file: 4915739Snate@binkert.org f = main_args.filter_file 4922SN/A filt = compile(f.read(), f.name, 'eval') 4936225Snate@binkert.org else: 4942SN/A filt = compile(main_args.filter, '<string>', 'eval') 4957491Ssteve.reinhardt@amd.com 496363SN/A filtered_tests = { 497449SN/A target: props for (target, props) in 498363SN/A test_data.iteritems() if eval(filt, dict(props)) 499449SN/A } 500395SN/A 5012SN/A if main_args.list: 5025581Ssaidi@eecs.umich.edu for target, props in sorted(filtered_tests.iteritems()): 5035581Ssaidi@eecs.umich.edu print('%s.%s' % (target, main_args.flavor)) 5046818SLisa.Hsu@amd.com for key, val in props.iteritems(): 5052SN/A print(' %s: %s' % (key, val)) 506395SN/A print('Total tests: %d' % len(filtered_tests)) 507395SN/A else: 508395SN/A tests_to_run = list([ 5092SN/A Test(target, main_args.flavor, main_args.build_dir, props) for 5102797Sktlim@umich.edu target, props in sorted(filtered_tests.iteritems()) 511395SN/A ]) 512395SN/A 513395SN/A for phase in phases: 514395SN/A phase.run(tests_to_run) 5152SN/A