|  | /* | 
|  | * 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 |