diff options
Diffstat (limited to 'src/sim')
-rw-r--r-- | src/sim/SConscript | 1 | ||||
-rw-r--r-- | src/sim/drain.cc | 73 | ||||
-rw-r--r-- | src/sim/drain.hh | 216 | ||||
-rw-r--r-- | src/sim/serialize.hh | 8 | ||||
-rw-r--r-- | src/sim/sim_events.cc | 11 | ||||
-rw-r--r-- | src/sim/sim_object.cc | 10 | ||||
-rw-r--r-- | src/sim/sim_object.hh | 111 | ||||
-rw-r--r-- | src/sim/system.cc | 13 | ||||
-rw-r--r-- | src/sim/system.hh | 4 |
9 files changed, 321 insertions, 126 deletions
diff --git a/src/sim/SConscript b/src/sim/SConscript index 16eeb36d3..42993b90f 100644 --- a/src/sim/SConscript +++ b/src/sim/SConscript @@ -44,6 +44,7 @@ Source('init.cc') Source('main.cc', main=True, skip_lib=True) Source('root.cc') Source('serialize.cc') +Source('drain.cc') Source('sim_events.cc') Source('sim_object.cc') Source('simulate.cc') diff --git a/src/sim/drain.cc b/src/sim/drain.cc new file mode 100644 index 000000000..3daf762f6 --- /dev/null +++ b/src/sim/drain.cc @@ -0,0 +1,73 @@ +/* + * Copyright (c) 2012 ARM Limited + * All rights reserved + * + * The license below extends only to copyright in the software and shall + * not be construed as granting a license to any other intellectual + * property including but not limited to intellectual property relating + * to a hardware implementation of the functionality of the software + * licensed hereunder. You may use the software subject to the license + * terms below provided that you ensure that this notice is replicated + * unmodified and in its entirety in all distributions of the software, + * modified or unmodified, in source code or in binary form. + * + * 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: Andreas Sandberg + */ + +#include "sim/drain.hh" +#include "sim/sim_exit.hh" + +DrainManager::DrainManager() + : _count(0) +{ +} + +DrainManager::~DrainManager() +{ +} + +void +DrainManager::drainCycleDone() +{ + exitSimLoop("Finished drain", 0); +} + + + +Drainable::Drainable() + : _drainState(Running) +{ +} + +Drainable::~Drainable() +{ +} + +void +Drainable::drainResume() +{ + _drainState = Running; +} diff --git a/src/sim/drain.hh b/src/sim/drain.hh new file mode 100644 index 000000000..252022bc7 --- /dev/null +++ b/src/sim/drain.hh @@ -0,0 +1,216 @@ +/* + * Copyright (c) 2012 ARM Limited + * All rights reserved + * + * The license below extends only to copyright in the software and shall + * not be construed as granting a license to any other intellectual + * property including but not limited to intellectual property relating + * to a hardware implementation of the functionality of the software + * licensed hereunder. You may use the software subject to the license + * terms below provided that you ensure that this notice is replicated + * unmodified and in its entirety in all distributions of the software, + * modified or unmodified, in source code or in binary form. + * + * 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: Andreas Sandberg + */ + +#ifndef __SIM_DRAIN_HH__ +#define __SIM_DRAIN_HH__ + +#include <cassert> +#include <vector> + +#include "base/flags.hh" + +class Event; + +/** + * 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. + * + * @note A System might not be completely drained even though the + * DrainManager has caused the simulation loop to exit. Draining needs + * to be restarted until all Drainable objects declare that they don't + * need further simulation to be completely drained. See Drainable for + * more information. + */ +class DrainManager +{ + public: + DrainManager(); + virtual ~DrainManager(); + + /** + * Get the number of objects registered with this DrainManager + * that are currently draining their state. + * + * @return Number of objects currently draining. + */ + unsigned int getCount() const { return _count; } + + void setCount(int count) { _count = count; } + + /** + * Notify the DrainManager that a Drainable object has finished + * draining. + */ + void signalDrainDone() { + assert(_count > 0); + if (--_count == 0) + drainCycleDone(); + } + + protected: + /** + * Callback when all registered Drainable objects have completed a + * drain cycle. + */ + virtual void drainCycleDone(); + + /** Number of objects still draining. */ + unsigned int _count; +}; + +/** + * Interface for objects that might require draining before + * checkpointing. + * + * 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 + * 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 + * the counter of the DrainManager. A pointer to the drain + * 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. + * + * <li>Check if any object still needs draining, if so repeat the + * process above. + * + * <li>Serialize objects, switch CPU model, or change timing model. + * + * <li>Call Drainable::drainResume() and continue the simulation. + * </ol> + * + */ +class Drainable +{ + public: + /** + * Object drain/handover states + * + * An object starts out in the Running state. When the simulator + * prepares to take a snapshot or prepares a CPU for handover, it + * calls the drain() method to transfer the object into the + * Draining or Drained state. If any object enters the Draining + * state (drain() returning >0), simulation continues until it all + * objects have entered the Drained state. + * + * Before resuming simulation, the simulator calls resume() to + * transfer the object to the Running state. + * + * \note Even though the state of an object (visible to the rest + * of the world through getState()) could be used to determine if + * all objects have entered the Drained state, the protocol is + * actually a bit more elaborate. See drain() for details. + */ + enum State { + Running, /** Running normally */ + Draining, /** Draining buffers pending serialization/handover */ + Drained /** Buffers drained, ready for serialization/handover */ + }; + + Drainable(); + virtual ~Drainable(); + + /** + * Determine if an object needs draining and register a + * DrainManager. + * + * When draining the state of an object, the simulator calls drain + * with a pointer to a drain manager. If the object does not need + * further simulation to drain internal buffers, it switched to + * the Drained state and returns 0, otherwise it switches to the + * Draining state and returns the number of times that it will + * call Event::process() on the drain event. Most objects are + * expected to return either 0 or 1. + * + * @note An object that has entered the Drained state can be + * disturbed by other objects in the system and consequently be + * forced to enter the Draining state again. The simulator + * therefore repeats the draining process until all objects return + * 0 on the first call to drain(). + * + * @param drainManager DrainManager to use to inform the simulator + * when draining has completed. + * + * @return 0 if the object is ready for serialization now, >0 if + * it needs further simulation. + */ + virtual unsigned int drain(DrainManager *drainManager) = 0; + + /** + * Resume execution after a successful drain. + * + * @note This method is normally only called from the simulation + * scripts. + */ + virtual void drainResume(); + + State getDrainState() const { return _drainState; } + + protected: + void setDrainState(State new_state) { _drainState = new_state; } + + + private: + State _drainState; + +}; + +#endif diff --git a/src/sim/serialize.hh b/src/sim/serialize.hh index 531b2e1cd..9ee34fe80 100644 --- a/src/sim/serialize.hh +++ b/src/sim/serialize.hh @@ -144,8 +144,14 @@ void fromSimObject(T &t, SimObject *s) fromSimObject(objptr, sptr); \ } while (0) -/* +/** * Basic support for object serialization. + * + * @note Many objects that support serialization need to be put in a + * consistent state when serialization takes place. We refer to the + * action of forcing an object into a consistent state as + * 'draining'. Objects that need draining inherit from Drainable. See + * Drainable for more information. */ class Serializable { diff --git a/src/sim/sim_events.cc b/src/sim/sim_events.cc index a77e8b103..2354e89f7 100644 --- a/src/sim/sim_events.cc +++ b/src/sim/sim_events.cc @@ -83,17 +83,6 @@ exitSimLoop(const std::string &message, int exit_code, Tick when, Tick repeat) mainEventQueue.schedule(event, when); } -CountedDrainEvent::CountedDrainEvent() - : count(0) -{ } - -void -CountedDrainEvent::process() -{ - if (--count == 0) - exitSimLoop("Finished drain", 0); -} - // // constructor: automatically schedules at specified time // diff --git a/src/sim/sim_object.cc b/src/sim/sim_object.cc index 32e936ff2..345fb85cb 100644 --- a/src/sim/sim_object.cc +++ b/src/sim/sim_object.cc @@ -67,7 +67,6 @@ SimObject::SimObject(const Params *p) #endif simObjectList.push_back(this); - state = Running; } void @@ -151,17 +150,12 @@ debugObjectBreak(const char *objs) #endif unsigned int -SimObject::drain(Event *drain_event) +SimObject::drain(DrainManager *drain_manager) { - state = Drained; + setDrainState(Drained); return 0; } -void -SimObject::resume() -{ - state = Running; -} SimObject * SimObject::find(const char *name) diff --git a/src/sim/sim_object.hh b/src/sim/sim_object.hh index c1238e23f..f04289e2f 100644 --- a/src/sim/sim_object.hh +++ b/src/sim/sim_object.hh @@ -45,6 +45,7 @@ #include "enums/MemoryMode.hh" #include "params/SimObject.hh" +#include "sim/drain.hh" #include "sim/eventq.hh" #include "sim/serialize.hh" @@ -72,40 +73,7 @@ class Event; * </ul> * <li>SimObject::resetStats() * <li>SimObject::startup() - * <li>SimObject::resume() if resuming from a checkpoint. - * </ol> - * - * 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 - * disc or the configuration change takes place. The process works as - * follows (see simulate.py for details): - * - * <ol> - * <li>An instance of a CountedDrainEvent 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::process() method is called. When the counter - * reaches zero, the simulation is stopped. - * - * <li>Call SimObject::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 - * the counter of the CountedDrainEvent. A pointer of the drain - * event is passed as an argument to the drain() method. - * - * <li>Continue simulation. When an object has finished draining its - * internal state, it calls CountedDrainEvent::process() on the - * CountedDrainEvent. When counter in the CountedDrainEvent reaches - * zero, the simulation stops. - * - * <li>Check if any object still needs draining, if so repeat the - * process above. - * - * <li>Serialize objects, switch CPU model, or change timing model. - * - * <li>Call SimObject::resume() and continue the simulation. + * <li>Drainable::drainResume() if resuming from a checkpoint. * </ol> * * @note Whenever a method is called on all objects in the simulator's @@ -114,42 +82,8 @@ class Event; * SimObject.py). This has the effect of calling the method on the * parent node <i>before</i> its children. */ -class SimObject : public EventManager, public Serializable +class SimObject : public EventManager, public Serializable, public Drainable { - public: - /** - * Object drain/handover states - * - * An object starts out in the Running state. When the simulator - * prepares to take a snapshot or prepares a CPU for handover, it - * calls the drain() method to transfer the object into the - * Draining or Drained state. If any object enters the Draining - * state (drain() returning >0), simulation continues until it all - * objects have entered the Drained. - * - * The before resuming simulation, the simulator calls resume() to - * transfer the object to the Running state. - * - * \note Even though the state of an object (visible to the rest - * of the world through getState()) could be used to determine if - * all objects have entered the Drained state, the protocol is - * actually a bit more elaborate. See drain() for details. - */ - enum State { - Running, /** Running normally */ - Draining, /** Draining buffers pending serialization/handover */ - Drained /** Buffers drained, ready for serialization/handover */ - }; - - private: - State state; - - protected: - void changeState(State new_state) { state = new_state; } - - public: - State getState() { return state; } - private: typedef std::vector<SimObject *> SimObjectList; @@ -217,43 +151,16 @@ class SimObject : public EventManager, public Serializable virtual void startup(); /** - * Serialize all SimObjects in the system. + * Provide a default implementation of the drain interface that + * simply returns 0 (draining completed) and sets the drain state + * to Drained. */ - static void serializeAll(std::ostream &os); + unsigned int drain(DrainManager *drainManger); /** - * Determine if an object needs draining and register a drain - * event. - * - * When draining the state of an object, the simulator calls drain - * with a pointer to a drain event. If the object does not need - * further simulation to drain internal buffers, it switched to - * the Drained state and returns 0, otherwise it switches to the - * Draining state and returns the number of times that it will - * call Event::process() on the drain event. Most objects are - * expected to return either 0 or 1. - * - * The default implementation simply switches to the Drained state - * and returns 0. - * - * @note An object that has entered the Drained state can be - * disturbed by other objects in the system and consequently be - * forced to enter the Draining state again. The simulator - * therefore repeats the draining process until all objects return - * 0 on the first call to drain(). - * - * @param drain_event Event to use to inform the simulator when - * the draining has completed. - * - * @return 0 if the object is ready for serialization now, >0 if - * it needs further simulation. - */ - virtual unsigned int drain(Event *drain_event); - - /** - * Switch an object in the Drained stated into the Running state. + * Serialize all SimObjects in the system. */ - virtual void resume(); + static void serializeAll(std::ostream &os); #ifdef DEBUG public: diff --git a/src/sim/system.cc b/src/sim/system.cc index 5ec7f4b30..259ed3e88 100644 --- a/src/sim/system.cc +++ b/src/sim/system.cc @@ -181,7 +181,7 @@ System::getMasterPort(const std::string &if_name, PortID idx) void System::setMemoryMode(Enums::MemoryMode mode) { - assert(getState() == Drained); + assert(getDrainState() == Drainable::Drained); memoryMode = mode; } @@ -328,10 +328,17 @@ System::isMemAddr(Addr addr) const return physmem.isMemAddr(addr); } +unsigned int +System::drain(DrainManager *dm) +{ + setDrainState(Drainable::Drained); + return 0; +} + void -System::resume() +System::drainResume() { - SimObject::resume(); + Drainable::drainResume(); totalNumInsts = 0; } diff --git a/src/sim/system.hh b/src/sim/system.hh index 645ef8af2..d1b79bbf4 100644 --- a/src/sim/system.hh +++ b/src/sim/system.hh @@ -382,7 +382,9 @@ class System : public MemObject void serialize(std::ostream &os); void unserialize(Checkpoint *cp, const std::string §ion); - virtual void resume(); + + unsigned int drain(DrainManager *dm); + void drainResume(); public: Counter totalNumInsts; |