1 # Copyright (c) 2017 Mark D. Hill and David A. Wood
4 # Redistribution and use in source and binary forms, with or without
5 # modification, are permitted provided that the following conditions are
6 # met: redistributions of source code must retain the above copyright
7 # notice, this list of conditions and the following disclaimer;
8 # redistributions in binary form must reproduce the above copyright
9 # notice, this list of conditions and the following disclaimer in the
10 # documentation and/or other materials provided with the distribution;
11 # neither the name of the copyright holders nor the names of its
12 # contributors may be used to endorse or promote products derived from
13 # this software without specific prior written permission.
15 # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
16 # "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
17 # LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
18 # A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
19 # OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
20 # SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
21 # LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
22 # DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
23 # THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
25 # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28 Built in test cases that verify particular details about a gem5 run.
32 from testlib
import test_util
33 from testlib
.configuration
import constants
34 from testlib
.helper
import joinpath
, diff_out_file
36 class Verifier(object):
37 def __init__(self
, fixtures
=tuple()):
38 self
.fixtures
= fixtures
40 def _test(self
, *args
, **kwargs
):
41 # Use a callback wrapper to make stack
42 # traces easier to understand.
43 self
.test(*args
, **kwargs
)
45 def instantiate_test(self
, name_pfx
):
46 name
= '-'.join([name_pfx
, self
.__class
__.__name
__])
47 return test_util
.TestFunction(self
._test
,
48 name
=name
, fixtures
=self
.fixtures
)
50 class MatchGoldStandard(Verifier
):
52 Compares a standard output to the test output and passes if they match,
55 def __init__(self
, standard_filename
, ignore_regex
=None,
56 test_filename
='simout'):
58 :param standard_filename: The path of the standard file to compare
61 :param ignore_regex: A string, compiled regex, or iterable containing
62 either which will be ignored in 'standard' and test output files when
65 super(MatchGoldStandard
, self
).__init
__()
66 self
.standard_filename
= standard_filename
67 self
.test_filename
= test_filename
69 self
.ignore_regex
= _iterable_regex(ignore_regex
)
71 def test(self
, params
):
72 # We need a tempdir fixture from our parent verifier suite.
73 fixtures
= params
.fixtures
74 # Get the file from the tempdir of the test.
75 tempdir
= fixtures
[constants
.tempdir_fixture_name
].path
76 self
.test_filename
= joinpath(tempdir
, self
.test_filename
)
78 diff
= diff_out_file(self
.standard_filename
,
80 ignore_regexes
=self
.ignore_regex
,
83 test_util
.fail('Stdout did not match:\n%s\nSee %s for full results'
86 def _generic_instance_warning(self
, kwargs
):
88 Method for helper classes to tell users to use this more generic class
89 if they are going to manually override the test_filename param.
91 if 'test_filename' in kwargs
:
92 raise ValueError('If you are setting test_filename use the more'
94 ' instead' % MatchGoldStandard
.__name
__)
96 class DerivedGoldStandard(MatchGoldStandard
):
97 __ignore_regex_sentinel
= object()
99 _default_ignore_regex
= []
101 def __init__(self
, standard_filename
,
102 ignore_regex
=__ignore_regex_sentinel
, **kwargs
):
104 if ignore_regex
== self
.__ignore
_regex
_sentinel
:
105 ignore_regex
= self
._default
_ignore
_regex
107 self
._generic
_instance
_warning
(kwargs
)
109 super(DerivedGoldStandard
, self
).__init
__(
111 test_filename
=self
._file
,
112 ignore_regex
=ignore_regex
,
115 class MatchStdout(DerivedGoldStandard
):
116 _file
= constants
.gem5_simulation_stdout
117 _default_ignore_regex
= [
118 re
.compile('^Redirecting (stdout|stderr) to'),
119 re
.compile('^gem5 version '),
120 re
.compile('^gem5 compiled '),
121 re
.compile('^gem5 started '),
122 re
.compile('^gem5 executing on '),
123 re
.compile('^command line:'),
124 re
.compile("^Couldn't import dot_parser,"),
125 re
.compile("^info: kernel located at:"),
126 re
.compile("^info: Standard input is not a terminal"),
127 re
.compile("^Couldn't unlink "),
128 re
.compile("^Using GPU kernel code file\(s\) "),
131 class MatchStdoutNoPerf(MatchStdout
):
132 _file
= constants
.gem5_simulation_stdout
133 _default_ignore_regex
= MatchStdout
._default
_ignore
_regex
+ [
134 re
.compile('^Exiting @ tick'),
137 class MatchStderr(DerivedGoldStandard
):
138 _file
= constants
.gem5_simulation_stderr
139 _default_ignore_regex
= []
141 class MatchStats(DerivedGoldStandard
):
142 # TODO: Likely will want to change this verifier since we have the weird
143 # perl script right now. A simple diff probably isn't going to work.
144 _file
= constants
.gem5_simulation_stats
145 _default_ignore_regex
= []
147 class MatchConfigINI(DerivedGoldStandard
):
148 _file
= constants
.gem5_simulation_config_ini
149 _default_ignore_regex
= (
150 re
.compile("^(executable|readfile|kernel|image_file)="),
151 re
.compile("^(cwd|input|codefile)="),
154 class MatchConfigJSON(DerivedGoldStandard
):
155 _file
= constants
.gem5_simulation_config_json
156 _default_ignore_regex
= (
157 re
.compile(r
'''^\s*"(executable|readfile|kernel|image_file)":'''),
158 re
.compile(r
'''^\s*"(cwd|input|codefile)":'''),
161 class MatchRegex(Verifier
):
162 def __init__(self
, regex
, match_stderr
=True, match_stdout
=True):
163 super(MatchRegex
, self
).__init
__()
164 self
.regex
= _iterable_regex(regex
)
165 self
.match_stderr
= match_stderr
166 self
.match_stdout
= match_stdout
168 def test(self
, params
):
169 fixtures
= params
.fixtures
170 # Get the file from the tempdir of the test.
171 tempdir
= fixtures
[constants
.tempdir_fixture_name
].path
173 def parse_file(fname
):
174 with
open(fname
, 'r') as file_
:
176 for regex
in self
.regex
:
177 if re
.match(regex
, line
):
179 if self
.match_stdout
:
180 if parse_file(joinpath(tempdir
,
181 constants
.gem5_simulation_stdout
)):
183 if self
.match_stderr
:
184 if parse_file(joinpath(tempdir
,
185 constants
.gem5_simulation_stderr
)):
187 test_util
.fail('Could not match regex.')
189 _re_type
= type(re
.compile(''))
190 def _iterable_regex(regex
):
191 if isinstance(regex
, _re_type
) or isinstance(regex
, str):