2012-11-02 17:32:01 +01:00
|
|
|
/*
|
|
|
|
* 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();
|
|
|
|
|
2012-11-02 17:32:02 +01:00
|
|
|
/**
|
|
|
|
* 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() {};
|
|
|
|
|
2012-11-02 17:32:01 +01:00
|
|
|
State getDrainState() const { return _drainState; }
|
|
|
|
|
|
|
|
protected:
|
|
|
|
void setDrainState(State new_state) { _drainState = new_state; }
|
|
|
|
|
|
|
|
|
|
|
|
private:
|
|
|
|
State _drainState;
|
|
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
#endif
|