simulate.py revision 11418:0aeca8f47eac
14479Sbinkertn@umich.edu# Copyright (c) 2012 ARM Limited 24479Sbinkertn@umich.edu# All rights reserved. 34479Sbinkertn@umich.edu# 44479Sbinkertn@umich.edu# The license below extends only to copyright in the software and shall 54479Sbinkertn@umich.edu# not be construed as granting a license to any other intellectual 64479Sbinkertn@umich.edu# property including but not limited to intellectual property relating 74479Sbinkertn@umich.edu# to a hardware implementation of the functionality of the software 84479Sbinkertn@umich.edu# licensed hereunder. You may use the software subject to the license 94479Sbinkertn@umich.edu# terms below provided that you ensure that this notice is replicated 104479Sbinkertn@umich.edu# unmodified and in its entirety in all distributions of the software, 114479Sbinkertn@umich.edu# modified or unmodified, in source code or in binary form. 124479Sbinkertn@umich.edu# 134479Sbinkertn@umich.edu# Copyright (c) 2005 The Regents of The University of Michigan 144479Sbinkertn@umich.edu# Copyright (c) 2010 Advanced Micro Devices, Inc. 154479Sbinkertn@umich.edu# All rights reserved. 164479Sbinkertn@umich.edu# 174479Sbinkertn@umich.edu# Redistribution and use in source and binary forms, with or without 184479Sbinkertn@umich.edu# modification, are permitted provided that the following conditions are 194479Sbinkertn@umich.edu# met: redistributions of source code must retain the above copyright 204479Sbinkertn@umich.edu# notice, this list of conditions and the following disclaimer; 214479Sbinkertn@umich.edu# redistributions in binary form must reproduce the above copyright 224479Sbinkertn@umich.edu# notice, this list of conditions and the following disclaimer in the 234479Sbinkertn@umich.edu# documentation and/or other materials provided with the distribution; 244479Sbinkertn@umich.edu# neither the name of the copyright holders nor the names of its 254479Sbinkertn@umich.edu# contributors may be used to endorse or promote products derived from 264479Sbinkertn@umich.edu# this software without specific prior written permission. 274479Sbinkertn@umich.edu# 286498Snate@binkert.org# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 294479Sbinkertn@umich.edu# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 304479Sbinkertn@umich.edu# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 314479Sbinkertn@umich.edu# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 324479Sbinkertn@umich.edu# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 334479Sbinkertn@umich.edu# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 344479Sbinkertn@umich.edu# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 354479Sbinkertn@umich.edu# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 364479Sbinkertn@umich.edu# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 374479Sbinkertn@umich.edu# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 384479Sbinkertn@umich.edu# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 394479Sbinkertn@umich.edu# 404479Sbinkertn@umich.edu# Authors: Nathan Binkert 414479Sbinkertn@umich.edu# Steve Reinhardt 424479Sbinkertn@umich.edu 434479Sbinkertn@umich.eduimport atexit 444479Sbinkertn@umich.eduimport os 454479Sbinkertn@umich.eduimport sys 464479Sbinkertn@umich.edu 474479Sbinkertn@umich.edu# import the SWIG-wrapped main C++ functions 484479Sbinkertn@umich.eduimport internal 494479Sbinkertn@umich.eduimport core 504479Sbinkertn@umich.eduimport stats 514479Sbinkertn@umich.eduimport SimObject 524479Sbinkertn@umich.eduimport ticks 534479Sbinkertn@umich.eduimport objects 544479Sbinkertn@umich.edufrom m5.util.dot_writer import do_dot, do_dvfs_dot 554479Sbinkertn@umich.edufrom m5.internal.stats import updateEvents as updateStatEvents 564479Sbinkertn@umich.edu 574479Sbinkertn@umich.edufrom util import fatal 584479Sbinkertn@umich.edufrom util import attrdict 594479Sbinkertn@umich.edu 604479Sbinkertn@umich.edu# define a MaxTick parameter, unsigned 64 bit 614479Sbinkertn@umich.eduMaxTick = 2**64 - 1 624479Sbinkertn@umich.edu 634479Sbinkertn@umich.edu_memory_modes = { 644479Sbinkertn@umich.edu "atomic" : objects.params.atomic, 654479Sbinkertn@umich.edu "timing" : objects.params.timing, 664479Sbinkertn@umich.edu "atomic_noncaching" : objects.params.atomic_noncaching, 674479Sbinkertn@umich.edu } 684479Sbinkertn@umich.edu 694479Sbinkertn@umich.edu_drain_manager = internal.drain.DrainManager.instance() 704479Sbinkertn@umich.edu 714479Sbinkertn@umich.edu# The final hook to generate .ini files. Called from the user script 724479Sbinkertn@umich.edu# once the config is built. 734479Sbinkertn@umich.edudef instantiate(ckpt_dir=None): 744479Sbinkertn@umich.edu from m5 import options 754479Sbinkertn@umich.edu 764479Sbinkertn@umich.edu root = objects.Root.getInstance() 774479Sbinkertn@umich.edu 784479Sbinkertn@umich.edu if not root: 794479Sbinkertn@umich.edu fatal("Need to instantiate Root() before calling instantiate()") 804479Sbinkertn@umich.edu 816498Snate@binkert.org # we need to fix the global frequency 824479Sbinkertn@umich.edu ticks.fixGlobalFrequency() 834479Sbinkertn@umich.edu 844479Sbinkertn@umich.edu # Make sure SimObject-valued params are in the configuration 854479Sbinkertn@umich.edu # hierarchy so we catch them with future descendants() walks 866498Snate@binkert.org for obj in root.descendants(): obj.adoptOrphanParams() 874479Sbinkertn@umich.edu 884479Sbinkertn@umich.edu # Unproxy in sorted order for determinism 894479Sbinkertn@umich.edu for obj in root.descendants(): obj.unproxyParams() 904479Sbinkertn@umich.edu 914479Sbinkertn@umich.edu if options.dump_config: 924479Sbinkertn@umich.edu ini_file = file(os.path.join(options.outdir, options.dump_config), 'w') 934479Sbinkertn@umich.edu # Print ini sections in sorted order for easier diffing 944479Sbinkertn@umich.edu for obj in sorted(root.descendants(), key=lambda o: o.path()): 954479Sbinkertn@umich.edu obj.print_ini(ini_file) 964479Sbinkertn@umich.edu ini_file.close() 974479Sbinkertn@umich.edu 984479Sbinkertn@umich.edu if options.json_config: 994479Sbinkertn@umich.edu try: 1004479Sbinkertn@umich.edu import json 1014479Sbinkertn@umich.edu json_file = file(os.path.join(options.outdir, options.json_config), 'w') 1024479Sbinkertn@umich.edu d = root.get_config_as_dict() 1034479Sbinkertn@umich.edu json.dump(d, json_file, indent=4) 1044479Sbinkertn@umich.edu json_file.close() 1054479Sbinkertn@umich.edu except ImportError: 1064479Sbinkertn@umich.edu pass 1074479Sbinkertn@umich.edu 1084479Sbinkertn@umich.edu do_dot(root, options.outdir, options.dot_config) 1094479Sbinkertn@umich.edu 1104479Sbinkertn@umich.edu # Initialize the global statistics 1114479Sbinkertn@umich.edu stats.initSimStats() 1124479Sbinkertn@umich.edu 1134479Sbinkertn@umich.edu # Create the C++ sim objects and connect ports 1144479Sbinkertn@umich.edu for obj in root.descendants(): obj.createCCObject() 1154479Sbinkertn@umich.edu for obj in root.descendants(): obj.connectPorts() 1164479Sbinkertn@umich.edu 1174479Sbinkertn@umich.edu # Do a second pass to finish initializing the sim objects 1184479Sbinkertn@umich.edu for obj in root.descendants(): obj.init() 1194479Sbinkertn@umich.edu 1204479Sbinkertn@umich.edu # Do a third pass to initialize statistics 1214479Sbinkertn@umich.edu for obj in root.descendants(): obj.regStats() 1224479Sbinkertn@umich.edu 1234479Sbinkertn@umich.edu # Do a fourth pass to initialize probe points 1244479Sbinkertn@umich.edu for obj in root.descendants(): obj.regProbePoints() 1254479Sbinkertn@umich.edu 1264479Sbinkertn@umich.edu # Do a fifth pass to connect probe listeners 1274479Sbinkertn@umich.edu for obj in root.descendants(): obj.regProbeListeners() 1284479Sbinkertn@umich.edu 1294479Sbinkertn@umich.edu # We want to generate the DVFS diagram for the system. This can only be 1304479Sbinkertn@umich.edu # done once all of the CPP objects have been created and initialised so 1314479Sbinkertn@umich.edu # that we are able to figure out which object belongs to which domain. 1324479Sbinkertn@umich.edu do_dvfs_dot(root, options.outdir, options.dot_dvfs_config) 1334479Sbinkertn@umich.edu 1344479Sbinkertn@umich.edu # We're done registering statistics. Enable the stats package now. 1354479Sbinkertn@umich.edu stats.enable() 1364479Sbinkertn@umich.edu 1374479Sbinkertn@umich.edu # Restore checkpoint (if any) 1384479Sbinkertn@umich.edu if ckpt_dir: 1394479Sbinkertn@umich.edu _drain_manager.preCheckpointRestore() 1404479Sbinkertn@umich.edu ckpt = internal.core.getCheckpoint(ckpt_dir) 1414479Sbinkertn@umich.edu internal.core.unserializeGlobals(ckpt); 1424479Sbinkertn@umich.edu for obj in root.descendants(): obj.loadState(ckpt) 1434479Sbinkertn@umich.edu else: 1444479Sbinkertn@umich.edu for obj in root.descendants(): obj.initState() 1454479Sbinkertn@umich.edu 1464479Sbinkertn@umich.edu # Check to see if any of the stat events are in the past after resuming from 1474479Sbinkertn@umich.edu # a checkpoint, If so, this call will shift them to be at a valid time. 1484479Sbinkertn@umich.edu updateStatEvents() 1494479Sbinkertn@umich.edu 1504479Sbinkertn@umich.eduneed_startup = True 1514479Sbinkertn@umich.edudef simulate(*args, **kwargs): 1524479Sbinkertn@umich.edu global need_startup 1534479Sbinkertn@umich.edu 1544479Sbinkertn@umich.edu if need_startup: 1554479Sbinkertn@umich.edu root = objects.Root.getInstance() 1564479Sbinkertn@umich.edu for obj in root.descendants(): obj.startup() 1574479Sbinkertn@umich.edu need_startup = False 1584479Sbinkertn@umich.edu 1594479Sbinkertn@umich.edu # Python exit handlers happen in reverse order. 1604479Sbinkertn@umich.edu # We want to dump stats last. 1614479Sbinkertn@umich.edu atexit.register(stats.dump) 1624479Sbinkertn@umich.edu 1634479Sbinkertn@umich.edu # register our C++ exit callback function with Python 1644479Sbinkertn@umich.edu atexit.register(internal.core.doExitCleanup) 1654479Sbinkertn@umich.edu 1664479Sbinkertn@umich.edu # Reset to put the stats in a consistent state. 1674479Sbinkertn@umich.edu stats.reset() 1686498Snate@binkert.org 1694479Sbinkertn@umich.edu if _drain_manager.isDrained(): 1704479Sbinkertn@umich.edu _drain_manager.resume() 1714479Sbinkertn@umich.edu 1724479Sbinkertn@umich.edu return internal.event.simulate(*args, **kwargs) 1734479Sbinkertn@umich.edu 1744479Sbinkertn@umich.edu# Export curTick to user script. 1754479Sbinkertn@umich.edudef curTick(): 1766498Snate@binkert.org return internal.core.curTick() 1776498Snate@binkert.org 1784479Sbinkertn@umich.edudef drain(): 1796498Snate@binkert.org """Drain the simulator in preparation of a checkpoint or memory mode 1804479Sbinkertn@umich.edu switch. 1814479Sbinkertn@umich.edu 1824479Sbinkertn@umich.edu This operation is a no-op if the simulator is already in the 1834479Sbinkertn@umich.edu Drained state. 1844479Sbinkertn@umich.edu 1854479Sbinkertn@umich.edu """ 1864479Sbinkertn@umich.edu 1874479Sbinkertn@umich.edu # Try to drain all objects. Draining might not be completed unless 1884479Sbinkertn@umich.edu # all objects return that they are drained on the first call. This 1894479Sbinkertn@umich.edu # is because as objects drain they may cause other objects to no 1904479Sbinkertn@umich.edu # longer be drained. 1914479Sbinkertn@umich.edu def _drain(): 1924479Sbinkertn@umich.edu # Try to drain the system. The drain is successful if all 1934479Sbinkertn@umich.edu # objects are done without simulation. We need to simulate 1944479Sbinkertn@umich.edu # more if not. 1954479Sbinkertn@umich.edu if _drain_manager.tryDrain(): 1964479Sbinkertn@umich.edu return True 1974479Sbinkertn@umich.edu 1984479Sbinkertn@umich.edu # WARNING: if a valid exit event occurs while draining, it 1994479Sbinkertn@umich.edu # will not get returned to the user script 2004479Sbinkertn@umich.edu exit_event = internal.event.simulate() 2014479Sbinkertn@umich.edu while exit_event.getCause() != 'Finished drain': 2024479Sbinkertn@umich.edu exit_event = simulate() 2034479Sbinkertn@umich.edu 2044479Sbinkertn@umich.edu return False 2054479Sbinkertn@umich.edu 2064479Sbinkertn@umich.edu # Don't try to drain a system that is already drained 2074479Sbinkertn@umich.edu is_drained = _drain_manager.isDrained() 2084479Sbinkertn@umich.edu while not is_drained: 2094479Sbinkertn@umich.edu is_drained = _drain() 2104479Sbinkertn@umich.edu 2114479Sbinkertn@umich.edu assert _drain_manager.isDrained(), "Drain state inconsistent" 2124479Sbinkertn@umich.edu 2134479Sbinkertn@umich.edudef memWriteback(root): 2144479Sbinkertn@umich.edu for obj in root.descendants(): 2154479Sbinkertn@umich.edu obj.memWriteback() 2164479Sbinkertn@umich.edu 2174479Sbinkertn@umich.edudef memInvalidate(root): 218 for obj in root.descendants(): 219 obj.memInvalidate() 220 221def checkpoint(dir): 222 root = objects.Root.getInstance() 223 if not isinstance(root, objects.Root): 224 raise TypeError, "Checkpoint must be called on a root object." 225 226 drain() 227 memWriteback(root) 228 print "Writing checkpoint" 229 internal.core.serializeAll(dir) 230 231def _changeMemoryMode(system, mode): 232 if not isinstance(system, (objects.Root, objects.System)): 233 raise TypeError, "Parameter of type '%s'. Must be type %s or %s." % \ 234 (type(system), objects.Root, objects.System) 235 if system.getMemoryMode() != mode: 236 system.setMemoryMode(mode) 237 else: 238 print "System already in target mode. Memory mode unchanged." 239 240def switchCpus(system, cpuList, verbose=True): 241 """Switch CPUs in a system. 242 243 Note: This method may switch the memory mode of the system if that 244 is required by the CPUs. It may also flush all caches in the 245 system. 246 247 Arguments: 248 system -- Simulated system. 249 cpuList -- (old_cpu, new_cpu) tuples 250 """ 251 252 if verbose: 253 print "switching cpus" 254 255 if not isinstance(cpuList, list): 256 raise RuntimeError, "Must pass a list to this function" 257 for item in cpuList: 258 if not isinstance(item, tuple) or len(item) != 2: 259 raise RuntimeError, "List must have tuples of (oldCPU,newCPU)" 260 261 old_cpus = [old_cpu for old_cpu, new_cpu in cpuList] 262 new_cpus = [new_cpu for old_cpu, new_cpu in cpuList] 263 old_cpu_set = set(old_cpus) 264 memory_mode_name = new_cpus[0].memory_mode() 265 for old_cpu, new_cpu in cpuList: 266 if not isinstance(old_cpu, objects.BaseCPU): 267 raise TypeError, "%s is not of type BaseCPU" % old_cpu 268 if not isinstance(new_cpu, objects.BaseCPU): 269 raise TypeError, "%s is not of type BaseCPU" % new_cpu 270 if new_cpu in old_cpu_set: 271 raise RuntimeError, \ 272 "New CPU (%s) is in the list of old CPUs." % (old_cpu,) 273 if not new_cpu.switchedOut(): 274 raise RuntimeError, \ 275 "New CPU (%s) is already active." % (new_cpu,) 276 if not new_cpu.support_take_over(): 277 raise RuntimeError, \ 278 "New CPU (%s) does not support CPU handover." % (old_cpu,) 279 if new_cpu.memory_mode() != memory_mode_name: 280 raise RuntimeError, \ 281 "%s and %s require different memory modes." % (new_cpu, 282 new_cpus[0]) 283 if old_cpu.switchedOut(): 284 raise RuntimeError, \ 285 "Old CPU (%s) is inactive." % (new_cpu,) 286 if not old_cpu.support_take_over(): 287 raise RuntimeError, \ 288 "Old CPU (%s) does not support CPU handover." % (old_cpu,) 289 290 try: 291 memory_mode = _memory_modes[memory_mode_name] 292 except KeyError: 293 raise RuntimeError, "Invalid memory mode (%s)" % memory_mode_name 294 295 drain() 296 297 # Now all of the CPUs are ready to be switched out 298 for old_cpu, new_cpu in cpuList: 299 old_cpu.switchOut() 300 301 # Change the memory mode if required. We check if this is needed 302 # to avoid printing a warning if no switch was performed. 303 if system.getMemoryMode() != memory_mode: 304 # Flush the memory system if we are switching to a memory mode 305 # that disables caches. This typically happens when switching to a 306 # hardware virtualized CPU. 307 if memory_mode == objects.params.atomic_noncaching: 308 memWriteback(system) 309 memInvalidate(system) 310 311 _changeMemoryMode(system, memory_mode) 312 313 for old_cpu, new_cpu in cpuList: 314 new_cpu.takeOverFrom(old_cpu) 315 316def notifyFork(root): 317 for obj in root.descendants(): 318 obj.notifyFork() 319 320fork_count = 0 321def fork(simout="%(parent)s.f%(fork_seq)i"): 322 """Fork the simulator. 323 324 This function forks the simulator. After forking the simulator, 325 the child process gets its output files redirected to a new output 326 directory. The default name of the output directory is the same as 327 the parent with the suffix ".fN" added where N is the fork 328 sequence number. The name of the output directory can be 329 overridden using the simout keyword argument. 330 331 Output file formatting dictionary: 332 parent -- Path to the parent process's output directory. 333 fork_seq -- Fork sequence number. 334 pid -- PID of the child process. 335 336 Keyword Arguments: 337 simout -- New simulation output directory. 338 339 Return Value: 340 pid of the child process or 0 if running in the child. 341 """ 342 from m5 import options 343 global fork_count 344 345 if not internal.core.listenersDisabled(): 346 raise RuntimeError, "Can not fork a simulator with listeners enabled" 347 348 drain() 349 350 try: 351 pid = os.fork() 352 except OSError, e: 353 raise e 354 355 if pid == 0: 356 # In child, notify objects of the fork 357 root = objects.Root.getInstance() 358 notifyFork(root) 359 # Setup a new output directory 360 parent = options.outdir 361 options.outdir = simout % { 362 "parent" : parent, 363 "fork_seq" : fork_count, 364 "pid" : os.getpid(), 365 } 366 core.setOutputDir(options.outdir) 367 else: 368 fork_count += 1 369 370 return pid 371 372from internal.core import disableAllListeners 373from internal.core import listenersDisabled 374