cface476189712198df1c59de7d140aee8d0b770
3 # Copyright 2018 Google, Inc.
5 # Redistribution and use in source and binary forms, with or without
6 # modification, are permitted provided that the following conditions are
7 # met: redistributions of source code must retain the above copyright
8 # notice, this list of conditions and the following disclaimer;
9 # redistributions in binary form must reproduce the above copyright
10 # notice, this list of conditions and the following disclaimer in the
11 # documentation and/or other materials provided with the distribution;
12 # neither the name of the copyright holders nor the names of its
13 # contributors may be used to endorse or promote products derived from
14 # this software without specific prior written permission.
16 # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
17 # "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
18 # LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
19 # A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
20 # OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
21 # SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
22 # LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23 # DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24 # THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25 # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
26 # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30 from __future__
import print_function
38 import multiprocessing
.pool
43 script_path
= os
.path
.abspath(inspect
.getfile(inspect
.currentframe()))
44 script_dir
= os
.path
.dirname(script_path
)
45 config_path
= os
.path
.join(script_dir
, 'config.py')
47 systemc_rel_path
= 'systemc'
48 tests_rel_path
= os
.path
.join(systemc_rel_path
, 'tests')
49 json_rel_path
= os
.path
.join(tests_rel_path
, 'tests.json')
53 logging
.basicConfig(level
=logging
.INFO
)
56 args
= ['scons'] + list(args
)
57 subprocess
.check_call(args
)
62 def __init__(self
, target
, suffix
, build_dir
, props
):
65 self
.build_dir
= build_dir
67 for key
, val
in props
.iteritems():
68 setattr(self
, key
, val
)
71 return os
.path
.join(self
.build_dir
, tests_rel_path
, self
.path
)
74 return os
.path
.join(script_dir
, self
.path
)
77 return os
.path
.join(self
.src_dir(), 'golden')
80 return '.'.join([self
.name
, self
.suffix
])
83 return os
.path
.join(self
.dir(), self
.bin())
86 return os
.path
.join(self
.dir(), 'm5out.' + self
.suffix
)
90 test_phase_classes
= {}
92 class TestPhaseMeta(type):
93 def __init__(cls
, name
, bases
, d
):
94 if not d
.pop('abstract', False):
95 test_phase_classes
[d
['name']] = cls
97 super(TestPhaseMeta
, cls
).__init
__(name
, bases
, d
)
99 class TestPhaseBase(object):
100 __metaclass__
= TestPhaseMeta
103 def __init__(self
, main_args
, *args
):
104 self
.main_args
= main_args
107 def __lt__(self
, other
):
108 return self
.number
< other
.number
110 class CompilePhase(TestPhaseBase
):
114 def run(self
, tests
):
115 targets
= list([test
.full_path() for test
in tests
])
116 scons_args
= list(self
.args
) + targets
119 class RunPhase(TestPhaseBase
):
123 def run(self
, tests
):
124 parser
= argparse
.ArgumentParser()
125 parser
.add_argument('--timeout', type=int, metavar
='SECONDS',
126 help='Time limit for each run in seconds.',
128 parser
.add_argument('-j', type=int, default
=1,
129 help='How many tests to run in parallel.')
130 args
= parser
.parse_args(self
.args
)
134 '--kill-after', str(args
.timeout
* 2),
140 cmd
.extend(timeout_cmd
)
143 '-red', test
.m5out_dir(),
144 '--listener-mode=off',
147 subprocess
.check_call(cmd
)
149 runnable
= filter(lambda t
: not t
.compile_only
, tests
)
151 map(run_test
, runnable
)
153 tp
= multiprocessing
.pool
.ThreadPool(args
.j
)
154 map(lambda t
: tp
.apply_async(run_test
, (t
,)), runnable
)
158 class VerifyPhase(TestPhaseBase
):
162 def run(self
, tests
):
164 if test
.compile_only
:
166 logging
.info("Would verify %s", test
.m5out_dir())
170 parser
= argparse
.ArgumentParser(description
='SystemC test utility')
172 parser
.add_argument('build_dir', metavar
='BUILD_DIR',
173 help='The build directory (ie. build/ARM).')
175 parser
.add_argument('--update-json', action
='store_true',
176 help='Update the json manifest of tests.')
178 parser
.add_argument('--flavor', choices
=['debug', 'opt', 'fast'],
180 help='Flavor of binary to test.')
182 parser
.add_argument('--list', action
='store_true',
183 help='List the available tests')
185 filter_opts
= parser
.add_mutually_exclusive_group()
186 filter_opts
.add_argument('--filter', default
='True',
187 help='Python expression which filters tests based '
188 'on their properties')
189 filter_opts
.add_argument('--filter-file', default
=None,
190 type=argparse
.FileType('r'),
191 help='Same as --filter, but read from a file')
193 def collect_phases(args
):
194 phase_groups
= [list(g
) for k
, g
in
195 itertools
.groupby(args
, lambda x
: x
!= '--phase') if k
]
196 main_args
= parser
.parse_args(phase_groups
[0][1:])
199 for group
in phase_groups
[1:]:
202 raise RuntimeException('Phase %s specified more than once' % name
)
203 phase
= test_phase_classes
[name
]
204 phases
.append(phase(main_args
, *group
[1:]))
206 return main_args
, phases
208 main_args
, phases
= collect_phases(sys
.argv
)
212 CompilePhase(main_args
),
214 VerifyPhase(main_args
)
219 json_path
= os
.path
.join(main_args
.build_dir
, json_rel_path
)
221 if main_args
.update_json
:
222 scons(os
.path
.join(json_path
))
224 with
open(json_path
) as f
:
225 test_data
= json
.load(f
)
227 if main_args
.filter_file
:
228 f
= main_args
.filter_file
229 filt
= compile(f
.read(), f
.name
, 'eval')
231 filt
= compile(main_args
.filter, '<string>', 'eval')
234 target
: props
for (target
, props
) in
235 test_data
.iteritems() if eval(filt
, dict(props
))
239 for target
, props
in sorted(filtered_tests
.iteritems()):
240 print('%s.%s' % (target
, main_args
.flavor
))
241 for key
, val
in props
.iteritems():
242 print(' %s: %s' % (key
, val
))
243 print('Total tests: %d' % len(filtered_tests
))
245 tests_to_run
= list([
246 Test(target
, main_args
.flavor
, main_args
.build_dir
, props
) for
247 target
, props
in sorted(filtered_tests
.iteritems())
251 phase
.run(tests_to_run
)