summaryrefslogtreecommitdiff
path: root/src/python/m5/simulate.py
diff options
context:
space:
mode:
Diffstat (limited to 'src/python/m5/simulate.py')
-rw-r--r--src/python/m5/simulate.py199
1 files changed, 199 insertions, 0 deletions
diff --git a/src/python/m5/simulate.py b/src/python/m5/simulate.py
new file mode 100644
index 000000000..1ef78d6cb
--- /dev/null
+++ b/src/python/m5/simulate.py
@@ -0,0 +1,199 @@
+# Copyright (c) 2005 The Regents of The University of Michigan
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are
+# met: redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer;
+# redistributions in binary form must reproduce the above copyright
+# notice, this list of conditions and the following disclaimer in the
+# documentation and/or other materials provided with the distribution;
+# neither the name of the copyright holders nor the names of its
+# contributors may be used to endorse or promote products derived from
+# this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+#
+# Authors: Nathan Binkert
+# Steve Reinhardt
+
+import atexit
+import os
+import sys
+
+# import the SWIG-wrapped main C++ functions
+import internal
+from main import options
+import SimObject
+import ticks
+
+# The final hook to generate .ini files. Called from the user script
+# once the config is built.
+def instantiate(root):
+ # we need to fix the global frequency
+ ticks.fixGlobalFrequency()
+
+ root.unproxy_all()
+ # ugly temporary hack to get output to config.ini
+ sys.stdout = file(os.path.join(options.outdir, 'config.ini'), 'w')
+ root.print_ini()
+ sys.stdout.close() # close config.ini
+ sys.stdout = sys.__stdout__ # restore to original
+
+ # Initialize the global statistics
+ internal.stats.initSimStats()
+
+ # Create the C++ sim objects and connect ports
+ root.createCCObject()
+ root.connectPorts()
+
+ # Do a second pass to finish initializing the sim objects
+ internal.sim_object.initAll()
+
+ # Do a third pass to initialize statistics
+ internal.sim_object.regAllStats()
+
+ # Check to make sure that the stats package is properly initialized
+ internal.stats.check()
+
+ # Reset to put the stats in a consistent state.
+ internal.stats.reset()
+
+def doDot(root):
+ dot = pydot.Dot()
+ instance.outputDot(dot)
+ dot.orientation = "portrait"
+ dot.size = "8.5,11"
+ dot.ranksep="equally"
+ dot.rank="samerank"
+ dot.write("config.dot")
+ dot.write_ps("config.ps")
+
+need_resume = []
+need_startup = True
+def simulate(*args, **kwargs):
+ global need_resume, need_startup
+
+ if need_startup:
+ internal.core.SimStartup()
+ need_startup = False
+
+ for root in need_resume:
+ resume(root)
+ need_resume = []
+
+ return internal.event.simulate(*args, **kwargs)
+
+# Export curTick to user script.
+def curTick():
+ return internal.core.cvar.curTick
+
+# Python exit handlers happen in reverse order. We want to dump stats last.
+atexit.register(internal.stats.dump)
+
+# register our C++ exit callback function with Python
+atexit.register(internal.core.doExitCleanup)
+
+# This loops until all objects have been fully drained.
+def doDrain(root):
+ all_drained = drain(root)
+ while (not all_drained):
+ all_drained = drain(root)
+
+# Tries to drain all objects. Draining might not be completed unless
+# all objects return that they are drained on the first call. This is
+# because as objects drain they may cause other objects to no longer
+# be drained.
+def drain(root):
+ all_drained = False
+ drain_event = internal.event.createCountedDrain()
+ unready_objects = root.startDrain(drain_event, True)
+ # If we've got some objects that can't drain immediately, then simulate
+ if unready_objects > 0:
+ drain_event.setCount(unready_objects)
+ simulate()
+ else:
+ all_drained = True
+ internal.event.cleanupCountedDrain(drain_event)
+ return all_drained
+
+def resume(root):
+ root.resume()
+
+def checkpoint(root, dir):
+ if not isinstance(root, objects.Root):
+ raise TypeError, "Checkpoint must be called on a root object."
+ doDrain(root)
+ print "Writing checkpoint"
+ internal.sim_object.serializeAll(dir)
+ resume(root)
+
+def restoreCheckpoint(root, dir):
+ print "Restoring from checkpoint"
+ internal.sim_object.unserializeAll(dir)
+ need_resume.append(root)
+
+def changeToAtomic(system):
+ if not isinstance(system, (objects.Root, objects.System)):
+ raise TypeError, "Parameter of type '%s'. Must be type %s or %s." % \
+ (type(system), objects.Root, objects.System)
+ if system.getMemoryMode() != internal.sim_object.SimObject.Atomic:
+ doDrain(system)
+ print "Changing memory mode to atomic"
+ system.changeTiming(internal.sim_object.SimObject.Atomic)
+
+def changeToTiming(system):
+ if not isinstance(system, (objects.Root, objects.System)):
+ raise TypeError, "Parameter of type '%s'. Must be type %s or %s." % \
+ (type(system), objects.Root, objects.System)
+
+ if system.getMemoryMode() != internal.sim_object.SimObject.Timing:
+ doDrain(system)
+ print "Changing memory mode to timing"
+ system.changeTiming(internal.sim_object.SimObject.Timing)
+
+def switchCpus(cpuList):
+ print "switching cpus"
+ if not isinstance(cpuList, list):
+ raise RuntimeError, "Must pass a list to this function"
+ for i in cpuList:
+ if not isinstance(i, tuple):
+ raise RuntimeError, "List must have tuples of (oldCPU,newCPU)"
+
+ [old_cpus, new_cpus] = zip(*cpuList)
+
+ for cpu in old_cpus:
+ if not isinstance(cpu, objects.BaseCPU):
+ raise TypeError, "%s is not of type BaseCPU" % cpu
+ for cpu in new_cpus:
+ if not isinstance(cpu, objects.BaseCPU):
+ raise TypeError, "%s is not of type BaseCPU" % cpu
+
+ # Drain all of the individual CPUs
+ drain_event = internal.event.createCountedDrain()
+ unready_cpus = 0
+ for old_cpu in old_cpus:
+ unready_cpus += old_cpu.startDrain(drain_event, False)
+ # If we've got some objects that can't drain immediately, then simulate
+ if unready_cpus > 0:
+ drain_event.setCount(unready_cpus)
+ simulate()
+ internal.event.cleanupCountedDrain(drain_event)
+ # Now all of the CPUs are ready to be switched out
+ for old_cpu in old_cpus:
+ old_cpu._ccObject.switchOut()
+ index = 0
+ for new_cpu in new_cpus:
+ new_cpu.takeOverFrom(old_cpus[index])
+ new_cpu._ccObject.resume()
+ index += 1