misc: Merge branch v20.1.0.3 hotfix into develop
[gem5.git] / tests / run.py
1 # Copyright (c) 2012 ARM Limited
2 # All rights reserved
3 #
4 # The license below extends only to copyright in the software and shall
5 # not be construed as granting a license to any other intellectual
6 # property including but not limited to intellectual property relating
7 # to a hardware implementation of the functionality of the software
8 # licensed hereunder. You may use the software subject to the license
9 # terms below provided that you ensure that this notice is replicated
10 # unmodified and in its entirety in all distributions of the software,
11 # modified or unmodified, in source code or in binary form.
12 #
13 # Copyright (c) 2006-2007 The Regents of The University of Michigan
14 # All rights reserved.
15 #
16 # Redistribution and use in source and binary forms, with or without
17 # modification, are permitted provided that the following conditions are
18 # met: redistributions of source code must retain the above copyright
19 # notice, this list of conditions and the following disclaimer;
20 # redistributions in binary form must reproduce the above copyright
21 # notice, this list of conditions and the following disclaimer in the
22 # documentation and/or other materials provided with the distribution;
23 # neither the name of the copyright holders nor the names of its
24 # contributors may be used to endorse or promote products derived from
25 # this software without specific prior written permission.
26 #
27 # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
28 # "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
29 # LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
30 # A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
31 # OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
32 # SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
33 # LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
34 # DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
35 # THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
36 # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
37 # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
38
39 import os
40 import sys
41 import re
42 import string
43
44 from os.path import join as joinpath
45 import os.path
46 import os
47
48 import m5
49
50 def skip_test(reason=""):
51 """Signal that a test should be skipped and optionally print why.
52
53 Keyword arguments:
54 reason -- Reason why the test failed. Output is omitted if empty.
55 """
56
57 if reason:
58 print("Skipping test: %s" % reason)
59 sys.exit(2)
60
61 def has_sim_object(name):
62 """Test if a SimObject exists in the simulator.
63
64 Arguments:
65 name -- Name of SimObject (string)
66
67 Returns: True if the object exists, False otherwise.
68 """
69
70 try:
71 cls = getattr(m5.objects, name)
72 return issubclass(cls, m5.objects.SimObject)
73 except AttributeError:
74 return False
75
76 def require_sim_object(name, fatal=False):
77 """Test if a SimObject exists and abort/skip test if not.
78
79 Arguments:
80 name -- Name of SimObject (string)
81
82 Keyword arguments:
83 fatal -- Set to True to indicate that the test should fail
84 instead of being skipped.
85 """
86
87 if has_sim_object(name):
88 return
89 else:
90 msg = "Test requires the '%s' SimObject." % name
91 if fatal:
92 m5.fatal(msg)
93 else:
94 skip_test(msg)
95
96
97 def require_file(path, fatal=False, mode=os.F_OK):
98 """Test if a file exists and abort/skip test if not.
99
100 Arguments:
101 path -- File to test for.
102
103 Keyword arguments:
104 fatal -- Set to True to indicate that the test should fail
105 instead of being skipped.
106 modes -- Mode to test for, default to existence. See the
107 Python documentation for os.access().
108 """
109
110 if os.access(path, mode):
111 return
112 else:
113 msg = "Test requires '%s'" % path
114 if not os.path.exists(path):
115 msg += " which does not exist."
116 else:
117 msg += " which has incorrect permissions."
118
119 if fatal:
120 m5.fatal(msg)
121 else:
122 skip_test(msg)
123
124 def require_kvm(kvm_dev="/dev/kvm", fatal=False):
125 """Test if KVM is available.
126
127 Keyword arguments:
128 kvm_dev -- Device to test (normally /dev/kvm)
129 fatal -- Set to True to indicate that the test should fail
130 instead of being skipped.
131 """
132
133 require_sim_object("BaseKvmCPU", fatal=fatal)
134 require_file(kvm_dev, fatal=fatal, mode=os.R_OK | os.W_OK)
135
136 def run_test(root):
137 """Default run_test implementations. Scripts can override it."""
138
139 # instantiate configuration
140 m5.instantiate()
141
142 # simulate until program terminates
143 exit_event = m5.simulate(maxtick)
144 print('Exiting @ tick', m5.curTick(), 'because', exit_event.getCause())
145
146 # Since we're in batch mode, dont allow tcp socket connections
147 m5.disableAllListeners()
148
149 # single "path" arg encodes everything we need to know about test
150 (category, mode, name, isa, opsys, config) = sys.argv[1].split('/')[-6:]
151
152 # find path to directory containing this file
153 tests_root = os.path.dirname(__file__)
154 test_progs = os.environ.get('M5_TEST_PROGS', '/dist/m5/regression/test-progs')
155 if not os.path.isdir(test_progs):
156 test_progs = joinpath(tests_root, 'test-progs')
157
158 # generate path to binary file
159 def binpath(app, file=None):
160 # executable has same name as app unless specified otherwise
161 if not file:
162 file = app
163 return joinpath(test_progs, app, 'bin', isa, opsys, file)
164
165 # generate path to input file
166 def inputpath(app, file=None):
167 # input file has same name as app unless specified otherwise
168 if not file:
169 file = app
170 return joinpath(test_progs, app, 'input', file)
171
172 def srcpath(path):
173 """Path to file in gem5's source tree"""
174 return joinpath(os.path.dirname(__file__), "..", path)
175
176 def run_config(config, argv=None):
177 """Execute a configuration script that is external to the test system"""
178
179 src_root = os.path.abspath(os.path.join(os.path.dirname(__file__), "../"))
180 abs_path = joinpath(src_root, config)
181
182 code = compile(open(abs_path, 'r').read(), abs_path, 'exec')
183 scope = {
184 '__file__' : config,
185 '__name__' : '__m5_main__',
186 }
187
188 # Set the working directory in case we are executing from
189 # outside gem5's source tree
190 os.chdir(src_root)
191
192 # gem5 normally adds the script's directory to the path to make
193 # script-relative imports work.
194 sys.path = [ os.path.dirname(abs_path), ] + sys.path
195
196 if argv is None:
197 sys.argv = [ config, ]
198 else:
199 sys.argv = argv
200 exec(code, scope)
201
202 # build configuration
203 sys.path.append(joinpath(tests_root, 'configs'))
204 test_filename = config
205 # for ruby configurations, remove the protocol name from the test filename
206 if re.search('-ruby', test_filename):
207 test_filename = test_filename.split('-ruby')[0]+'-ruby'
208 exec(compile( \
209 open(joinpath(tests_root, 'configs', test_filename + '.py')).read(), \
210 joinpath(tests_root, 'configs', test_filename + '.py'), 'exec'))
211
212 # set default maxtick... script can override
213 # -1 means run forever
214 maxtick = m5.MaxTick
215
216 # tweak configuration for specific test
217 sys.path.append(joinpath(tests_root, category, mode, name))
218 exec(compile( \
219 open(joinpath(tests_root, category, mode, name, 'test.py')).read(), \
220 joinpath(tests_root, category, mode, name, 'test.py'), 'exec'))
221
222 # Initialize all CPUs in a system
223 def initCPUs(sys):
224 def initCPU(cpu):
225 # We might actually have a MemTest object or something similar
226 # here that just pretends to be a CPU.
227 try:
228 cpu.createThreads()
229 except:
230 pass
231
232 # The CPU attribute doesn't exist in some cases, e.g. the Ruby
233 # testers.
234 if not hasattr(sys, "cpu"):
235 return
236
237 # The CPU can either be a list of CPUs or a single object.
238 if isinstance(sys.cpu, list):
239 [ initCPU(cpu) for cpu in sys.cpu ]
240 else:
241 initCPU(sys.cpu)
242
243 # We might be creating a single system or a dual system. Try
244 # initializing the CPUs in all known system attributes.
245 for sysattr in [ "system", "testsys", "drivesys" ]:
246 if hasattr(root, sysattr):
247 initCPUs(getattr(root, sysattr))
248
249 run_test(root)