cpu: Introduce sanity checks when switching between CPUs
authorAndreas Sandberg <Andreas.Sandberg@ARM.com>
Mon, 7 Jan 2013 18:05:44 +0000 (13:05 -0500)
committerAndreas Sandberg <Andreas.Sandberg@ARM.com>
Mon, 7 Jan 2013 18:05:44 +0000 (13:05 -0500)
This patch introduces the following sanity checks when switching
between CPUs:

 * Check that the set of new and old CPUs do not overlap. Having an
   overlap between the set of new CPUs and the set of old CPUs is
   currently not supported. Doing such a switch used to result in the
   following assertion error:
     BaseCPU::takeOverFrom(BaseCPU*): \
       Assertion `!new_itb_port->isConnected()' failed.

 * Check that all new CPUs are in the switched out state.

 * Check that all old CPUs are in the switched in state.

src/cpu/BaseCPU.py
src/cpu/base.cc
src/cpu/base.hh
src/python/m5/simulate.py

index 697be87e1a177a9946dcc7d2f6c5e9fdd29d8e8b..957203150634a1ba60e7bc2d6641816a74ff2163 100644 (file)
@@ -95,6 +95,7 @@ class BaseCPU(MemObject):
         code('''
     void switchOut();
     void takeOverFrom(BaseCPU *cpu);
+    bool switchedOut();
 ''')
 
     def takeOverFrom(self, old_cpu):
index 2b1df669677ae0e8d1adbe1a955bbf0608dfe5b1..b8cd60f6305e20bf9dccbcebbb4e0f938c243609 100644 (file)
@@ -119,6 +119,7 @@ BaseCPU::BaseCPU(Params *p, bool is_checker)
       _instMasterId(p->system->getMasterId(name() + ".inst")),
       _dataMasterId(p->system->getMasterId(name() + ".data")),
       _taskId(ContextSwitchTaskId::Unknown), _pid(Request::invldPid),
+      _switchedOut(p->defer_registration),
       interrupts(p->interrupts), profileEvent(NULL),
       numThreads(p->numThreads), system(p->system)
 {
@@ -356,6 +357,8 @@ BaseCPU::findContext(ThreadContext *tc)
 void
 BaseCPU::switchOut()
 {
+    assert(!_switchedOut);
+    _switchedOut = true;
     if (profileEvent && profileEvent->scheduled())
         deschedule(profileEvent);
 }
@@ -365,8 +368,11 @@ BaseCPU::takeOverFrom(BaseCPU *oldCPU)
 {
     assert(threadContexts.size() == oldCPU->threadContexts.size());
     assert(_cpuId == oldCPU->cpuId());
+    assert(_switchedOut);
+    assert(oldCPU != this);
     _pid = oldCPU->getPid();
     _taskId = oldCPU->taskId();
+    _switchedOut = false;
 
     ThreadID size = threadContexts.size();
     for (ThreadID i = 0; i < size; ++i) {
index 6552be0d6db49dc48e6e4aa06ba71f944f218295..633b7f2a70cf7eca0992a40b032e8a65d8814494 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2011 ARM Limited
+ * Copyright (c) 2011-2012 ARM Limited
  * All rights reserved
  *
  * The license below extends only to copyright in the software and shall
@@ -114,6 +114,9 @@ class BaseCPU : public MemObject
      * used to generate a taskId */
     uint32_t _pid;
 
+    /** Is the CPU switched out or active? */
+    bool _switchedOut;
+
     /**
      * Define a base class for the CPU ports (instruction and data)
      * that is refined in the subclasses. This class handles the
@@ -320,6 +323,13 @@ class BaseCPU : public MemObject
      */
     virtual void takeOverFrom(BaseCPU *cpu);
 
+    /**
+     * Determine if the CPU is switched out.
+     *
+     * @return True if the CPU is switched out, false otherwise.
+     */
+    bool switchedOut() const { return _switchedOut; }
+
     /**
      *  Number of threads we're actually simulating (<= SMT_MAX_THREADS).
      * This is a constant for the duration of the simulation.
index 8ad273225164e5fad791bae7b581066c28b99efa..a30648929c9676bc12caac4dfdca0d7c2c6d25ad 100644 (file)
@@ -228,11 +228,21 @@ 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])
     for old_cpu, new_cpu in cpuList:
         if not isinstance(old_cpu, objects.BaseCPU):
             raise TypeError, "%s is not of type BaseCPU" % old_cpu
         if not isinstance(new_cpu, objects.BaseCPU):
             raise TypeError, "%s is not of type BaseCPU" % new_cpu
+        if new_cpu in old_cpu_set:
+            raise RuntimeError, \
+                "New CPU (%s) is in the list of old CPUs." % (old_cpu,)
+        if not new_cpu.switchedOut():
+            raise RuntimeError, \
+                "New CPU (%s) is already active." % (new_cpu,)
+        if old_cpu.switchedOut():
+            raise RuntimeError, \
+                "Old CPU (%s) is inactive." % (new_cpu,)
 
     # Now all of the CPUs are ready to be switched out
     for old_cpu, new_cpu in cpuList: