summaryrefslogtreecommitdiff
path: root/src/sim/drain.hh
diff options
context:
space:
mode:
Diffstat (limited to 'src/sim/drain.hh')
-rw-r--r--src/sim/drain.hh216
1 files changed, 216 insertions, 0 deletions
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