Jim Stichnoth | dc7c597 | 2015-03-10 11:17:15 -0700 | [diff] [blame] | 1 | #!/usr/bin/env python2 |
| 2 | |
| 3 | import argparse |
| 4 | import ConfigParser |
| 5 | import os |
| 6 | import shutil |
| 7 | import sys |
| 8 | |
| 9 | from utils import shellcmd |
| 10 | from utils import FindBaseNaCl |
| 11 | |
| 12 | def Match(desc, includes, excludes, default_match): |
| 13 | """Determines whether desc is a match against includes and excludes. |
| 14 | |
| 15 | 'desc' is a set of attributes, and 'includes' and 'excludes' are lists of sets |
| 16 | of attributes. |
| 17 | |
| 18 | If 'desc' matches any element from 'excludes', the result is False. |
| 19 | Otherwise, if 'desc' matches any element from 'includes', the result is True. |
| 20 | Otherwise, the 'default_match' value is returned. |
| 21 | """ |
| 22 | for exclude in excludes: |
Jim Stichnoth | 833f13f | 2015-03-18 08:59:23 -0700 | [diff] [blame] | 23 | if exclude <= desc: |
Jim Stichnoth | dc7c597 | 2015-03-10 11:17:15 -0700 | [diff] [blame] | 24 | return False |
| 25 | for include in includes: |
Jim Stichnoth | 833f13f | 2015-03-18 08:59:23 -0700 | [diff] [blame] | 26 | if include <= desc: |
Jim Stichnoth | dc7c597 | 2015-03-10 11:17:15 -0700 | [diff] [blame] | 27 | return True |
| 28 | return default_match |
| 29 | |
Jan Voung | 8e32fed | 2015-06-17 10:16:23 -0700 | [diff] [blame] | 30 | |
| 31 | def RunNativePrefix(toolchain_root, target, run_cmd): |
| 32 | """Returns a prefix for running an executable for the target. |
| 33 | |
| 34 | For example, we may be running an ARM or MIPS target executable on an |
| 35 | x86 machine and need to use an emulator. |
| 36 | """ |
| 37 | arch_map = { 'x8632' : '', |
| 38 | 'x8664' : '', |
| 39 | 'arm32' : os.path.join(toolchain_root, 'arm_trusted', |
| 40 | 'run_under_qemu_arm'), |
| 41 | } |
| 42 | prefix = arch_map[target] |
| 43 | return (prefix + ' ' + run_cmd) if prefix else run_cmd |
| 44 | |
| 45 | |
Jim Stichnoth | dc7c597 | 2015-03-10 11:17:15 -0700 | [diff] [blame] | 46 | def main(): |
| 47 | """Framework for cross test generation and execution. |
| 48 | |
| 49 | Builds and executes cross tests from the space of all possible attribute |
| 50 | combinations. The space can be restricted by providing subsets of attributes |
| 51 | to specifically include or exclude. |
| 52 | """ |
| 53 | # pypath is where to find other Subzero python scripts. |
| 54 | pypath = os.path.abspath(os.path.dirname(sys.argv[0])) |
| 55 | root = FindBaseNaCl() |
| 56 | |
| 57 | # The rest of the attribute sets. |
Jan Voung | 8e32fed | 2015-06-17 10:16:23 -0700 | [diff] [blame] | 58 | targets = [ 'x8632', 'arm32' ] |
Jim Stichnoth | dc7c597 | 2015-03-10 11:17:15 -0700 | [diff] [blame] | 59 | sandboxing = [ 'native', 'sandbox' ] |
| 60 | opt_levels = [ 'Om1', 'O2' ] |
Jan Voung | 8e32fed | 2015-06-17 10:16:23 -0700 | [diff] [blame] | 61 | arch_attrs = { 'x8632': [ 'sse2', 'sse4.1' ], |
| 62 | 'arm32': [ 'neon', 'hwdiv-arm' ] } |
| 63 | flat_attrs = [] |
| 64 | for v in arch_attrs.values(): |
| 65 | flat_attrs += v |
| 66 | arch_flags = { 'x8632': [], |
| 67 | # ARM doesn't have an integrated assembler yet. |
| 68 | 'arm32': ['--filetype=asm'] } |
Jim Stichnoth | dc7c597 | 2015-03-10 11:17:15 -0700 | [diff] [blame] | 69 | # all_keys is only used in the help text. |
| 70 | all_keys = '; '.join([' '.join(targets), ' '.join(sandboxing), |
Jan Voung | 8e32fed | 2015-06-17 10:16:23 -0700 | [diff] [blame] | 71 | ' '.join(opt_levels), ' '.join(flat_attrs)]) |
Jim Stichnoth | dc7c597 | 2015-03-10 11:17:15 -0700 | [diff] [blame] | 72 | |
| 73 | argparser = argparse.ArgumentParser( |
| 74 | description=' ' + main.__doc__ + |
| 75 | 'The set of attributes is the set of tests plus the following:\n' + |
| 76 | all_keys, formatter_class=argparse.RawTextHelpFormatter) |
| 77 | argparser.add_argument('--config', default='crosstest.cfg', dest='config', |
| 78 | metavar='FILE', help='Test configuration file') |
| 79 | argparser.add_argument('--print-tests', default=False, action='store_true', |
| 80 | help='Print the set of test names and exit') |
| 81 | argparser.add_argument('--include', '-i', default=[], dest='include', |
| 82 | action='append', metavar='ATTR_LIST', |
| 83 | help='Attributes to include (comma-separated). ' + |
| 84 | 'Can be used multiple times.') |
| 85 | argparser.add_argument('--exclude', '-e', default=[], dest='exclude', |
| 86 | action='append', metavar='ATTR_LIST', |
| 87 | help='Attributes to include (comma-separated). ' + |
| 88 | 'Can be used multiple times.') |
| 89 | argparser.add_argument('--verbose', '-v', default=False, action='store_true', |
| 90 | help='Use verbose output') |
| 91 | argparser.add_argument('--defer', default=False, action='store_true', |
| 92 | help='Defer execution until all executables are built') |
| 93 | argparser.add_argument('--no-compile', '-n', default=False, |
| 94 | action='store_true', |
| 95 | help="Don't build; reuse binaries from the last run") |
| 96 | argparser.add_argument('--dir', dest='dir', metavar='DIRECTORY', |
| 97 | default=('{root}/toolchain_build/src/subzero/' + |
| 98 | 'crosstest/Output').format(root=root), |
| 99 | help='Output directory') |
| 100 | argparser.add_argument('--lit', default=False, action='store_true', |
| 101 | help='Generate files for lit testing') |
Jan Voung | 8e32fed | 2015-06-17 10:16:23 -0700 | [diff] [blame] | 102 | argparser.add_argument('--toolchain-root', dest='toolchain_root', |
| 103 | help='Path to toolchain binaries.') |
Jim Stichnoth | dc7c597 | 2015-03-10 11:17:15 -0700 | [diff] [blame] | 104 | args = argparser.parse_args() |
| 105 | |
| 106 | # Run from the crosstest directory to make it easy to grab inputs. |
| 107 | crosstest_dir = '{root}/toolchain_build/src/subzero/crosstest'.format( |
| 108 | root=root) |
| 109 | os.chdir(crosstest_dir) |
| 110 | |
| 111 | tests = ConfigParser.RawConfigParser() |
| 112 | tests.read('crosstest.cfg') |
| 113 | |
| 114 | if args.print_tests: |
| 115 | print 'Test name attributes: ' + ' '.join(sorted(tests.sections())) |
| 116 | sys.exit(0) |
| 117 | |
| 118 | # includes and excludes are both lists of sets. |
| 119 | includes = [ set(item.split(',')) for item in args.include ] |
| 120 | excludes = [ set(item.split(',')) for item in args.exclude ] |
| 121 | # If any --include args are provided, the default is to not match. |
| 122 | default_match = not args.include |
| 123 | |
| 124 | # Delete and recreate the output directory, unless --no-compile was specified. |
| 125 | if not args.no_compile: |
| 126 | if os.path.exists(args.dir): |
| 127 | if os.path.isdir(args.dir): |
| 128 | shutil.rmtree(args.dir) |
| 129 | else: |
| 130 | os.remove(args.dir) |
| 131 | if not os.path.exists(args.dir): |
| 132 | os.makedirs(args.dir) |
| 133 | |
| 134 | # If --defer is specified, collect the run commands into deferred_cmds for |
| 135 | # later execution. |
| 136 | deferred_cmds = [] |
| 137 | for test in sorted(tests.sections()): |
| 138 | for target in targets: |
| 139 | for sb in sandboxing: |
| 140 | for opt in opt_levels: |
Jan Voung | 8e32fed | 2015-06-17 10:16:23 -0700 | [diff] [blame] | 141 | for attr in arch_attrs[target]: |
Jim Stichnoth | dc7c597 | 2015-03-10 11:17:15 -0700 | [diff] [blame] | 142 | desc = [ test, target, sb, opt, attr ] |
| 143 | if Match(set(desc), includes, excludes, default_match): |
| 144 | exe = '{test}_{target}_{sb}_{opt}_{attr}'.format( |
| 145 | test=test, target=target, sb=sb, opt=opt, |
| 146 | attr=attr) |
| 147 | extra = (tests.get(test, 'flags').split(' ') |
| 148 | if tests.has_option(test, 'flags') else []) |
| 149 | # Generate the compile command. |
Jan Voung | 8e32fed | 2015-06-17 10:16:23 -0700 | [diff] [blame] | 150 | cmp_cmd = ( |
| 151 | ['{path}/crosstest.py'.format(path=pypath), |
| 152 | '-{opt}'.format(opt=opt), |
| 153 | '--mattr={attr}'.format(attr=attr), |
| 154 | '--prefix=Subzero_', |
| 155 | '--target={target}'.format(target=target), |
| 156 | '--sandbox={sb}'.format(sb='1' if sb=='sandbox' else '0'), |
| 157 | '--dir={dir}'.format(dir=args.dir), |
| 158 | '--output={exe}'.format(exe=exe), |
| 159 | '--driver={drv}'.format(drv=tests.get(test, 'driver'))] + |
| 160 | extra + |
| 161 | ['--test=' + t |
| 162 | for t in tests.get(test, 'test').split(' ')] + |
| 163 | arch_flags[target]) |
Jim Stichnoth | dc7c597 | 2015-03-10 11:17:15 -0700 | [diff] [blame] | 164 | run_cmd_base = os.path.join(args.dir, exe) |
| 165 | # Generate the run command. |
| 166 | run_cmd = run_cmd_base |
| 167 | if sb == 'sandbox': |
| 168 | run_cmd = '{root}/run.py -q '.format(root=root) + run_cmd |
Jan Voung | 8e32fed | 2015-06-17 10:16:23 -0700 | [diff] [blame] | 169 | else: |
| 170 | run_cmd = RunNativePrefix(args.toolchain_root, target, run_cmd) |
Jim Stichnoth | dc7c597 | 2015-03-10 11:17:15 -0700 | [diff] [blame] | 171 | if args.lit: |
| 172 | # Create a file to drive the lit test. |
| 173 | with open(run_cmd_base + '.xtest', 'w') as f: |
| 174 | f.write('# RUN: sh %s | FileCheck %s\n') |
| 175 | f.write('cd ' + crosstest_dir + ' && \\\n') |
| 176 | f.write(' '.join(cmp_cmd) + ' && \\\n') |
| 177 | f.write(run_cmd + '\n') |
| 178 | f.write('echo Recreate a failure using ' + __file__ + |
Jim Stichnoth | a9eeb42 | 2015-06-17 22:16:57 -0700 | [diff] [blame] | 179 | ' --toolchain-root=' + args.toolchain_root + |
Jim Stichnoth | dc7c597 | 2015-03-10 11:17:15 -0700 | [diff] [blame] | 180 | ' --include=' + ','.join(desc) + '\n') |
| 181 | f.write('# CHECK: Failures=0\n') |
| 182 | else: |
| 183 | if not args.no_compile: |
| 184 | shellcmd(cmp_cmd, |
| 185 | echo=args.verbose) |
| 186 | if (args.defer): |
| 187 | deferred_cmds.append(run_cmd) |
| 188 | else: |
| 189 | shellcmd(run_cmd, echo=True) |
| 190 | for run_cmd in deferred_cmds: |
| 191 | shellcmd(run_cmd, echo=True) |
| 192 | |
| 193 | if __name__ == '__main__': |
| 194 | main() |