summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--configs/common/Simulation.py19
-rw-r--r--src/python/m5/simulate.py63
-rw-r--r--tests/configs/switcheroo.py12
3 files changed, 60 insertions, 34 deletions
diff --git a/configs/common/Simulation.py b/configs/common/Simulation.py
index d678c57a0..6f0e3cee0 100644
--- a/configs/common/Simulation.py
+++ b/configs/common/Simulation.py
@@ -242,10 +242,7 @@ def repeatSwitch(testsys, repeat_switch_cpu_list, maxtick, switch_freq):
if exit_cause != "simulate() limit reached":
return exit_event
- print "draining the system"
- m5.drain(testsys)
- m5.switchCpus(repeat_switch_cpu_list)
- m5.resume(testsys)
+ m5.switchCpus(testsys, repeat_switch_cpu_list)
tmp_cpu_list = []
for old_cpu, new_cpu in repeat_switch_cpu_list:
@@ -436,15 +433,7 @@ def run(options, root, testsys, cpu_class):
exit_event = m5.simulate(10000)
print "Switched CPUS @ tick %s" % (m5.curTick())
- # when you change to Timing (or Atomic), you halt the system
- # given as argument. When you are finished with the system
- # changes (including switchCpus), you must resume the system
- # manually. You DON'T need to resume after just switching
- # CPUs if you haven't changed anything on the system level.
-
- m5.changeToTiming(testsys)
- m5.switchCpus(switch_cpu_list)
- m5.resume(testsys)
+ m5.switchCpus(testsys, switch_cpu_list)
if options.standard_switch:
print "Switch at instruction count:%d" % \
@@ -458,9 +447,7 @@ def run(options, root, testsys, cpu_class):
print "Switching CPUS @ tick %s" % (m5.curTick())
print "Simulation ends instruction count:%d" % \
(testsys.switch_cpus_1[0].max_insts_any_thread)
- m5.drain(testsys)
- m5.switchCpus(switch_cpu_list1)
- m5.resume(testsys)
+ m5.switchCpus(testsys, switch_cpu_list1)
# If we're taking and restoring checkpoints, use checkpoint_dir
# option only for finding the checkpoints to restore from. This
diff --git a/src/python/m5/simulate.py b/src/python/m5/simulate.py
index a30648929..3583e8264 100644
--- a/src/python/m5/simulate.py
+++ b/src/python/m5/simulate.py
@@ -60,6 +60,11 @@ from util import attrdict
# define a MaxTick parameter
MaxTick = 2**63 - 1
+_memory_modes = {
+ "atomic" : objects.params.atomic,
+ "timing" : objects.params.timing,
+ }
+
# The final hook to generate .ini files. Called from the user script
# once the config is built.
def instantiate(ckpt_dir=None):
@@ -202,7 +207,7 @@ def checkpoint(dir):
internal.core.serializeAll(dir)
resume(root)
-def changeMemoryMode(system, mode):
+def _changeMemoryMode(system, mode):
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)
@@ -212,15 +217,26 @@ def changeMemoryMode(system, mode):
else:
print "System already in target mode. Memory mode unchanged."
-def changeToAtomic(system, **kwargs):
- print "Changing memory mode to atomic"
- changeMemoryMode(system, objects.params.atomic, **kwargs)
+def switchCpus(system, cpuList, do_drain=True):
+ """Switch CPUs in a system.
+
+ By default, this method drains and resumes the system. This
+ behavior can be disabled by setting the keyword argument
+ 'do_drain' to false, which might be desirable if multiple
+ operations requiring a drained system are going to be performed in
+ sequence.
+
+ Note: This method may switch the memory mode of the system if that
+ is required by the CPUs. It may also flush all caches in the
+ system.
-def changeToTiming(system, **kwargs):
- print "Changing memory mode to timing"
- changeMemoryMode(system, objects.params.timing, **kwargs)
+ Arguments:
+ system -- Simulated system.
+ cpuList -- (old_cpu, new_cpu) tuples
-def switchCpus(cpuList):
+ Keyword Arguments:
+ do_drain -- Perform a drain/resume of the system when switching.
+ """
print "switching cpus"
if not isinstance(cpuList, list):
raise RuntimeError, "Must pass a list to this function"
@@ -228,7 +244,10 @@ def switchCpus(cpuList):
if not isinstance(item, tuple) or len(item) != 2:
raise RuntimeError, "List must have tuples of (oldCPU,newCPU)"
- old_cpu_set = set([old_cpu for old_cpu, new_cpu in cpuList])
+ old_cpus = [old_cpu for old_cpu, new_cpu in cpuList]
+ new_cpus = [new_cpu for old_cpu, new_cpu in cpuList]
+ old_cpu_set = set(old_cpus)
+ memory_mode_name = new_cpus[0].memory_mode()
for old_cpu, new_cpu in cpuList:
if not isinstance(old_cpu, objects.BaseCPU):
raise TypeError, "%s is not of type BaseCPU" % old_cpu
@@ -240,15 +259,41 @@ def switchCpus(cpuList):
if not new_cpu.switchedOut():
raise RuntimeError, \
"New CPU (%s) is already active." % (new_cpu,)
+ if not new_cpu.support_take_over():
+ raise RuntimeError, \
+ "New CPU (%s) does not support CPU handover." % (old_cpu,)
+ if new_cpu.memory_mode() != memory_mode_name:
+ raise RuntimeError, \
+ "%s and %s require different memory modes." % (new_cpu,
+ new_cpus[0])
if old_cpu.switchedOut():
raise RuntimeError, \
"Old CPU (%s) is inactive." % (new_cpu,)
+ if not old_cpu.support_take_over():
+ raise RuntimeError, \
+ "Old CPU (%s) does not support CPU handover." % (old_cpu,)
+
+ try:
+ memory_mode = _memory_modes[memory_mode_name]
+ except KeyError:
+ raise RuntimeError, "Invalid memory mode (%s)" % memory_mode_name
+
+ if do_drain:
+ drain(system)
# Now all of the CPUs are ready to be switched out
for old_cpu, new_cpu in cpuList:
old_cpu.switchOut()
+ # Change the memory mode if required. We check if this is needed
+ # to avoid printing a warning if no switch was performed.
+ if system.getMemoryMode() != memory_mode:
+ _changeMemoryMode(system, memory_mode)
+
for old_cpu, new_cpu in cpuList:
new_cpu.takeOverFrom(old_cpu)
+ if do_drain:
+ resume(system)
+
from internal.core import disableAllListeners
diff --git a/tests/configs/switcheroo.py b/tests/configs/switcheroo.py
index dadf8db03..4b2dd9a69 100644
--- a/tests/configs/switcheroo.py
+++ b/tests/configs/switcheroo.py
@@ -40,12 +40,6 @@ from m5.objects import *
m5.util.addToPath('../configs/common')
from Caches import *
-def _memMode(cclass):
- if cclass == AtomicSimpleCPU:
- return "atomic", m5.objects.params.atomic
- else:
- return "timing", m5.objects.params.timing
-
class Sequential:
"""Sequential CPU switcher.
@@ -104,7 +98,7 @@ def run_test(root, switcher=None, freq=1000):
current_cpu = switcher.first()
system = root.system
- system.mem_mode = _memMode(type(current_cpu))[0]
+ system.mem_mode = type(current_cpu).memory_mode()
# instantiate configuration
m5.instantiate()
@@ -122,9 +116,9 @@ def run_test(root, switcher=None, freq=1000):
print "Switching CPUs..."
print "Next CPU: %s" % type(next_cpu)
m5.drain(system)
- system.setMemoryMode(_memMode(type(next_cpu))[1])
if current_cpu != next_cpu:
- m5.switchCpus([ (current_cpu, next_cpu) ])
+ m5.switchCpus(system, [ (current_cpu, next_cpu) ],
+ do_drain=False)
else:
print "Source CPU and destination CPU are the same, skipping..."
m5.resume(system)