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) 2005 The Regents of The University of Michigan 14# Copyright (c) 2010 Advanced Micro Devices, Inc. 15# All rights reserved. 16# 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. 27# 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. 39# 40# Authors: Nathan Binkert 41# Steve Reinhardt 42 43import atexit 44import os 45import sys 46 47# import the SWIG-wrapped main C++ functions
|
48import internal
49import core
|
48import _m5.drain 49import _m5.core 50from _m5.stats import updateEvents as updateStatEvents 51 |
52import stats 53import SimObject 54import ticks 55import objects 56from m5.util.dot_writer import do_dot, do_dvfs_dot
|
55from m5.internal.stats import updateEvents as updateStatEvents
|
57 58from util import fatal 59from util import attrdict 60 61# define a MaxTick parameter, unsigned 64 bit 62MaxTick = 2**64 - 1 63 64_memory_modes = { 65 "atomic" : objects.params.atomic, 66 "timing" : objects.params.timing, 67 "atomic_noncaching" : objects.params.atomic_noncaching, 68 } 69
|
69_drain_manager = internal.drain.DrainManager.instance()
|
70_drain_manager = _m5.drain.DrainManager.instance() |
71 72# The final hook to generate .ini files. Called from the user script 73# once the config is built. 74def instantiate(ckpt_dir=None): 75 from m5 import options 76 77 root = objects.Root.getInstance() 78 79 if not root: 80 fatal("Need to instantiate Root() before calling instantiate()") 81 82 # we need to fix the global frequency 83 ticks.fixGlobalFrequency() 84 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() 88 89 # Unproxy in sorted order for determinism 90 for obj in root.descendants(): obj.unproxyParams() 91 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) 97 ini_file.close() 98 99 if options.json_config: 100 try: 101 import json 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) 105 json_file.close() 106 except ImportError: 107 pass 108 109 do_dot(root, options.outdir, options.dot_config) 110 111 # Initialize the global statistics 112 stats.initSimStats() 113 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() 117 118 # Do a second pass to finish initializing the sim objects 119 for obj in root.descendants(): obj.init() 120 121 # Do a third pass to initialize statistics 122 for obj in root.descendants(): obj.regStats() 123 124 # Do a fourth pass to initialize probe points 125 for obj in root.descendants(): obj.regProbePoints() 126 127 # Do a fifth pass to connect probe listeners 128 for obj in root.descendants(): obj.regProbeListeners() 129 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) 135 136 # We're done registering statistics. Enable the stats package now. 137 stats.enable() 138 139 # Restore checkpoint (if any) 140 if ckpt_dir: 141 _drain_manager.preCheckpointRestore()
|
141 ckpt = internal.core.getCheckpoint(ckpt_dir)
142 internal.core.unserializeGlobals(ckpt);
|
142 ckpt = _m5.core.getCheckpoint(ckpt_dir) 143 _m5.core.unserializeGlobals(ckpt); |
144 for obj in root.descendants(): obj.loadState(ckpt) 145 else: 146 for obj in root.descendants(): obj.initState() 147 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. 150 updateStatEvents() 151 152need_startup = True 153def simulate(*args, **kwargs): 154 global need_startup 155 156 if need_startup: 157 root = objects.Root.getInstance() 158 for obj in root.descendants(): obj.startup() 159 need_startup = False 160 161 # Python exit handlers happen in reverse order. 162 # We want to dump stats last. 163 atexit.register(stats.dump) 164 165 # register our C++ exit callback function with Python
|
165 atexit.register(internal.core.doExitCleanup)
|
166 atexit.register(_m5.core.doExitCleanup) |
167 168 # Reset to put the stats in a consistent state. 169 stats.reset() 170 171 if _drain_manager.isDrained(): 172 _drain_manager.resume() 173
|
173 return internal.event.simulate(*args, **kwargs)
|
174 return _m5.event.simulate(*args, **kwargs) |
175
|
175# Export curTick to user script.
176def curTick():
177 return internal.core.curTick()
178
|
176def drain(): 177 """Drain the simulator in preparation of a checkpoint or memory mode 178 switch. 179 180 This operation is a no-op if the simulator is already in the 181 Drained state. 182 183 """ 184 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 188 # longer be drained. 189 def _drain(): 190 # Try to drain the system. The drain is successful if all 191 # objects are done without simulation. We need to simulate 192 # more if not. 193 if _drain_manager.tryDrain(): 194 return True 195 196 # WARNING: if a valid exit event occurs while draining, it 197 # will not get returned to the user script
|
201 exit_event = internal.event.simulate()
|
198 exit_event = _m5.event.simulate() |
199 while exit_event.getCause() != 'Finished drain': 200 exit_event = simulate() 201 202 return False 203 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() 208 209 assert _drain_manager.isDrained(), "Drain state inconsistent" 210 211def memWriteback(root): 212 for obj in root.descendants(): 213 obj.memWriteback() 214 215def memInvalidate(root): 216 for obj in root.descendants(): 217 obj.memInvalidate() 218 219def checkpoint(dir): 220 root = objects.Root.getInstance() 221 if not isinstance(root, objects.Root): 222 raise TypeError, "Checkpoint must be called on a root object." 223 224 drain() 225 memWriteback(root) 226 print "Writing checkpoint"
|
230 internal.core.serializeAll(dir)
|
227 _m5.core.serializeAll(dir) |
228 229def _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) 235 else: 236 print "System already in target mode. Memory mode unchanged." 237 238def switchCpus(system, cpuList, verbose=True): 239 """Switch CPUs in a system. 240 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 243 system. 244 245 Arguments: 246 system -- Simulated system. 247 cpuList -- (old_cpu, new_cpu) tuples 248 """ 249 250 if verbose: 251 print "switching cpus" 252 253 if not isinstance(cpuList, list): 254 raise RuntimeError, "Must pass a list to this function" 255 for item in cpuList: 256 if not isinstance(item, tuple) or len(item) != 2: 257 raise RuntimeError, "List must have tuples of (oldCPU,newCPU)" 258 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, 280 new_cpus[0]) 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,) 287 288 try: 289 memory_mode = _memory_modes[memory_mode_name] 290 except KeyError: 291 raise RuntimeError, "Invalid memory mode (%s)" % memory_mode_name 292 293 drain() 294 295 # Now all of the CPUs are ready to be switched out 296 for old_cpu, new_cpu in cpuList: 297 old_cpu.switchOut() 298 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: 306 memWriteback(system) 307 memInvalidate(system) 308 309 _changeMemoryMode(system, memory_mode) 310 311 for old_cpu, new_cpu in cpuList: 312 new_cpu.takeOverFrom(old_cpu) 313 314def notifyFork(root): 315 for obj in root.descendants(): 316 obj.notifyFork() 317 318fork_count = 0 319def fork(simout="%(parent)s.f%(fork_seq)i"): 320 """Fork the simulator. 321 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. 328 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. 333 334 Keyword Arguments: 335 simout -- New simulation output directory. 336 337 Return Value: 338 pid of the child process or 0 if running in the child. 339 """ 340 from m5 import options 341 global fork_count 342
|
346 if not internal.core.listenersDisabled():
|
343 if not _m5.core.listenersDisabled(): |
344 raise RuntimeError, "Can not fork a simulator with listeners enabled" 345 346 drain() 347 348 try: 349 pid = os.fork() 350 except OSError, e: 351 raise e 352 353 if pid == 0: 354 # In child, notify objects of the fork 355 root = objects.Root.getInstance() 356 notifyFork(root) 357 # Setup a new output directory 358 parent = options.outdir 359 options.outdir = simout % { 360 "parent" : parent, 361 "fork_seq" : fork_count, 362 "pid" : os.getpid(), 363 }
|
367 core.setOutputDir(options.outdir)
|
364 _m5.core.setOutputDir(options.outdir) |
365 else: 366 fork_count += 1 367 368 return pid 369
|
373from internal.core import disableAllListeners
374from internal.core import listenersDisabled
|
370from _m5.core import disableAllListeners, listenersDisabled 371from _m5.core import curTick |
|