}
}
-unsigned int
-Stage2MMU::drain(DrainManager *dm)
-{
- return port.drain(dm);
-}
-
ArmISA::Stage2MMU *
ArmStage2MMUParams::create()
{
*/
DmaPort& getPort() { return port; }
- unsigned int drain(DrainManager *dm);
-
Fault readDataUntimed(ThreadContext *tc, Addr oVAddr, Addr descAddr,
uint8_t *data, int numBytes, Request::Flags flags, bool isFunctional);
Fault readDataTimed(ThreadContext *tc, Addr descAddr,
unsigned int
UFSHostDevice::drain(DrainManager *dm)
{
- unsigned int count = 0;
-
- // check pio, dma port, and doorbells
- count = pioPort.drain(dm) + dmaPort.drain(dm);
-
if (UFSHCIMem.TRUTRLDBR) {
- count += 1;
drainManager = dm;
- } else {
- DPRINTF(UFSHostDevice, "UFSHostDevice in drained state\n");
- }
-
- if (count) {
DPRINTF(UFSHostDevice, "UFSDevice is draining...\n");
setDrainState(DrainState::Draining);
+ return 1;
} else {
DPRINTF(UFSHostDevice, "UFSDevice drained\n");
setDrainState(DrainState::Drained);
+ return 0;
}
- return count;
}
/**
{
if (nextState == Idle || ce->getDrainState() != DrainState::Running)
return 0;
- unsigned int count = 1;
- count += cePort.drain(dm);
DPRINTF(Drain, "CopyEngineChannel not drained\n");
this->drainManager = dm;
- return count;
-}
-
-unsigned int
-CopyEngine::drain(DrainManager *dm)
-{
- unsigned int count;
- count = pioPort.drain(dm) + dmaPort.drain(dm) + configPort.drain(dm);
- for (int x = 0;x < chan.size(); x++)
- count += chan[x]->drain(dm);
-
- if (count)
- setDrainState(DrainState::Draining);
- else
- setDrainState(DrainState::Drained);
-
- DPRINTF(Drain, "CopyEngine not drained\n");
- return count;
+ return 1;
}
void
}
}
-void
-CopyEngine::drainResume()
-{
- Drainable::drainResume();
- for (int x = 0;x < chan.size(); x++)
- chan[x]->drainResume();
-}
-
-
void
CopyEngine::CopyEngineChannel::drainResume()
{
void serialize(CheckpointOut &cp) const M5_ATTR_OVERRIDE;
void unserialize(CheckpointIn &cp) M5_ATTR_OVERRIDE;
-
- unsigned int drain(DrainManager *drainManger);
- void drainResume();
};
#endif //__DEV_COPY_ENGINE_HH__
PioDevice::init();
}
-unsigned int
-DmaDevice::drain(DrainManager *dm)
-{
- unsigned int count = pioPort.drain(dm) + dmaPort.drain(dm);
- if (count)
- setDrainState(DrainState::Draining);
- else
- setDrainState(DrainState::Drained);
- return count;
-}
-
unsigned int
DmaPort::drain(DrainManager *dm)
{
#include "sim/drain.hh"
#include "sim/system.hh"
-class DmaPort : public MasterPort
+class DmaPort : public MasterPort, public Drainable
{
private:
virtual void init();
- unsigned int drain(DrainManager *drainManger);
-
unsigned int cacheBlockSize() const { return sys->cacheLineSize(); }
virtual BaseMasterPort &getMasterPort(const std::string &if_name,
unsigned int
IGbE::drain(DrainManager *dm)
{
- unsigned int count;
- count = pioPort.drain(dm) + dmaPort.drain(dm);
+ unsigned int count(0);
if (rxDescCache.hasOutstandingEvents() ||
txDescCache.hasOutstandingEvents()) {
count++;
return MemObject::getSlavePort(if_name, idx);
}
-unsigned int
-PioDevice::drain(DrainManager *dm)
-{
- unsigned int count;
- count = pioPort.drain(dm);
- if (count)
- setDrainState(DrainState::Draining);
- else
- setDrainState(DrainState::Drained);
- return count;
-}
-
BasicPioDevice::BasicPioDevice(const Params *p, Addr size)
: PioDevice(p), pioAddr(p->pio_addr), pioSize(size),
pioDelay(p->pio_latency)
virtual void init();
- unsigned int drain(DrainManager *drainManger);
-
virtual BaseSlavePort &getSlavePort(const std::string &if_name,
PortID idx = InvalidPortID);
DmaDevice::init();
}
-unsigned int
-PciDevice::drain(DrainManager *dm)
-{
- unsigned int count;
- count = pioPort.drain(dm) + dmaPort.drain(dm) + configPort.drain(dm);
- if (count)
- setDrainState(DrainState::Draining);
- else
- setDrainState(DrainState::Drained);
- return count;
-}
-
Tick
PciDevice::readConfig(PacketPtr pkt)
{
void unserialize(CheckpointIn &cp) M5_ATTR_OVERRIDE;
- virtual unsigned int drain(DrainManager *dm);
-
virtual BaseSlavePort &getSlavePort(const std::string &if_name,
PortID idx = InvalidPortID)
{
}
-unsigned int
-BaseCache::drain(DrainManager *dm)
-{
- int count = memSidePort->drain(dm) + cpuSidePort->drain(dm) +
- mshrQueue.drain(dm) + writeBuffer.drain(dm);
-
- // Set status
- if (count != 0) {
- setDrainState(DrainState::Draining);
- DPRINTF(Drain, "Cache not drained\n");
- return count;
- }
-
- setDrainState(DrainState::Drained);
- return 0;
-}
-
BaseCache *
BaseCacheParams::create()
{
// interesting again.
}
- virtual unsigned int drain(DrainManager *dm);
-
virtual bool inCache(Addr addr, bool is_secure) const = 0;
virtual bool inMissQueue(Addr addr, bool is_secure) const = 0;
}
}
-unsigned int
-CoherentXBar::drain(DrainManager *dm)
-{
- // sum up the individual layers
- unsigned int total = 0;
- for (auto l: reqLayers)
- total += l->drain(dm);
- for (auto l: respLayers)
- total += l->drain(dm);
- for (auto l: snoopLayers)
- total += l->drain(dm);
- return total;
-}
-
void
CoherentXBar::regStats()
{
virtual ~CoherentXBar();
- unsigned int drain(DrainManager *dm);
-
virtual void regStats();
};
unsigned int
DRAMCtrl::drain(DrainManager *dm)
{
- unsigned int count = port.drain(dm);
-
// if there is anything in any of our internal queues, keep track
// of that as well
if (!(writeQueue.empty() && readQueue.empty() &&
DPRINTF(Drain, "DRAM controller not drained, write: %d, read: %d,"
" resp: %d\n", writeQueue.size(), readQueue.size(),
respQueue.size());
- ++count;
drainManager = dm;
// the only part that is not drained automatically over time
if (!writeQueue.empty() && !nextReqEvent.scheduled()) {
schedule(nextReqEvent, curTick());
}
- }
-
- if (count)
setDrainState(DrainState::Draining);
- else
+ return 1;
+ } else {
setDrainState(DrainState::Drained);
- return count;
+ return 0;
+ }
}
void
masterPorts[dest_id]->sendFunctional(pkt);
}
-unsigned int
-NoncoherentXBar::drain(DrainManager *dm)
-{
- // sum up the individual layers
- unsigned int total = 0;
- for (auto l: reqLayers)
- total += l->drain(dm);
- for (auto l: respLayers)
- total += l->drain(dm);
- return total;
-}
-
NoncoherentXBar*
NoncoherentXBarParams::create()
{
virtual ~NoncoherentXBar();
- unsigned int drain(DrainManager *dm);
-
/**
* stats
*/
* functional request. */
bool checkFunctional(PacketPtr pkt)
{ return respQueue.checkFunctional(pkt); }
-
- unsigned int drain(DrainManager *dm) { return respQueue.drain(dm); }
};
/**
return reqQueue.checkFunctional(pkt) ||
snoopRespQueue.checkFunctional(pkt);
}
-
- unsigned int drain(DrainManager *dm)
- { return reqQueue.drain(dm) + snoopRespQueue.drain(dm); }
};
#endif // __MEM_QPORT_HH__
}
}
-unsigned int
-DMASequencer::getChildDrainCount(DrainManager *dm)
-{
- int count = 0;
- count += slave_port.drain(dm);
- DPRINTF(Config, "count after slave port check %d\n", count);
- return count;
-}
-
unsigned int
DMASequencer::drain(DrainManager *dm)
{
DPRINTF(Config, "outstanding count %d\n", outstandingCount());
bool need_drain = outstandingCount() > 0;
- //
- // Also, get the number of child ports that will also need to clear
- // their buffered requests before they call drainManager->signalDrainDone()
- //
- unsigned int child_drain_count = getChildDrainCount(dm);
// Set status
if (need_drain) {
DPRINTF(Drain, "DMASequencer not drained\n");
setDrainState(DrainState::Draining);
- return child_drain_count + 1;
+ return 1;
}
drainManager = NULL;
setDrainState(DrainState::Drained);
- return child_drain_count;
+ return 0;
}
void
}
}
-unsigned int
-RubyPort::getChildDrainCount(DrainManager *dm)
-{
- int count = 0;
-
- if (memMasterPort.isConnected()) {
- count += memMasterPort.drain(dm);
- DPRINTF(Config, "count after pio check %d\n", count);
- }
-
- for (CpuPortIter p = slave_ports.begin(); p != slave_ports.end(); ++p) {
- count += (*p)->drain(dm);
- DPRINTF(Config, "count after slave port check %d\n", count);
- }
-
- for (std::vector<PioMasterPort *>::iterator p = master_ports.begin();
- p != master_ports.end(); ++p) {
- count += (*p)->drain(dm);
- DPRINTF(Config, "count after master port check %d\n", count);
- }
-
- DPRINTF(Config, "final count %d\n", count);
- return count;
-}
-
unsigned int
RubyPort::drain(DrainManager *dm)
{
DPRINTF(Config, "outstanding count %d\n", outstandingCount());
bool need_drain = outstandingCount() > 0;
- //
- // Also, get the number of child ports that will also need to clear
- // their buffered requests before they call drainManager->signalDrainDone()
- //
- unsigned int child_drain_count = getChildDrainCount(dm);
-
// Set status
if (need_drain) {
drainManager = dm;
DPRINTF(Drain, "RubyPort not drained\n");
setDrainState(DrainState::Draining);
- return child_drain_count + 1;
+ return 1;
}
drainManager = NULL;
setDrainState(DrainState::Drained);
- return child_drain_count;
+ return 0;
}
void
retryList.push_back(port);
}
- unsigned int getChildDrainCount(DrainManager *dm);
-
PioMasterPort pioMasterPort;
PioSlavePort pioSlavePort;
MemMasterPort memMasterPort;
BaseSlavePort& getSlavePort(const std::string& if_name,
PortID idx = InvalidPortID);
- virtual unsigned int drain(DrainManager *dm) = 0;
-
virtual void regStats();
};
"atomic_noncaching" : objects.params.atomic_noncaching,
}
+_drain_manager = internal.drain.DrainManager.instance()
+
# The final hook to generate .ini files. Called from the user script
# once the config is built.
def instantiate(ckpt_dir=None):
# Restore checkpoint (if any)
if ckpt_dir:
+ _drain_manager.preCheckpointRestore()
ckpt = internal.core.getCheckpoint(ckpt_dir)
internal.core.unserializeGlobals(ckpt);
for obj in root.descendants(): obj.loadState(ckpt)
- need_resume.append(root)
else:
for obj in root.descendants(): obj.initState()
# a checkpoint, If so, this call will shift them to be at a valid time.
updateStatEvents()
-need_resume = []
need_startup = True
def simulate(*args, **kwargs):
- global need_resume, need_startup
+ global need_startup
if need_startup:
root = objects.Root.getInstance()
# Reset to put the stats in a consistent state.
stats.reset()
- for root in need_resume:
- resume(root)
- need_resume = []
+ if _drain_manager.isDrained():
+ _drain_manager.resume()
return internal.event.simulate(*args, **kwargs)
def curTick():
return internal.core.curTick()
-# Drain the system in preparation of a checkpoint or memory mode
-# switch.
-def drain(root):
+def drain():
+ """Drain the simulator in preparation of a checkpoint or memory mode
+ switch.
+
+ This operation is a no-op if the simulator is already in the
+ Drained state.
+
+ """
+
# Try 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():
- all_drained = False
- dm = internal.drain.createDrainManager()
- unready_objs = sum(obj.drain(dm) for obj in root.descendants())
- # If we've got some objects that can't drain immediately, then simulate
- if unready_objs > 0:
- dm.setCount(unready_objs)
- #WARNING: if a valid exit event occurs while draining, it will not
- # get returned to the user script
+ # Try to drain the system. The drain is successful if all
+ # objects are done without simulation. We need to simulate
+ # more if not.
+ if _drain_manager.tryDrain():
+ return True
+
+ # WARNING: if a valid exit event occurs while draining, it
+ # will not get returned to the user script
+ exit_event = internal.event.simulate()
+ while exit_event.getCause() != 'Finished drain':
exit_event = simulate()
- while exit_event.getCause() != 'Finished drain':
- exit_event = simulate()
- else:
- all_drained = True
- internal.drain.cleanupDrainManager(dm)
- return all_drained
- all_drained = _drain()
- while (not all_drained):
- all_drained = _drain()
+ return False
+
+ # Don't try to drain a system that is already drained
+ is_drained = _drain_manager.isDrained()
+ while not is_drained:
+ is_drained = _drain()
+
+ assert _drain_manager.isDrained(), "Drain state inconsistent"
def memWriteback(root):
for obj in root.descendants():
for obj in root.descendants():
obj.memInvalidate()
-def resume(root):
- for obj in root.descendants(): obj.drainResume()
-
def checkpoint(dir):
root = objects.Root.getInstance()
if not isinstance(root, objects.Root):
raise TypeError, "Checkpoint must be called on a root object."
- drain(root)
+
+ drain()
memWriteback(root)
print "Writing checkpoint"
internal.core.serializeAll(dir)
- resume(root)
def _changeMemoryMode(system, mode):
if not isinstance(system, (objects.Root, objects.System)):
else:
print "System already in target mode. Memory mode unchanged."
-def switchCpus(system, cpuList, do_drain=True, verbose=True):
+def switchCpus(system, cpuList, verbose=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.
Arguments:
system -- Simulated system.
cpuList -- (old_cpu, new_cpu) tuples
-
- Keyword Arguments:
- do_drain -- Perform a drain/resume of the system when switching.
"""
if verbose:
except KeyError:
raise RuntimeError, "Invalid memory mode (%s)" % memory_mode_name
- if do_drain:
- drain(system)
+ drain()
# Now all of the CPUs are ready to be switched out
for old_cpu, new_cpu in cpuList:
for old_cpu, new_cpu in cpuList:
new_cpu.takeOverFrom(old_cpu)
- if do_drain:
- resume(system)
-
from internal.core import disableAllListeners
%nodefaultctor Drainable;
%include "sim/drain.hh"
-
-%inline %{
-
-DrainManager *
-createDrainManager()
-{
- return new DrainManager();
-}
-
-void
-cleanupDrainManager(DrainManager *drain_manager)
-{
- assert(drain_manager);
- assert(drain_manager->getCount() == 0);
- delete drain_manager;
-}
-
-%}
}
unsigned int
-CxxConfigManager::drain(DrainManager *drain_manager)
+CxxConfigManager::drain()
{
- unsigned int ret = 0;
-
- for (auto i = objectsInOrder.begin(); i != objectsInOrder.end(); ++ i)
- ret += (*i)->drain(drain_manager);
-
- return ret;
+ return DrainManager::instance().tryDrain() ? 0 : 1;
}
void
CxxConfigManager::drainResume()
{
- forEachObject(&SimObject::drainResume);
+ DrainManager::instance().resume();
}
void
void startup();
/** Drain all objects */
- unsigned int drain(DrainManager *drain_manager);
+ unsigned int drain();
/** Resume from drain */
void drainResume();
*/
#include "sim/drain.hh"
+
+#include "base/misc.hh"
+#include "base/trace.hh"
+#include "debug/Drain.hh"
#include "sim/sim_exit.hh"
+DrainManager DrainManager::_instance;
+
DrainManager::DrainManager()
- : _count(0)
+ : _count(0),
+ _state(DrainState::Running)
{
}
{
}
+bool
+DrainManager::tryDrain()
+{
+ panic_if(_state == DrainState::Drained,
+ "Trying to drain a drained system\n");
+
+ panic_if(_count != 0,
+ "Drain counter must be zero at the start of a drain cycle\n");
+
+ DPRINTF(Drain, "Trying to drain %u objects.\n", drainableCount());
+ _state = DrainState::Draining;
+ for (auto *obj : _allDrainable)
+ _count += obj->drain(&_instance);
+
+ if (_count == 0) {
+ DPRINTF(Drain, "Drain done.\n");
+ _state = DrainState::Drained;
+ return true;
+ } else {
+ DPRINTF(Drain, "Need another drain cycle. %u/%u objects not ready.\n",
+ _count, drainableCount());
+ return false;
+ }
+}
+
+void
+DrainManager::resume()
+{
+ panic_if(_state == DrainState::Running,
+ "Trying to resume a system that is already running\n");
+
+ warn_if(_state == DrainState::Draining,
+ "Resuming a system that isn't fully drained, this is untested and "
+ "likely to break\n");
+
+ panic_if(_count != 0,
+ "Resume called in the middle of a drain cycle. %u objects "
+ "left to drain.\n", _count);
+
+ DPRINTF(Drain, "Resuming %u objects.\n", drainableCount());
+ _state = DrainState::Running;
+ for (auto *obj : _allDrainable)
+ obj->drainResume();
+}
+
+void
+DrainManager::preCheckpointRestore()
+{
+ panic_if(_state != DrainState::Running,
+ "preCheckpointRestore() called on a system that isn't in the "
+ "Running state.\n");
+
+ DPRINTF(Drain, "Applying pre-restore fixes to %u objects.\n",
+ drainableCount());
+ _state = DrainState::Drained;
+ for (auto *obj : _allDrainable)
+ obj->_drainState = DrainState::Drained;
+}
+
+void
+DrainManager::signalDrainDone()
+{
+ if (--_count == 0) {
+ DPRINTF(Drain, "All %u objects drained..\n", drainableCount());
+ exitSimLoop("Finished drain", 0);
+ }
+}
+
+
+void
+DrainManager::registerDrainable(Drainable *obj)
+{
+ std::lock_guard<std::mutex> lock(globalLock);
+ _allDrainable.insert(obj);
+}
+
void
-DrainManager::drainCycleDone()
+DrainManager::unregisterDrainable(Drainable *obj)
+{
+ std::lock_guard<std::mutex> lock(globalLock);
+ _allDrainable.erase(obj);
+}
+
+size_t
+DrainManager::drainableCount() const
{
- exitSimLoop("Finished drain", 0);
+ std::lock_guard<std::mutex> lock(globalLock);
+ return _allDrainable.size();
}
Drainable::Drainable()
- : _drainState(DrainState::Running)
+ : _drainManager(DrainManager::instance()),
+ _drainState(DrainState::Running)
{
+ _drainManager.registerDrainable(this);
}
Drainable::~Drainable()
{
+ _drainManager.unregisterDrainable(this);
}
void
#ifndef __SIM_DRAIN_HH__
#define __SIM_DRAIN_HH__
-#include <cassert>
-#include <vector>
+#include <atomic>
+#include <mutex>
+#include <unordered_set>
#include "base/flags.hh"
/**
* This class coordinates draining of a System.
*
- * When draining a System, we need to make sure that all SimObjects in
- * that system have drained their state before declaring the operation
- * to be successful. This class keeps track of how many objects are
- * still in the process of draining their state. Once it determines
- * that all objects have drained their state, it exits the simulation
- * loop.
+ * When draining the simulator, we need to make sure that all
+ * Drainable objects within the system have ended up in the drained
+ * state before declaring the operation to be successful. This class
+ * keeps track of how many objects are still in the process of
+ * draining. Once it determines that all objects have drained their
+ * state, it exits the simulation loop.
*
* @note A System might not be completely drained even though the
* DrainManager has caused the simulation loop to exit. Draining needs
*/
class DrainManager
{
- public:
+ private:
DrainManager();
- virtual ~DrainManager();
+#ifndef SWIG
+ DrainManager(DrainManager &) = delete;
+#endif
+ ~DrainManager();
+
+ public:
+ /** Get the singleton DrainManager instance */
+ static DrainManager &instance() { return _instance; }
+
+ /**
+ * Try to drain the system.
+ *
+ * Try to drain the system and return true if all objects are in a
+ * the Drained state at which point the whole simulator is in a
+ * consistent state and ready for checkpointing or CPU
+ * handover. The simulation script must continue simulating until
+ * the simulation loop returns "Finished drain", at which point
+ * this method should be called again. This cycle should continue
+ * until this method returns true.
+ *
+ * @return true if all objects were drained successfully, false if
+ * more simulation is needed.
+ */
+ bool tryDrain();
/**
- * Get the number of objects registered with this DrainManager
- * that are currently draining their state.
+ * Resume normal simulation in a Drained system.
+ */
+ void resume();
+
+ /**
+ * Run state fixups before a checkpoint restore operation
*
- * @return Number of objects currently draining.
+ * The drain state of an object isn't stored in a checkpoint since
+ * the whole system is always going to be in the Drained state
+ * when the checkpoint is created. When the checkpoint is restored
+ * at a later stage, recreated objects will be in the Running
+ * state since the state isn't stored in checkpoints. This method
+ * performs state fixups on all Drainable objects and the
+ * DrainManager itself.
*/
- unsigned int getCount() const { return _count; }
+ void preCheckpointRestore();
+
+ /** Check if the system is drained */
+ bool isDrained() { return _state == DrainState::Drained; }
- void setCount(int count) { _count = count; }
+ /** Get the simulators global drain state */
+ DrainState state() { return _state; }
/**
* Notify the DrainManager that a Drainable object has finished
* draining.
*/
- void signalDrainDone() {
- assert(_count > 0);
- if (--_count == 0)
- drainCycleDone();
- }
+ void signalDrainDone();
- protected:
+ public:
+ void registerDrainable(Drainable *obj);
+ void unregisterDrainable(Drainable *obj);
+
+ private:
/**
- * Callback when all registered Drainable objects have completed a
- * drain cycle.
+ * Thread-safe helper function to get the number of Drainable
+ * objects in a system.
*/
- virtual void drainCycleDone();
+ size_t drainableCount() const;
- /** Number of objects still draining. */
- unsigned int _count;
+ /** Lock protecting the set of drainable objects */
+ mutable std::mutex globalLock;
+
+ /** Set of all drainable objects */
+ std::unordered_set<Drainable *> _allDrainable;
+
+ /**
+ * Number of objects still draining. This is flagged atomic since
+ * it can be manipulated by SimObjects living in different
+ * threads.
+ */
+ std::atomic_uint _count;
+
+ /** Global simulator drain state */
+ DrainState _state;
+
+ /** Singleton instance of the drain manager */
+ static DrainManager _instance;
};
/**
* An object's internal state needs to be drained when creating a
* checkpoint, switching between CPU models, or switching between
* timing models. Once the internal state has been drained from
- * <i>all</i> objects in the system, the objects are serialized to
+ * <i>all</i> objects in the simulator, the objects are serialized to
* disc or the configuration change takes place. The process works as
* follows (see simulate.py for details):
*
* <ol>
- * <li>An instance of a DrainManager is created to keep track of how
- * many objects need to be drained. The object maintains an
- * internal counter that is decreased every time its
- * CountedDrainEvent::signalDrainDone() method is called. When the
- * counter reaches zero, the simulation is stopped.
- *
* <li>Call Drainable::drain() for every object in the
* system. Draining has completed if all of them return
* zero. Otherwise, the sum of the return values is loaded into
* manager is passed as an argument to the drain() method.
*
* <li>Continue simulation. When an object has finished draining its
- * internal state, it calls CountedDrainEvent::signalDrainDone()
- * on the manager. When the counter in the manager reaches zero,
- * the simulation stops.
+ * internal state, it calls DrainManager::signalDrainDone() on the
+ * manager. When the counter in the manager reaches zero, the
+ * simulation stops.
*
* <li>Check if any object still needs draining, if so repeat the
* process above.
*/
class Drainable
{
+ friend class DrainManager;
+
public:
Drainable();
virtual ~Drainable();
void setDrainState(DrainState new_state) { _drainState = new_state; }
private:
+ DrainManager &_drainManager;
DrainState _drainState;
};
-DrainManager *createDrainManager();
-void cleanupDrainManager(DrainManager *drain_manager);
-
#endif
if verbose:
print "Switching CPUs..."
print "Next CPU: %s" % type(next_cpu)
- m5.drain(system)
+ m5.drain()
if current_cpu != next_cpu:
m5.switchCpus(system, [ (current_cpu, next_cpu) ],
- do_drain=False, verbose=verbose)
+ verbose=verbose)
else:
print "Source CPU and destination CPU are the same, skipping..."
- m5.resume(system)
current_cpu = next_cpu
elif exit_cause == "target called exit()" or \
exit_cause == "m5_exit instruction encountered":