simulate.py revision 11991
17008Snate@binkert.org# Copyright (c) 2012 ARM Limited 27008Snate@binkert.org# All rights reserved. 37008Snate@binkert.org# 47008Snate@binkert.org# The license below extends only to copyright in the software and shall 57008Snate@binkert.org# not be construed as granting a license to any other intellectual 67008Snate@binkert.org# property including but not limited to intellectual property relating 77008Snate@binkert.org# to a hardware implementation of the functionality of the software 87008Snate@binkert.org# licensed hereunder. You may use the software subject to the license 97008Snate@binkert.org# terms below provided that you ensure that this notice is replicated 107008Snate@binkert.org# unmodified and in its entirety in all distributions of the software, 117008Snate@binkert.org# modified or unmodified, in source code or in binary form. 127008Snate@binkert.org# 137008Snate@binkert.org# Copyright (c) 2005 The Regents of The University of Michigan 147008Snate@binkert.org# Copyright (c) 2010 Advanced Micro Devices, Inc. 157008Snate@binkert.org# All rights reserved. 167008Snate@binkert.org# 177008Snate@binkert.org# Redistribution and use in source and binary forms, with or without 187008Snate@binkert.org# modification, are permitted provided that the following conditions are 197008Snate@binkert.org# met: redistributions of source code must retain the above copyright 207008Snate@binkert.org# notice, this list of conditions and the following disclaimer; 217008Snate@binkert.org# redistributions in binary form must reproduce the above copyright 227008Snate@binkert.org# notice, this list of conditions and the following disclaimer in the 237008Snate@binkert.org# documentation and/or other materials provided with the distribution; 247008Snate@binkert.org# neither the name of the copyright holders nor the names of its 257008Snate@binkert.org# contributors may be used to endorse or promote products derived from 267008Snate@binkert.org# this software without specific prior written permission. 277008Snate@binkert.org# 286285Snate@binkert.org# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 297039Snate@binkert.org# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 307039Snate@binkert.org# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 316285Snate@binkert.org# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 327055Snate@binkert.org# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 337055Snate@binkert.org# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 346876Ssteve.reinhardt@amd.com# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 359745Snilay@cs.wisc.edu# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 368341Snilay@cs.wisc.edu# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 376506Spdudnik@gmail.com# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 387055Snate@binkert.org# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 398436SBrad.Beckmann@amd.com# 409497Snilay@cs.wisc.edu# Authors: Nathan Binkert 4110301Snilay@cs.wisc.edu# Steve Reinhardt 4210301Snilay@cs.wisc.edu 436881SBrad.Beckmann@amd.comimport atexit 4410301Snilay@cs.wisc.eduimport os 459364Snilay@cs.wisc.eduimport sys 467055Snate@binkert.org 479465Snilay@cs.wisc.edu# import the wrapped C++ functions 486285Snate@binkert.orgimport _m5.drain 496285Snate@binkert.orgimport _m5.core 506285Snate@binkert.orgfrom _m5.stats import updateEvents as updateStatEvents 519465Snilay@cs.wisc.edu 527039Snate@binkert.orgimport stats 537039Snate@binkert.orgimport SimObject 546876Ssteve.reinhardt@amd.comimport ticks 558436SBrad.Beckmann@amd.comimport objects 569496Snilay@cs.wisc.edufrom m5.util.dot_writer import do_dot, do_dvfs_dot 578257SBrad.Beckmann@amd.com 589745Snilay@cs.wisc.edufrom util import fatal 5910078Snilay@cs.wisc.edufrom util import attrdict 6010078Snilay@cs.wisc.edu 6110078Snilay@cs.wisc.edu# define a MaxTick parameter, unsigned 64 bit 629819Snilay@cs.wisc.eduMaxTick = 2**64 - 1 639819Snilay@cs.wisc.edu 649819Snilay@cs.wisc.edu_memory_modes = { 659819Snilay@cs.wisc.edu "atomic" : objects.params.atomic, 669819Snilay@cs.wisc.edu "timing" : objects.params.timing, 679819Snilay@cs.wisc.edu "atomic_noncaching" : objects.params.atomic_noncaching, 687039Snate@binkert.org } 698531Snilay@cs.wisc.edu 706285Snate@binkert.org_drain_manager = _m5.drain.DrainManager.instance() 717055Snate@binkert.org 727039Snate@binkert.org# The final hook to generate .ini files. Called from the user script 7310012Snilay@cs.wisc.edu# once the config is built. 7410012Snilay@cs.wisc.edudef instantiate(ckpt_dir=None): 759745Snilay@cs.wisc.edu from m5 import options 768683Snilay@cs.wisc.edu 778683Snilay@cs.wisc.edu root = objects.Root.getInstance() 789302Snilay@cs.wisc.edu 799302Snilay@cs.wisc.edu if not root: 809302Snilay@cs.wisc.edu fatal("Need to instantiate Root() before calling instantiate()") 819302Snilay@cs.wisc.edu 829302Snilay@cs.wisc.edu # we need to fix the global frequency 839302Snilay@cs.wisc.edu ticks.fixGlobalFrequency() 8410522Snilay@cs.wisc.edu 859302Snilay@cs.wisc.edu # Make sure SimObject-valued params are in the configuration 869302Snilay@cs.wisc.edu # hierarchy so we catch them with future descendants() walks 879302Snilay@cs.wisc.edu for obj in root.descendants(): obj.adoptOrphanParams() 8810522Snilay@cs.wisc.edu 899363Snilay@cs.wisc.edu # Unproxy in sorted order for determinism 909363Snilay@cs.wisc.edu for obj in root.descendants(): obj.unproxyParams() 919363Snilay@cs.wisc.edu 929363Snilay@cs.wisc.edu if options.dump_config: 939364Snilay@cs.wisc.edu ini_file = file(os.path.join(options.outdir, options.dump_config), 'w') 949745Snilay@cs.wisc.edu # Print ini sections in sorted order for easier diffing 959745Snilay@cs.wisc.edu for obj in sorted(root.descendants(), key=lambda o: o.path()): 969745Snilay@cs.wisc.edu obj.print_ini(ini_file) 979745Snilay@cs.wisc.edu ini_file.close() 989745Snilay@cs.wisc.edu 999745Snilay@cs.wisc.edu if options.json_config: 10010311Snilay@cs.wisc.edu try: 10110311Snilay@cs.wisc.edu import json 10210311Snilay@cs.wisc.edu json_file = file(os.path.join(options.outdir, options.json_config), 'w') 1039496Snilay@cs.wisc.edu d = root.get_config_as_dict() 1049496Snilay@cs.wisc.edu json.dump(d, json_file, indent=4) 1059496Snilay@cs.wisc.edu json_file.close() 10610012Snilay@cs.wisc.edu except ImportError: 10710012Snilay@cs.wisc.edu pass 10810012Snilay@cs.wisc.edu 1099497Snilay@cs.wisc.edu do_dot(root, options.outdir, options.dot_config) 1109496Snilay@cs.wisc.edu 1119496Snilay@cs.wisc.edu # Initialize the global statistics 1129496Snilay@cs.wisc.edu stats.initSimStats() 1139497Snilay@cs.wisc.edu 1149507Snilay@cs.wisc.edu # Create the C++ sim objects and connect ports 1159496Snilay@cs.wisc.edu for obj in root.descendants(): obj.createCCObject() 1169596Snilay@cs.wisc.edu for obj in root.descendants(): obj.connectPorts() 1179596Snilay@cs.wisc.edu 1189596Snilay@cs.wisc.edu # Do a second pass to finish initializing the sim objects 1199596Snilay@cs.wisc.edu for obj in root.descendants(): obj.init() 1209596Snilay@cs.wisc.edu 1219364Snilay@cs.wisc.edu # Do a third pass to initialize statistics 1229364Snilay@cs.wisc.edu for obj in root.descendants(): obj.regStats() 12310005Snilay@cs.wisc.edu 12410005Snilay@cs.wisc.edu # Do a fourth pass to initialize probe points 12510005Snilay@cs.wisc.edu for obj in root.descendants(): obj.regProbePoints() 1269364Snilay@cs.wisc.edu 1279364Snilay@cs.wisc.edu # Do a fifth pass to connect probe listeners 1289364Snilay@cs.wisc.edu for obj in root.descendants(): obj.regProbeListeners() 12910087Snilay@cs.wisc.edu 1309364Snilay@cs.wisc.edu # We want to generate the DVFS diagram for the system. This can only be 1319364Snilay@cs.wisc.edu # done once all of the CPP objects have been created and initialised so 1329364Snilay@cs.wisc.edu # that we are able to figure out which object belongs to which domain. 13310087Snilay@cs.wisc.edu if options.dot_dvfs_config: 1349996Snilay@cs.wisc.edu do_dvfs_dot(root, options.outdir, options.dot_dvfs_config) 1359996Snilay@cs.wisc.edu 1369364Snilay@cs.wisc.edu # We're done registering statistics. Enable the stats package now. 13710005Snilay@cs.wisc.edu stats.enable() 13810096Snilay@cs.wisc.edu 13910005Snilay@cs.wisc.edu # Restore checkpoint (if any) 1409496Snilay@cs.wisc.edu if ckpt_dir: 1419496Snilay@cs.wisc.edu _drain_manager.preCheckpointRestore() 1429496Snilay@cs.wisc.edu ckpt = _m5.core.getCheckpoint(ckpt_dir) 14310012Snilay@cs.wisc.edu _m5.core.unserializeGlobals(ckpt); 1449497Snilay@cs.wisc.edu for obj in root.descendants(): obj.loadState(ckpt) 1459497Snilay@cs.wisc.edu else: 1469497Snilay@cs.wisc.edu for obj in root.descendants(): obj.initState() 14710012Snilay@cs.wisc.edu 14810012Snilay@cs.wisc.edu # Check to see if any of the stat events are in the past after resuming from 1499745Snilay@cs.wisc.edu # a checkpoint, If so, this call will shift them to be at a valid time. 1509745Snilay@cs.wisc.edu updateStatEvents() 1519745Snilay@cs.wisc.edu 1529745Snilay@cs.wisc.eduneed_startup = True 1539745Snilay@cs.wisc.edudef simulate(*args, **kwargs): 1549745Snilay@cs.wisc.edu global need_startup 1559745Snilay@cs.wisc.edu 1569745Snilay@cs.wisc.edu if need_startup: 1579745Snilay@cs.wisc.edu root = objects.Root.getInstance() 1589745Snilay@cs.wisc.edu for obj in root.descendants(): obj.startup() 15910012Snilay@cs.wisc.edu need_startup = False 1609745Snilay@cs.wisc.edu 1619745Snilay@cs.wisc.edu # Python exit handlers happen in reverse order. 1626285Snate@binkert.org # We want to dump stats last. 1636285Snate@binkert.org atexit.register(stats.dump) 1647039Snate@binkert.org 165 # register our C++ exit callback function with Python 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 174 return _m5.event.simulate(*args, **kwargs) 175 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 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" 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 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 } 364 _m5.core.setOutputDir(options.outdir) 365 else: 366 fork_count += 1 367 368 return pid 369 370from _m5.core import disableAllListeners, listenersDisabled 371from _m5.core import curTick 372