1 # Copyright (c) 2012 ARM Limited
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.
13 # Copyright (c) 2005 The Regents of The University of Michigan
14 # Copyright (c) 2010 Advanced Micro Devices, Inc.
15 # All rights reserved.
17 # Redistribution and use in source and binary forms, with or without
18 # modification, are permitted provided that the following conditions are
19 # met: redistributions of source code must retain the above copyright
20 # notice, this list of conditions and the following disclaimer;
21 # redistributions in binary form must reproduce the above copyright
22 # notice, this list of conditions and the following disclaimer in the
23 # documentation and/or other materials provided with the distribution;
24 # neither the name of the copyright holders nor the names of its
25 # contributors may be used to endorse or promote products derived from
26 # this software without specific prior written permission.
28 # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
29 # "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
30 # LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
31 # A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
32 # OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
33 # SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
34 # LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
35 # DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
36 # THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
37 # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
38 # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
40 # Authors: Nathan Binkert
47 # import the wrapped C++ functions
50 from _m5
.stats
import updateEvents
as updateStatEvents
56 from m5
.util
.dot_writer
import do_dot
, do_dvfs_dot
58 from util
import fatal
59 from util
import attrdict
61 # define a MaxTick parameter, unsigned 64 bit
65 "atomic" : objects
.params
.atomic
,
66 "timing" : objects
.params
.timing
,
67 "atomic_noncaching" : objects
.params
.atomic_noncaching
,
70 _drain_manager
= _m5
.drain
.DrainManager
.instance()
72 # The final hook to generate .ini files. Called from the user script
73 # once the config is built.
74 def instantiate(ckpt_dir
=None):
75 from m5
import options
77 root
= objects
.Root
.getInstance()
80 fatal("Need to instantiate Root() before calling instantiate()")
82 # we need to fix the global frequency
83 ticks
.fixGlobalFrequency()
85 # Make sure SimObject-valued params are in the configuration
86 # hierarchy so we catch them with future descendants() walks
87 for obj
in root
.descendants(): obj
.adoptOrphanParams()
89 # Unproxy in sorted order for determinism
90 for obj
in root
.descendants(): obj
.unproxyParams()
92 if options
.dump_config
:
93 ini_file
= file(os
.path
.join(options
.outdir
, options
.dump_config
), 'w')
94 # Print ini sections in sorted order for easier diffing
95 for obj
in sorted(root
.descendants(), key
=lambda o
: o
.path()):
96 obj
.print_ini(ini_file
)
99 if options
.json_config
:
102 json_file
= file(os
.path
.join(options
.outdir
, options
.json_config
), 'w')
103 d
= root
.get_config_as_dict()
104 json
.dump(d
, json_file
, indent
=4)
109 do_dot(root
, options
.outdir
, options
.dot_config
)
111 # Initialize the global statistics
114 # Create the C++ sim objects and connect ports
115 for obj
in root
.descendants(): obj
.createCCObject()
116 for obj
in root
.descendants(): obj
.connectPorts()
118 # Do a second pass to finish initializing the sim objects
119 for obj
in root
.descendants(): obj
.init()
121 # Do a third pass to initialize statistics
122 for obj
in root
.descendants(): obj
.regStats()
124 # Do a fourth pass to initialize probe points
125 for obj
in root
.descendants(): obj
.regProbePoints()
127 # Do a fifth pass to connect probe listeners
128 for obj
in root
.descendants(): obj
.regProbeListeners()
130 # We want to generate the DVFS diagram for the system. This can only be
131 # done once all of the CPP objects have been created and initialised so
132 # that we are able to figure out which object belongs to which domain.
133 if options
.dot_dvfs_config
:
134 do_dvfs_dot(root
, options
.outdir
, options
.dot_dvfs_config
)
136 # We're done registering statistics. Enable the stats package now.
139 # Restore checkpoint (if any)
141 _drain_manager
.preCheckpointRestore()
142 ckpt
= _m5
.core
.getCheckpoint(ckpt_dir
)
143 _m5
.core
.unserializeGlobals(ckpt
);
144 for obj
in root
.descendants(): obj
.loadState(ckpt
)
146 for obj
in root
.descendants(): obj
.initState()
148 # Check to see if any of the stat events are in the past after resuming from
149 # a checkpoint, If so, this call will shift them to be at a valid time.
153 def simulate(*args
, **kwargs
):
157 root
= objects
.Root
.getInstance()
158 for obj
in root
.descendants(): obj
.startup()
161 # Python exit handlers happen in reverse order.
162 # We want to dump stats last.
163 atexit
.register(stats
.dump
)
165 # register our C++ exit callback function with Python
166 atexit
.register(_m5
.core
.doExitCleanup
)
168 # Reset to put the stats in a consistent state.
171 if _drain_manager
.isDrained():
172 _drain_manager
.resume()
174 return _m5
.event
.simulate(*args
, **kwargs
)
177 """Drain the simulator in preparation of a checkpoint or memory mode
180 This operation is a no-op if the simulator is already in the
185 # Try to drain all objects. Draining might not be completed unless
186 # all objects return that they are drained on the first call. This
187 # is because as objects drain they may cause other objects to no
190 # Try to drain the system. The drain is successful if all
191 # objects are done without simulation. We need to simulate
193 if _drain_manager
.tryDrain():
196 # WARNING: if a valid exit event occurs while draining, it
197 # will not get returned to the user script
198 exit_event
= _m5
.event
.simulate()
199 while exit_event
.getCause() != 'Finished drain':
200 exit_event
= simulate()
204 # Don't try to drain a system that is already drained
205 is_drained
= _drain_manager
.isDrained()
206 while not is_drained
:
207 is_drained
= _drain()
209 assert _drain_manager
.isDrained(), "Drain state inconsistent"
211 def memWriteback(root
):
212 for obj
in root
.descendants():
215 def memInvalidate(root
):
216 for obj
in root
.descendants():
220 root
= objects
.Root
.getInstance()
221 if not isinstance(root
, objects
.Root
):
222 raise TypeError, "Checkpoint must be called on a root object."
226 print "Writing checkpoint"
227 _m5
.core
.serializeAll(dir)
229 def _changeMemoryMode(system
, mode
):
230 if not isinstance(system
, (objects
.Root
, objects
.System
)):
231 raise TypeError, "Parameter of type '%s'. Must be type %s or %s." % \
232 (type(system
), objects
.Root
, objects
.System
)
233 if system
.getMemoryMode() != mode
:
234 system
.setMemoryMode(mode
)
236 print "System already in target mode. Memory mode unchanged."
238 def switchCpus(system
, cpuList
, verbose
=True):
239 """Switch CPUs in a system.
241 Note: This method may switch the memory mode of the system if that
242 is required by the CPUs. It may also flush all caches in the
246 system -- Simulated system.
247 cpuList -- (old_cpu, new_cpu) tuples
251 print "switching cpus"
253 if not isinstance(cpuList
, list):
254 raise RuntimeError, "Must pass a list to this function"
256 if not isinstance(item
, tuple) or len(item
) != 2:
257 raise RuntimeError, "List must have tuples of (oldCPU,newCPU)"
259 old_cpus
= [old_cpu
for old_cpu
, new_cpu
in cpuList
]
260 new_cpus
= [new_cpu
for old_cpu
, new_cpu
in cpuList
]
261 old_cpu_set
= set(old_cpus
)
262 memory_mode_name
= new_cpus
[0].memory_mode()
263 for old_cpu
, new_cpu
in cpuList
:
264 if not isinstance(old_cpu
, objects
.BaseCPU
):
265 raise TypeError, "%s is not of type BaseCPU" % old_cpu
266 if not isinstance(new_cpu
, objects
.BaseCPU
):
267 raise TypeError, "%s is not of type BaseCPU" % new_cpu
268 if new_cpu
in old_cpu_set
:
269 raise RuntimeError, \
270 "New CPU (%s) is in the list of old CPUs." % (old_cpu
,)
271 if not new_cpu
.switchedOut():
272 raise RuntimeError, \
273 "New CPU (%s) is already active." % (new_cpu
,)
274 if not new_cpu
.support_take_over():
275 raise RuntimeError, \
276 "New CPU (%s) does not support CPU handover." % (old_cpu
,)
277 if new_cpu
.memory_mode() != memory_mode_name
:
278 raise RuntimeError, \
279 "%s and %s require different memory modes." % (new_cpu
,
281 if old_cpu
.switchedOut():
282 raise RuntimeError, \
283 "Old CPU (%s) is inactive." % (new_cpu
,)
284 if not old_cpu
.support_take_over():
285 raise RuntimeError, \
286 "Old CPU (%s) does not support CPU handover." % (old_cpu
,)
289 memory_mode
= _memory_modes
[memory_mode_name
]
291 raise RuntimeError, "Invalid memory mode (%s)" % memory_mode_name
295 # Now all of the CPUs are ready to be switched out
296 for old_cpu
, new_cpu
in cpuList
:
299 # Change the memory mode if required. We check if this is needed
300 # to avoid printing a warning if no switch was performed.
301 if system
.getMemoryMode() != memory_mode
:
302 # Flush the memory system if we are switching to a memory mode
303 # that disables caches. This typically happens when switching to a
304 # hardware virtualized CPU.
305 if memory_mode
== objects
.params
.atomic_noncaching
:
307 memInvalidate(system
)
309 _changeMemoryMode(system
, memory_mode
)
311 for old_cpu
, new_cpu
in cpuList
:
312 new_cpu
.takeOverFrom(old_cpu
)
314 def notifyFork(root
):
315 for obj
in root
.descendants():
319 def fork(simout
="%(parent)s.f%(fork_seq)i"):
320 """Fork the simulator.
322 This function forks the simulator. After forking the simulator,
323 the child process gets its output files redirected to a new output
324 directory. The default name of the output directory is the same as
325 the parent with the suffix ".fN" added where N is the fork
326 sequence number. The name of the output directory can be
327 overridden using the simout keyword argument.
329 Output file formatting dictionary:
330 parent -- Path to the parent process's output directory.
331 fork_seq -- Fork sequence number.
332 pid -- PID of the child process.
335 simout -- New simulation output directory.
338 pid of the child process or 0 if running in the child.
340 from m5
import options
343 if not _m5
.core
.listenersDisabled():
344 raise RuntimeError, "Can not fork a simulator with listeners enabled"
354 # In child, notify objects of the fork
355 root
= objects
.Root
.getInstance()
357 # Setup a new output directory
358 parent
= options
.outdir
359 options
.outdir
= simout
% {
361 "fork_seq" : fork_count
,
364 _m5
.core
.setOutputDir(options
.outdir
)
370 from _m5
.core
import disableAllListeners
, listenersDisabled
371 from _m5
.core
import listenersLoopbackOnly
372 from _m5
.core
import curTick