SConscript revision 9242:256143419b40
1545SN/A# -*- mode:python -*- 211010Sandreas.sandberg@arm.com 38948SN/A# Copyright (c) 2004-2006 The Regents of The University of Michigan 48948SN/A# All rights reserved. 58948SN/A# 68948SN/A# Redistribution and use in source and binary forms, with or without 78948SN/A# modification, are permitted provided that the following conditions are 88948SN/A# met: redistributions of source code must retain the above copyright 98948SN/A# notice, this list of conditions and the following disclaimer; 108948SN/A# redistributions in binary form must reproduce the above copyright 118948SN/A# notice, this list of conditions and the following disclaimer in the 128948SN/A# documentation and/or other materials provided with the distribution; 138948SN/A# neither the name of the copyright holders nor the names of its 142512SN/A# contributors may be used to endorse or promote products derived from 15545SN/A# this software without specific prior written permission. 16545SN/A# 17545SN/A# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 18545SN/A# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 19545SN/A# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 20545SN/A# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 21545SN/A# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 22545SN/A# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 23545SN/A# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 24545SN/A# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 25545SN/A# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 26545SN/A# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 27545SN/A# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 28545SN/A# 29545SN/A# Authors: Steve Reinhardt 30545SN/A# Kevin Lim 31545SN/A 32545SN/Aimport os, signal 33545SN/Aimport sys, time 34545SN/Aimport glob 35545SN/Afrom SCons.Script.SConscript import SConsEnvironment 36545SN/A 37545SN/AImport('env') 38545SN/A 392665SN/Aenv['DIFFOUT'] = File('diff-out') 402665SN/A 412665SN/A# get the termcap from the environment 429166Sandreas.hansson@arm.comtermcap = env['TERMCAP'] 4311010Sandreas.sandberg@arm.com 44545SN/A# Dict that accumulates lists of tests by category (quick, medium, long) 45545SN/Aenv.Tests = {} 4611010Sandreas.sandberg@arm.com 4711010Sandreas.sandberg@arm.comdef contents(node): 4811010Sandreas.sandberg@arm.com return file(str(node)).read() 4911010Sandreas.sandberg@arm.com 503090SN/A# functions to parse return value from scons Execute()... not the same 518232SN/A# as wait() etc., so python built-in os funcs don't work. 529152Satgutier@umich.edudef signaled(status): 532901SN/A return (status & 0x80) != 0; 54545SN/A 559165Sandreas.hansson@arm.comdef signum(status): 5611010Sandreas.sandberg@arm.com return (status & 0x7f); 5711010Sandreas.sandberg@arm.com 5811010Sandreas.sandberg@arm.com# List of signals that indicate that we should retry the test rather 592489SN/A# than consider it failed. 602489SN/Aretry_signals = (signal.SIGTERM, signal.SIGKILL, signal.SIGINT, 619166Sandreas.hansson@arm.com signal.SIGQUIT, signal.SIGHUP) 629166Sandreas.hansson@arm.com 639166Sandreas.hansson@arm.com# regular expressions of lines to ignore when diffing outputs 649166Sandreas.hansson@arm.comoutput_ignore_regexes = ( 659166Sandreas.hansson@arm.com '^command line:', # for stdout file 669166Sandreas.hansson@arm.com '^M5 compiled ', # for stderr file 679166Sandreas.hansson@arm.com '^M5 started ', # for stderr file 689166Sandreas.hansson@arm.com '^M5 executing on ', # for stderr file 699166Sandreas.hansson@arm.com '^Simulation complete at', # for stderr file 709166Sandreas.hansson@arm.com '^Listening for', # for stderr file 719166Sandreas.hansson@arm.com 'listening for remote gdb', # for stderr file 729166Sandreas.hansson@arm.com ) 739166Sandreas.hansson@arm.com 749166Sandreas.hansson@arm.comoutput_ignore_args = ' '.join(["-I '"+s+"'" for s in output_ignore_regexes]) 759166Sandreas.hansson@arm.com 769166Sandreas.hansson@arm.comoutput_ignore_args += ' --exclude=stats.txt --exclude=outdiff' 779166Sandreas.hansson@arm.com 789166Sandreas.hansson@arm.comdef run_test(target, source, env): 799166Sandreas.hansson@arm.com """Check output from running test. 809166Sandreas.hansson@arm.com 819166Sandreas.hansson@arm.com Targets are as follows: 829166Sandreas.hansson@arm.com target[0] : status 839166Sandreas.hansson@arm.com 849166Sandreas.hansson@arm.com Sources are: 859166Sandreas.hansson@arm.com source[0] : M5 binary 869166Sandreas.hansson@arm.com source[1] : tests/run.py script 879166Sandreas.hansson@arm.com source[2] : reference stats file 889166Sandreas.hansson@arm.com 899166Sandreas.hansson@arm.com """ 909166Sandreas.hansson@arm.com # make sure target files are all gone 919452SAndreas.Sandberg@ARM.com for t in target: 929166Sandreas.hansson@arm.com if os.path.exists(t.abspath): 939166Sandreas.hansson@arm.com env.Execute(Delete(t.abspath)) 949166Sandreas.hansson@arm.com 959166Sandreas.hansson@arm.com tgt_dir = os.path.dirname(str(target[0])) 969166Sandreas.hansson@arm.com 979166Sandreas.hansson@arm.com # Base command for running test. We mess around with indirectly 989166Sandreas.hansson@arm.com # referring to files via SOURCES and TARGETS so that scons can mess 999166Sandreas.hansson@arm.com # with paths all it wants to and we still get the right files. 1009166Sandreas.hansson@arm.com cmd = '${SOURCES[0]} -d %s -re ${SOURCES[1]} %s' % (tgt_dir, tgt_dir) 10110913Sandreas.sandberg@arm.com 10210913Sandreas.sandberg@arm.com # Prefix test run with batch job submission command if appropriate. 1039166Sandreas.hansson@arm.com # Batch command also supports timeout arg (in seconds, not minutes). 1049166Sandreas.hansson@arm.com timeout = 15 * 60 # used to be a param, probably should be again 1052489SN/A if env['BATCH']: 1068975SN/A cmd = '%s -t %d %s' % (env['BATCH_CMD'], timeout, cmd) 1072384SN/A 10811284Sandreas.hansson@arm.com pre_exec_time = time.time() 10910821Sandreas.hansson@arm.com status = env.Execute(env.subst(cmd, target=target, source=source)) 11011284Sandreas.hansson@arm.com if status == 0: 1114435SN/A # M5 terminated normally. 1129166Sandreas.hansson@arm.com # Run diff on output & ref directories to find differences. 1132569SN/A # Exclude the stats file since we will use diff-out on that. 1142657SN/A 1152384SN/A # NFS file systems can be annoying and not have updated yet 116679SN/A # wait until we see the file modified 1174762SN/A statsdiff = os.path.join(tgt_dir, 'statsdiff') 1189165Sandreas.hansson@arm.com m_time = 0 1192565SN/A nap = 0 1202384SN/A while m_time < pre_exec_time and nap < 10: 1218851SN/A try: 1228851SN/A m_time = os.stat(statsdiff).st_mtime 1238851SN/A except OSError: 1248851SN/A pass 1258851SN/A time.sleep(1) 1268851SN/A nap += 1 1278851SN/A 1288851SN/A outdiff = os.path.join(tgt_dir, 'outdiff') 12910913Sandreas.sandberg@arm.com # tack 'true' on the end so scons doesn't report diff's 13010913Sandreas.sandberg@arm.com # non-zero exit code as a build error 1312901SN/A diffcmd = 'diff -ubrs %s ${SOURCES[2].dir} %s > %s; true' \ 13210913Sandreas.sandberg@arm.com % (output_ignore_args, tgt_dir, outdiff) 13310913Sandreas.sandberg@arm.com env.Execute(env.subst(diffcmd, target=target, source=source)) 13410913Sandreas.sandberg@arm.com print "===== Output differences =====" 13510913Sandreas.sandberg@arm.com print contents(outdiff) 13610913Sandreas.sandberg@arm.com # Run diff-out on stats.txt file 13710913Sandreas.sandberg@arm.com diffcmd = '$DIFFOUT ${SOURCES[2]} %s > %s' \ 1382901SN/A % (os.path.join(tgt_dir, 'stats.txt'), statsdiff) 1392901SN/A diffcmd = env.subst(diffcmd, target=target, source=source) 1402384SN/A status = env.Execute(diffcmd, strfunction=None) 14110713Sandreas.hansson@arm.com print "===== Statistics differences =====" 1422489SN/A print contents(statsdiff) 1434435SN/A 1449307Sandreas.hansson@arm.com else: # m5 exit status != 0 1452489SN/A # M5 did not terminate properly, so no need to check the output 1462641SN/A if signaled(status): 14710621SCurtis.Dunham@arm.com print 'M5 terminated with signal', signum(status) 1482641SN/A if signum(status) in retry_signals: 1497607SN/A # Consider the test incomplete; don't create a 'status' output. 1502384SN/A # Hand the return status to scons and let scons decide what 1519166Sandreas.hansson@arm.com # to do about it (typically terminate unless run with -k). 1529166Sandreas.hansson@arm.com return status 1539166Sandreas.hansson@arm.com else: 1549016Sandreas.hansson@arm.com print 'M5 exited with non-zero status', status 1552384SN/A # complete but failed execution (call to exit() with non-zero 15610621SCurtis.Dunham@arm.com # status, SIGABORT due to assertion failure, etc.)... fall through 15710621SCurtis.Dunham@arm.com # and generate FAILED status as if output comparison had failed 15810621SCurtis.Dunham@arm.com 15910621SCurtis.Dunham@arm.com # Generate status file contents based on exit status of m5 or diff-out 16010621SCurtis.Dunham@arm.com if status == 0: 16110621SCurtis.Dunham@arm.com status_str = "passed." 1624451SN/A else: 1639166Sandreas.hansson@arm.com status_str = "FAILED!" 1649814Sandreas.hansson@arm.com f = file(str(target[0]), 'w') 1652406SN/A print >>f, tgt_dir, status_str 16610621SCurtis.Dunham@arm.com f.close() 16710024Sdam.sunwoo@arm.com # done 1689166Sandreas.hansson@arm.com return 0 1692641SN/A 1709166Sandreas.hansson@arm.comdef run_test_string(target, source, env): 1719166Sandreas.hansson@arm.com return env.subst("Running test in ${TARGETS[0].dir}.", 1729166Sandreas.hansson@arm.com target=target, source=source) 1732641SN/A 1749166Sandreas.hansson@arm.comtestAction = env.Action(run_test, run_test_string) 1752641SN/A 1769166Sandreas.hansson@arm.comdef print_test(target, source, env): 1779166Sandreas.hansson@arm.com # print the status with colours to make it easier to see what 1789166Sandreas.hansson@arm.com # passed and what failed 1792384SN/A line = contents(source[0]) 1809307Sandreas.hansson@arm.com 1819307Sandreas.hansson@arm.com # split the line to words and get the last one 1829307Sandreas.hansson@arm.com words = line.split() 1839307Sandreas.hansson@arm.com status = words[-1] 1849307Sandreas.hansson@arm.com 18510621SCurtis.Dunham@arm.com # if the test failed make it red, if it passed make it green, and 18610621SCurtis.Dunham@arm.com # skip the punctuation 1872384SN/A if status == "FAILED!": 1882384SN/A status = termcap.Red + status[:-1] + termcap.Normal + status[-1] 1894435SN/A elif status == "passed.": 1909166Sandreas.hansson@arm.com status = termcap.Green + status[:-1] + termcap.Normal + status[-1] 1914435SN/A 1929166Sandreas.hansson@arm.com # put it back in the list and join with space 1934435SN/A words[-1] = status 1949166Sandreas.hansson@arm.com line = " ".join(words) 1959166Sandreas.hansson@arm.com 1969166Sandreas.hansson@arm.com print '***** ' + line 1979307Sandreas.hansson@arm.com return 0 1989166Sandreas.hansson@arm.com 1999307Sandreas.hansson@arm.comprintAction = env.Action(print_test, strfunction = None) 2009307Sandreas.hansson@arm.com 2019307Sandreas.hansson@arm.com# Static vars for update_test: 2029307Sandreas.hansson@arm.com# - long-winded message about ignored sources 2039307Sandreas.hansson@arm.comignore_msg = ''' 2049307Sandreas.hansson@arm.comNote: The following file(s) will not be copied. New non-standard 2059307Sandreas.hansson@arm.com output files must be copied manually once before --update-ref will 2069307Sandreas.hansson@arm.com recognize them as outputs. Otherwise they are assumed to be 2079307Sandreas.hansson@arm.com inputs and are ignored. 2089307Sandreas.hansson@arm.com''' 2099307Sandreas.hansson@arm.com# - reference files always needed 2109307Sandreas.hansson@arm.comneeded_files = set(['simout', 'simerr', 'stats.txt', 'config.ini']) 2119307Sandreas.hansson@arm.com# - source files we always want to ignore 2129307Sandreas.hansson@arm.comknown_ignores = set(['status', 'outdiff', 'statsdiff']) 2139307Sandreas.hansson@arm.com 2149307Sandreas.hansson@arm.comdef update_test(target, source, env): 2159307Sandreas.hansson@arm.com """Update reference test outputs. 2169307Sandreas.hansson@arm.com 2179307Sandreas.hansson@arm.com Target is phony. First two sources are the ref & new stats.txt file 2189307Sandreas.hansson@arm.com files, respectively. We actually copy everything in the 2199307Sandreas.hansson@arm.com respective directories except the status & diff output files. 2209307Sandreas.hansson@arm.com 2219307Sandreas.hansson@arm.com """ 2229307Sandreas.hansson@arm.com dest_dir = str(source[0].get_dir()) 2239307Sandreas.hansson@arm.com src_dir = str(source[1].get_dir()) 2249307Sandreas.hansson@arm.com dest_files = set(os.listdir(dest_dir)) 2259307Sandreas.hansson@arm.com src_files = set(os.listdir(src_dir)) 2264435SN/A # Copy all of the required files plus any existing dest files. 2274435SN/A wanted_files = needed_files | dest_files 2282384SN/A missing_files = wanted_files - src_files 2294435SN/A if len(missing_files) > 0: 2302384SN/A print " WARNING: the following file(s) are missing " \ 2319166Sandreas.hansson@arm.com "and will not be updated:" 2322901SN/A print " ", " ,".join(missing_files) 2332901SN/A copy_files = wanted_files - missing_files 2344435SN/A warn_ignored_files = (src_files - copy_files) - known_ignores 2352902SN/A if len(warn_ignored_files) > 0: 2369524SAndreas.Sandberg@ARM.com print ignore_msg, 2379307Sandreas.hansson@arm.com print " ", ", ".join(warn_ignored_files) 2389307Sandreas.hansson@arm.com for f in copy_files: 2399307Sandreas.hansson@arm.com if f in dest_files: 2409307Sandreas.hansson@arm.com print " Replacing file", f 2414435SN/A dest_files.remove(f) 2424435SN/A else: 2434435SN/A print " Creating new file", f 2449307Sandreas.hansson@arm.com copyAction = Copy(os.path.join(dest_dir, f), os.path.join(src_dir, f)) 2459524SAndreas.Sandberg@ARM.com copyAction.strfunction = None 2469307Sandreas.hansson@arm.com env.Execute(copyAction) 2479307Sandreas.hansson@arm.com return 0 2489307Sandreas.hansson@arm.com 2499307Sandreas.hansson@arm.comdef update_test_string(target, source, env): 2504435SN/A return env.subst("Updating ${SOURCES[0].dir} from ${SOURCES[1].dir}", 2519307Sandreas.hansson@arm.com target=target, source=source) 2529307Sandreas.hansson@arm.com 2539307Sandreas.hansson@arm.comupdateAction = env.Action(update_test, update_test_string) 2544435SN/A 2559307Sandreas.hansson@arm.comdef test_builder(env, ref_dir): 2569307Sandreas.hansson@arm.com """Define a test.""" 2579166Sandreas.hansson@arm.com 2589166Sandreas.hansson@arm.com (category, mode, name, _ref, isa, opsys, config) = ref_dir.split('/') 259545SN/A assert(_ref == 'ref') 2608598SN/A 2619294Sandreas.hansson@arm.com # target path (where test output goes) is the same except without 2629294Sandreas.hansson@arm.com # the 'ref' component 2638598SN/A tgt_dir = os.path.join(category, mode, name, isa, opsys, config) 2648598SN/A 2658922SN/A # prepend file name with tgt_dir 2668598SN/A def tgt(f): 2678922SN/A return os.path.join(tgt_dir, f) 2688598SN/A 26911010Sandreas.sandberg@arm.com ref_stats = os.path.join(ref_dir, 'stats.txt') 27011010Sandreas.sandberg@arm.com new_stats = tgt('stats.txt') 27111010Sandreas.sandberg@arm.com status_file = tgt('status') 27211010Sandreas.sandberg@arm.com 27311010Sandreas.sandberg@arm.com env.Command([status_file], 27411010Sandreas.sandberg@arm.com [env.M5Binary, 'run.py', ref_stats], 27511010Sandreas.sandberg@arm.com testAction) 27611010Sandreas.sandberg@arm.com 27711010Sandreas.sandberg@arm.com # phony target to echo status 27811010Sandreas.sandberg@arm.com if GetOption('update_ref'): 27911010Sandreas.sandberg@arm.com p = env.Command(tgt('_update'), 28011010Sandreas.sandberg@arm.com [ref_stats, new_stats, status_file], 28111010Sandreas.sandberg@arm.com updateAction) 28211010Sandreas.sandberg@arm.com else: 28311010Sandreas.sandberg@arm.com p = env.Command(tgt('_print'), [status_file], printAction) 28411010Sandreas.sandberg@arm.com 28511010Sandreas.sandberg@arm.com env.AlwaysBuild(p) 28611010Sandreas.sandberg@arm.com 28711010Sandreas.sandberg@arm.com 28811010Sandreas.sandberg@arm.com# Figure out applicable configs based on build type 28911010Sandreas.sandberg@arm.comconfigs = [] 29011010Sandreas.sandberg@arm.comif env['TARGET_ISA'] == 'alpha': 29111010Sandreas.sandberg@arm.com configs += ['tsunami-simple-atomic', 29211010Sandreas.sandberg@arm.com 'tsunami-simple-timing', 29311010Sandreas.sandberg@arm.com 'tsunami-simple-atomic-dual', 29411010Sandreas.sandberg@arm.com 'tsunami-simple-timing-dual', 29511010Sandreas.sandberg@arm.com 'twosys-tsunami-simple-atomic', 29611010Sandreas.sandberg@arm.com 'tsunami-o3', 'tsunami-o3-dual', 29711010Sandreas.sandberg@arm.com 'tsunami-inorder'] 29811010Sandreas.sandberg@arm.comif env['TARGET_ISA'] == 'sparc': 29911010Sandreas.sandberg@arm.com configs += ['t1000-simple-atomic', 30011010Sandreas.sandberg@arm.com 't1000-simple-timing'] 30111010Sandreas.sandberg@arm.comif env['TARGET_ISA'] == 'arm': 30211010Sandreas.sandberg@arm.com configs += ['simple-atomic-dummychecker', 30311010Sandreas.sandberg@arm.com 'o3-timing-checker', 30411010Sandreas.sandberg@arm.com 'realview-simple-atomic', 30511010Sandreas.sandberg@arm.com 'realview-simple-atomic-dual', 30611010Sandreas.sandberg@arm.com 'realview-simple-timing', 30711010Sandreas.sandberg@arm.com 'realview-simple-timing-dual', 30811010Sandreas.sandberg@arm.com 'realview-o3', 30911010Sandreas.sandberg@arm.com 'realview-o3-checker', 31011010Sandreas.sandberg@arm.com 'realview-o3-dual'] 31111010Sandreas.sandberg@arm.comif env['TARGET_ISA'] == 'x86': 31211010Sandreas.sandberg@arm.com configs += ['pc-simple-atomic', 31311010Sandreas.sandberg@arm.com 'pc-simple-timing', 31411010Sandreas.sandberg@arm.com 'pc-o3-timing'] 31511010Sandreas.sandberg@arm.com 31611010Sandreas.sandberg@arm.comconfigs += ['simple-atomic', 'simple-timing', 'o3-timing', 'memtest', 31711010Sandreas.sandberg@arm.com 'simple-atomic-mp', 'simple-timing-mp', 'o3-timing-mp', 31811010Sandreas.sandberg@arm.com 'inorder-timing', 'rubytest', 'tgen-simple-mem'] 31911010Sandreas.sandberg@arm.com 32011010Sandreas.sandberg@arm.comif env['PROTOCOL'] != 'None': 32111010Sandreas.sandberg@arm.com if env['PROTOCOL'] == 'MI_example': 32211010Sandreas.sandberg@arm.com configs += [c + "-ruby" for c in configs] 32311010Sandreas.sandberg@arm.com else: 32411010Sandreas.sandberg@arm.com configs = [c + "-ruby-" + env['PROTOCOL'] for c in configs] 32511010Sandreas.sandberg@arm.com 32611010Sandreas.sandberg@arm.comcwd = os.getcwd() 32711010Sandreas.sandberg@arm.comos.chdir(str(Dir('.').srcdir)) 32811010Sandreas.sandberg@arm.comfor config in configs: 32911010Sandreas.sandberg@arm.com dirs = glob.glob('*/*/*/ref/%s/*/%s' % (env['TARGET_ISA'], config)) 33011010Sandreas.sandberg@arm.com for d in dirs: 33111010Sandreas.sandberg@arm.com if not os.path.exists(os.path.join(d, 'skip')): 33211010Sandreas.sandberg@arm.com test_builder(env, d) 33311010Sandreas.sandberg@arm.comos.chdir(cwd) 33411010Sandreas.sandberg@arm.com