simulate.py revision 10436:bdb307e8be54
112837Sgabeblack@google.com# Copyright (c) 2012 ARM Limited 212837Sgabeblack@google.com# All rights reserved. 312837Sgabeblack@google.com# 412837Sgabeblack@google.com# The license below extends only to copyright in the software and shall 512837Sgabeblack@google.com# not be construed as granting a license to any other intellectual 612837Sgabeblack@google.com# property including but not limited to intellectual property relating 712837Sgabeblack@google.com# to a hardware implementation of the functionality of the software 812837Sgabeblack@google.com# licensed hereunder. You may use the software subject to the license 912837Sgabeblack@google.com# terms below provided that you ensure that this notice is replicated 1012837Sgabeblack@google.com# unmodified and in its entirety in all distributions of the software, 1112837Sgabeblack@google.com# modified or unmodified, in source code or in binary form. 1212837Sgabeblack@google.com# 1312837Sgabeblack@google.com# Copyright (c) 2005 The Regents of The University of Michigan 1412837Sgabeblack@google.com# Copyright (c) 2010 Advanced Micro Devices, Inc. 1512837Sgabeblack@google.com# All rights reserved. 1612837Sgabeblack@google.com# 1712837Sgabeblack@google.com# Redistribution and use in source and binary forms, with or without 1812837Sgabeblack@google.com# modification, are permitted provided that the following conditions are 1912837Sgabeblack@google.com# met: redistributions of source code must retain the above copyright 2012837Sgabeblack@google.com# notice, this list of conditions and the following disclaimer; 2112837Sgabeblack@google.com# redistributions in binary form must reproduce the above copyright 2212837Sgabeblack@google.com# notice, this list of conditions and the following disclaimer in the 2312837Sgabeblack@google.com# documentation and/or other materials provided with the distribution; 2412837Sgabeblack@google.com# neither the name of the copyright holders nor the names of its 2512837Sgabeblack@google.com# contributors may be used to endorse or promote products derived from 2612837Sgabeblack@google.com# this software without specific prior written permission. 2712837Sgabeblack@google.com# 2812837Sgabeblack@google.com# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 2912837Sgabeblack@google.com# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 3012901Sgabeblack@google.com# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 3113135Sgabeblack@google.com# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 3212901Sgabeblack@google.com# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 3312901Sgabeblack@google.com# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 3412837Sgabeblack@google.com# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 3513280Sgabeblack@google.com# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 3612982Sgabeblack@google.com# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 3712951Sgabeblack@google.com# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 3813280Sgabeblack@google.com# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 3913288Sgabeblack@google.com# 4012953Sgabeblack@google.com# Authors: Nathan Binkert 4113260Sgabeblack@google.com# Steve Reinhardt 4213288Sgabeblack@google.com 4313288Sgabeblack@google.comimport atexit 4413288Sgabeblack@google.comimport os 4513155Sgabeblack@google.comimport sys 4612837Sgabeblack@google.com 4712951Sgabeblack@google.com# import the SWIG-wrapped main C++ functions 4813155Sgabeblack@google.comimport internal 4913135Sgabeblack@google.comimport core 5012837Sgabeblack@google.comimport stats 5112952Sgabeblack@google.comimport SimObject 5212952Sgabeblack@google.comimport ticks 5312952Sgabeblack@google.comimport objects 5412952Sgabeblack@google.comfrom m5.util.dot_writer import do_dot 5512952Sgabeblack@google.comfrom m5.internal.stats import updateEvents as updateStatEvents 5612952Sgabeblack@google.com 5713135Sgabeblack@google.comfrom util import fatal 5813135Sgabeblack@google.comfrom util import attrdict 5913135Sgabeblack@google.com 6013135Sgabeblack@google.com# define a MaxTick parameter, unsigned 64 bit 6113135Sgabeblack@google.comMaxTick = 2**64 - 1 6213135Sgabeblack@google.com 6313135Sgabeblack@google.com_memory_modes = { 6413135Sgabeblack@google.com "atomic" : objects.params.atomic, 6512993Sgabeblack@google.com "timing" : objects.params.timing, 6612993Sgabeblack@google.com "atomic_noncaching" : objects.params.atomic_noncaching, 6712952Sgabeblack@google.com } 6812952Sgabeblack@google.com 6912952Sgabeblack@google.com# The final hook to generate .ini files. Called from the user script 7012952Sgabeblack@google.com# once the config is built. 7112952Sgabeblack@google.comdef instantiate(ckpt_dir=None): 7213135Sgabeblack@google.com from m5 import options 7313135Sgabeblack@google.com 7413135Sgabeblack@google.com root = objects.Root.getInstance() 7513135Sgabeblack@google.com 7613135Sgabeblack@google.com if not root: 7713135Sgabeblack@google.com fatal("Need to instantiate Root() before calling instantiate()") 7813135Sgabeblack@google.com 7913135Sgabeblack@google.com # we need to fix the global frequency 8012993Sgabeblack@google.com ticks.fixGlobalFrequency() 8112993Sgabeblack@google.com 8212952Sgabeblack@google.com # Make sure SimObject-valued params are in the configuration 8312952Sgabeblack@google.com # hierarchy so we catch them with future descendants() walks 8412952Sgabeblack@google.com for obj in root.descendants(): obj.adoptOrphanParams() 8512952Sgabeblack@google.com 8612952Sgabeblack@google.com # Unproxy in sorted order for determinism 8713135Sgabeblack@google.com for obj in root.descendants(): obj.unproxyParams() 8813135Sgabeblack@google.com 8913135Sgabeblack@google.com if options.dump_config: 9013135Sgabeblack@google.com ini_file = file(os.path.join(options.outdir, options.dump_config), 'w') 9113135Sgabeblack@google.com # Print ini sections in sorted order for easier diffing 9213135Sgabeblack@google.com for obj in sorted(root.descendants(), key=lambda o: o.path()): 9313135Sgabeblack@google.com obj.print_ini(ini_file) 9413135Sgabeblack@google.com ini_file.close() 9512993Sgabeblack@google.com 9613194Sgabeblack@google.com if options.json_config: 9712993Sgabeblack@google.com try: 9812952Sgabeblack@google.com import json 9912952Sgabeblack@google.com json_file = file(os.path.join(options.outdir, options.json_config), 'w') 10012952Sgabeblack@google.com d = root.get_config_as_dict() 10112952Sgabeblack@google.com json.dump(d, json_file, indent=4) 10212837Sgabeblack@google.com json_file.close() 10312837Sgabeblack@google.com except ImportError: 10412837Sgabeblack@google.com pass 10513091Sgabeblack@google.com 10612951Sgabeblack@google.com do_dot(root, options.outdir, options.dot_config) 10712951Sgabeblack@google.com 10812837Sgabeblack@google.com # Initialize the global statistics 10913091Sgabeblack@google.com stats.initSimStats() 11012951Sgabeblack@google.com 11112951Sgabeblack@google.com # Create the C++ sim objects and connect ports 11212837Sgabeblack@google.com for obj in root.descendants(): obj.createCCObject() 11313091Sgabeblack@google.com for obj in root.descendants(): obj.connectPorts() 11412837Sgabeblack@google.com 11512982Sgabeblack@google.com # Do a second pass to finish initializing the sim objects 11612837Sgabeblack@google.com for obj in root.descendants(): obj.init() 11713091Sgabeblack@google.com 11812837Sgabeblack@google.com # Do a third pass to initialize statistics 11912837Sgabeblack@google.com for obj in root.descendants(): obj.regStats() 12012837Sgabeblack@google.com 12112837Sgabeblack@google.com # Do a fourth pass to initialize probe points 12212837Sgabeblack@google.com for obj in root.descendants(): obj.regProbePoints() 12312837Sgabeblack@google.com 12412837Sgabeblack@google.com # Do a fifth pass to connect probe listeners 12512837Sgabeblack@google.com for obj in root.descendants(): obj.regProbeListeners() 12612837Sgabeblack@google.com 12712837Sgabeblack@google.com # We're done registering statistics. Enable the stats package now. 12812837Sgabeblack@google.com stats.enable() 12912837Sgabeblack@google.com 13012837Sgabeblack@google.com # Restore checkpoint (if any) 13112837Sgabeblack@google.com if ckpt_dir: 13212837Sgabeblack@google.com ckpt = internal.core.getCheckpoint(ckpt_dir) 13312837Sgabeblack@google.com internal.core.unserializeGlobals(ckpt); 13412837Sgabeblack@google.com for obj in root.descendants(): obj.loadState(ckpt) 13512837Sgabeblack@google.com need_resume.append(root) 13612837Sgabeblack@google.com else: 13712837Sgabeblack@google.com for obj in root.descendants(): obj.initState() 13812837Sgabeblack@google.com 13912837Sgabeblack@google.com # Check to see if any of the stat events are in the past after resuming from 14012837Sgabeblack@google.com # a checkpoint, If so, this call will shift them to be at a valid time. 14112837Sgabeblack@google.com updateStatEvents() 14212837Sgabeblack@google.com 14312837Sgabeblack@google.comneed_resume = [] 14412837Sgabeblack@google.comneed_startup = True 14512837Sgabeblack@google.comdef simulate(*args, **kwargs): 14612837Sgabeblack@google.com global need_resume, need_startup 14712837Sgabeblack@google.com 14812837Sgabeblack@google.com if need_startup: 14912837Sgabeblack@google.com root = objects.Root.getInstance() 15012837Sgabeblack@google.com for obj in root.descendants(): obj.startup() 15112837Sgabeblack@google.com need_startup = False 15212837Sgabeblack@google.com 15312837Sgabeblack@google.com # Python exit handlers happen in reverse order. 15412837Sgabeblack@google.com # We want to dump stats last. 15512837Sgabeblack@google.com atexit.register(stats.dump) 15612837Sgabeblack@google.com 15712837Sgabeblack@google.com # register our C++ exit callback function with Python 15812837Sgabeblack@google.com atexit.register(internal.core.doExitCleanup) 15912837Sgabeblack@google.com 16012837Sgabeblack@google.com # Reset to put the stats in a consistent state. 16112837Sgabeblack@google.com stats.reset() 16212837Sgabeblack@google.com 16312837Sgabeblack@google.com for root in need_resume: 16412837Sgabeblack@google.com resume(root) 16512837Sgabeblack@google.com need_resume = [] 16612837Sgabeblack@google.com 16712837Sgabeblack@google.com return internal.event.simulate(*args, **kwargs) 16812837Sgabeblack@google.com 16912837Sgabeblack@google.com# Export curTick to user script. 17012837Sgabeblack@google.comdef curTick(): 17112837Sgabeblack@google.com return internal.core.curTick() 17212837Sgabeblack@google.com 17312837Sgabeblack@google.com# Drain the system in preparation of a checkpoint or memory mode 17412837Sgabeblack@google.com# switch. 17512837Sgabeblack@google.comdef drain(root): 17612837Sgabeblack@google.com # Try to drain all objects. Draining might not be completed unless 17712837Sgabeblack@google.com # all objects return that they are drained on the first call. This 17812837Sgabeblack@google.com # is because as objects drain they may cause other objects to no 17912837Sgabeblack@google.com # longer be drained. 18012837Sgabeblack@google.com def _drain(): 18112837Sgabeblack@google.com all_drained = False 18212837Sgabeblack@google.com dm = internal.drain.createDrainManager() 18312837Sgabeblack@google.com unready_objs = sum(obj.drain(dm) for obj in root.descendants()) 18412837Sgabeblack@google.com # If we've got some objects that can't drain immediately, then simulate 18513091Sgabeblack@google.com if unready_objs > 0: 18613091Sgabeblack@google.com dm.setCount(unready_objs) 18713091Sgabeblack@google.com #WARNING: if a valid exit event occurs while draining, it will not 18813091Sgabeblack@google.com # get returned to the user script 18913091Sgabeblack@google.com exit_event = simulate() 19013091Sgabeblack@google.com while exit_event.getCause() != 'Finished drain': 19113091Sgabeblack@google.com exit_event = simulate() 19213091Sgabeblack@google.com else: 19313091Sgabeblack@google.com all_drained = True 19413091Sgabeblack@google.com internal.drain.cleanupDrainManager(dm) 19513091Sgabeblack@google.com return all_drained 19613091Sgabeblack@google.com 19713091Sgabeblack@google.com all_drained = _drain() 19813091Sgabeblack@google.com while (not all_drained): 19913091Sgabeblack@google.com all_drained = _drain() 20013091Sgabeblack@google.com 20113091Sgabeblack@google.comdef memWriteback(root): 20213091Sgabeblack@google.com for obj in root.descendants(): 20313091Sgabeblack@google.com obj.memWriteback() 20413091Sgabeblack@google.com 20513091Sgabeblack@google.comdef memInvalidate(root): 20613091Sgabeblack@google.com for obj in root.descendants(): 20713091Sgabeblack@google.com obj.memInvalidate() 20813091Sgabeblack@google.com 20912837Sgabeblack@google.comdef resume(root): 21012837Sgabeblack@google.com for obj in root.descendants(): obj.drainResume() 21113292Sgabeblack@google.com 21213292Sgabeblack@google.comdef checkpoint(dir): 21313292Sgabeblack@google.com root = objects.Root.getInstance() 21413292Sgabeblack@google.com if not isinstance(root, objects.Root): 21513292Sgabeblack@google.com raise TypeError, "Checkpoint must be called on a root object." 21613292Sgabeblack@google.com drain(root) 21713292Sgabeblack@google.com memWriteback(root) 21813292Sgabeblack@google.com print "Writing checkpoint" 21913292Sgabeblack@google.com internal.core.serializeAll(dir) 22013292Sgabeblack@google.com resume(root) 22113292Sgabeblack@google.com 22213292Sgabeblack@google.comdef _changeMemoryMode(system, mode): 22313292Sgabeblack@google.com if not isinstance(system, (objects.Root, objects.System)): 22413292Sgabeblack@google.com raise TypeError, "Parameter of type '%s'. Must be type %s or %s." % \ 22513292Sgabeblack@google.com (type(system), objects.Root, objects.System) 22613292Sgabeblack@google.com if system.getMemoryMode() != mode: 22713292Sgabeblack@google.com drain(system) 22813292Sgabeblack@google.com system.setMemoryMode(mode) 22913292Sgabeblack@google.com else: 23013292Sgabeblack@google.com print "System already in target mode. Memory mode unchanged." 23113292Sgabeblack@google.com 23213292Sgabeblack@google.comdef switchCpus(system, cpuList, do_drain=True, verbose=True): 23313292Sgabeblack@google.com """Switch CPUs in a system. 23413292Sgabeblack@google.com 23513292Sgabeblack@google.com By default, this method drains and resumes the system. This 23613292Sgabeblack@google.com behavior can be disabled by setting the keyword argument 23713292Sgabeblack@google.com 'do_drain' to false, which might be desirable if multiple 23813292Sgabeblack@google.com operations requiring a drained system are going to be performed in 23912837Sgabeblack@google.com sequence. 24012837Sgabeblack@google.com 24112837Sgabeblack@google.com Note: This method may switch the memory mode of the system if that 24212951Sgabeblack@google.com is required by the CPUs. It may also flush all caches in the 24312837Sgabeblack@google.com system. 24412837Sgabeblack@google.com 24512837Sgabeblack@google.com Arguments: 24612837Sgabeblack@google.com system -- Simulated system. 24712837Sgabeblack@google.com cpuList -- (old_cpu, new_cpu) tuples 24812951Sgabeblack@google.com 24912837Sgabeblack@google.com Keyword Arguments: 25012837Sgabeblack@google.com do_drain -- Perform a drain/resume of the system when switching. 25112951Sgabeblack@google.com """ 25213079Sgabeblack@google.com 25312951Sgabeblack@google.com if verbose: 25413284Sgabeblack@google.com print "switching cpus" 25513284Sgabeblack@google.com 25613284Sgabeblack@google.com if not isinstance(cpuList, list): 25713284Sgabeblack@google.com raise RuntimeError, "Must pass a list to this function" 25813284Sgabeblack@google.com for item in cpuList: 25913284Sgabeblack@google.com if not isinstance(item, tuple) or len(item) != 2: 26013284Sgabeblack@google.com raise RuntimeError, "List must have tuples of (oldCPU,newCPU)" 26113284Sgabeblack@google.com 26213284Sgabeblack@google.com old_cpus = [old_cpu for old_cpu, new_cpu in cpuList] 26313284Sgabeblack@google.com new_cpus = [new_cpu for old_cpu, new_cpu in cpuList] 26412837Sgabeblack@google.com old_cpu_set = set(old_cpus) 26512951Sgabeblack@google.com memory_mode_name = new_cpus[0].memory_mode() 26613191Sgabeblack@google.com for old_cpu, new_cpu in cpuList: 26713191Sgabeblack@google.com if not isinstance(old_cpu, objects.BaseCPU): 26813191Sgabeblack@google.com raise TypeError, "%s is not of type BaseCPU" % old_cpu 26913191Sgabeblack@google.com if not isinstance(new_cpu, objects.BaseCPU): 27013191Sgabeblack@google.com raise TypeError, "%s is not of type BaseCPU" % new_cpu 27113191Sgabeblack@google.com if new_cpu in old_cpu_set: 27213191Sgabeblack@google.com raise RuntimeError, \ 27312951Sgabeblack@google.com "New CPU (%s) is in the list of old CPUs." % (old_cpu,) 27412951Sgabeblack@google.com if not new_cpu.switchedOut(): 27513191Sgabeblack@google.com raise RuntimeError, \ 27613191Sgabeblack@google.com "New CPU (%s) is already active." % (new_cpu,) 27713191Sgabeblack@google.com if not new_cpu.support_take_over(): 27813191Sgabeblack@google.com raise RuntimeError, \ 27913191Sgabeblack@google.com "New CPU (%s) does not support CPU handover." % (old_cpu,) 28013191Sgabeblack@google.com if new_cpu.memory_mode() != memory_mode_name: 28113191Sgabeblack@google.com raise RuntimeError, \ 28213191Sgabeblack@google.com "%s and %s require different memory modes." % (new_cpu, 28313191Sgabeblack@google.com new_cpus[0]) 28413191Sgabeblack@google.com if old_cpu.switchedOut(): 28513191Sgabeblack@google.com raise RuntimeError, \ 28613191Sgabeblack@google.com "Old CPU (%s) is inactive." % (new_cpu,) 28712928Sgabeblack@google.com if not old_cpu.support_take_over(): 28812837Sgabeblack@google.com raise RuntimeError, \ 28913260Sgabeblack@google.com "Old CPU (%s) does not support CPU handover." % (old_cpu,) 29012837Sgabeblack@google.com 29113288Sgabeblack@google.com try: 29212837Sgabeblack@google.com memory_mode = _memory_modes[memory_mode_name] 29312837Sgabeblack@google.com except KeyError: 29412837Sgabeblack@google.com raise RuntimeError, "Invalid memory mode (%s)" % memory_mode_name 29513260Sgabeblack@google.com 29612837Sgabeblack@google.com if do_drain: 29713288Sgabeblack@google.com drain(system) 29812837Sgabeblack@google.com 29912837Sgabeblack@google.com # Now all of the CPUs are ready to be switched out 30012837Sgabeblack@google.com for old_cpu, new_cpu in cpuList: 30113260Sgabeblack@google.com old_cpu.switchOut() 30212837Sgabeblack@google.com 30313288Sgabeblack@google.com # Change the memory mode if required. We check if this is needed 30412837Sgabeblack@google.com # to avoid printing a warning if no switch was performed. 30512837Sgabeblack@google.com if system.getMemoryMode() != memory_mode: 30612837Sgabeblack@google.com # Flush the memory system if we are switching to a memory mode 30713260Sgabeblack@google.com # that disables caches. This typically happens when switching to a 30812837Sgabeblack@google.com # hardware virtualized CPU. 30913288Sgabeblack@google.com if memory_mode == objects.params.atomic_noncaching: 31012837Sgabeblack@google.com memWriteback(system) 31112837Sgabeblack@google.com memInvalidate(system) 31212837Sgabeblack@google.com 31312837Sgabeblack@google.com _changeMemoryMode(system, memory_mode) 31413260Sgabeblack@google.com 31512837Sgabeblack@google.com for old_cpu, new_cpu in cpuList: 31613288Sgabeblack@google.com new_cpu.takeOverFrom(old_cpu) 31712837Sgabeblack@google.com 31812837Sgabeblack@google.com if do_drain: 31912837Sgabeblack@google.com resume(system) 32013260Sgabeblack@google.com 32112837Sgabeblack@google.comfrom internal.core import disableAllListeners 32213288Sgabeblack@google.com