| /* |
| * 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(); |
| |
| /** |
| * Write back dirty buffers to memory using functional writes. |
| * |
| * After returning, an object implementing this method should have |
| * written all its dirty data back to memory. This method is |
| * typically used to prepare a system with caches for |
| * checkpointing. |
| */ |
| virtual void memWriteback() {}; |
| |
| /** |
| * Invalidate the contents of memory buffers. |
| * |
| * When the switching to hardware virtualized CPU models, we need |
| * to make sure that we don't have any cached state in the system |
| * that might become stale when we return. This method is used to |
| * flush all such state back to main memory. |
| * |
| * @warn This does <i>not</i> cause any dirty state to be written |
| * back to memory. |
| */ |
| virtual void memInvalidate() {}; |
| |
| State getDrainState() const { return _drainState; } |
| |
| protected: |
| void setDrainState(State new_state) { _drainState = new_state; } |
| |
| |
| private: |
| State _drainState; |
| |
| }; |
| |
| DrainManager *createDrainManager(); |
| void cleanupDrainManager(DrainManager *drain_manager); |
| |
| #endif |