drain.hh revision 9554
19342SAndreas.Sandberg@arm.com/*
29342SAndreas.Sandberg@arm.com * Copyright (c) 2012 ARM Limited
39342SAndreas.Sandberg@arm.com * All rights reserved
49342SAndreas.Sandberg@arm.com *
59342SAndreas.Sandberg@arm.com * The license below extends only to copyright in the software and shall
69342SAndreas.Sandberg@arm.com * not be construed as granting a license to any other intellectual
79342SAndreas.Sandberg@arm.com * property including but not limited to intellectual property relating
89342SAndreas.Sandberg@arm.com * to a hardware implementation of the functionality of the software
99342SAndreas.Sandberg@arm.com * licensed hereunder.  You may use the software subject to the license
109342SAndreas.Sandberg@arm.com * terms below provided that you ensure that this notice is replicated
119342SAndreas.Sandberg@arm.com * unmodified and in its entirety in all distributions of the software,
129342SAndreas.Sandberg@arm.com * modified or unmodified, in source code or in binary form.
139342SAndreas.Sandberg@arm.com *
149342SAndreas.Sandberg@arm.com * Redistribution and use in source and binary forms, with or without
159342SAndreas.Sandberg@arm.com * modification, are permitted provided that the following conditions are
169342SAndreas.Sandberg@arm.com * met: redistributions of source code must retain the above copyright
179342SAndreas.Sandberg@arm.com * notice, this list of conditions and the following disclaimer;
189342SAndreas.Sandberg@arm.com * redistributions in binary form must reproduce the above copyright
199342SAndreas.Sandberg@arm.com * notice, this list of conditions and the following disclaimer in the
209342SAndreas.Sandberg@arm.com * documentation and/or other materials provided with the distribution;
219342SAndreas.Sandberg@arm.com * neither the name of the copyright holders nor the names of its
229342SAndreas.Sandberg@arm.com * contributors may be used to endorse or promote products derived from
239342SAndreas.Sandberg@arm.com * this software without specific prior written permission.
249342SAndreas.Sandberg@arm.com *
259342SAndreas.Sandberg@arm.com * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
269342SAndreas.Sandberg@arm.com * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
279342SAndreas.Sandberg@arm.com * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
289342SAndreas.Sandberg@arm.com * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
299342SAndreas.Sandberg@arm.com * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
309342SAndreas.Sandberg@arm.com * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
319342SAndreas.Sandberg@arm.com * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
329342SAndreas.Sandberg@arm.com * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
339342SAndreas.Sandberg@arm.com * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
349342SAndreas.Sandberg@arm.com * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
359342SAndreas.Sandberg@arm.com * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
369342SAndreas.Sandberg@arm.com *
379342SAndreas.Sandberg@arm.com * Authors: Andreas Sandberg
389342SAndreas.Sandberg@arm.com */
399342SAndreas.Sandberg@arm.com
409342SAndreas.Sandberg@arm.com#ifndef __SIM_DRAIN_HH__
419342SAndreas.Sandberg@arm.com#define __SIM_DRAIN_HH__
429342SAndreas.Sandberg@arm.com
439342SAndreas.Sandberg@arm.com#include <cassert>
449342SAndreas.Sandberg@arm.com#include <vector>
459342SAndreas.Sandberg@arm.com
469342SAndreas.Sandberg@arm.com#include "base/flags.hh"
479342SAndreas.Sandberg@arm.com
489342SAndreas.Sandberg@arm.comclass Event;
499342SAndreas.Sandberg@arm.com
509342SAndreas.Sandberg@arm.com/**
519342SAndreas.Sandberg@arm.com * This class coordinates draining of a System.
529342SAndreas.Sandberg@arm.com *
539342SAndreas.Sandberg@arm.com * When draining a System, we need to make sure that all SimObjects in
549342SAndreas.Sandberg@arm.com * that system have drained their state before declaring the operation
559342SAndreas.Sandberg@arm.com * to be successful. This class keeps track of how many objects are
569342SAndreas.Sandberg@arm.com * still in the process of draining their state. Once it determines
579342SAndreas.Sandberg@arm.com * that all objects have drained their state, it exits the simulation
589342SAndreas.Sandberg@arm.com * loop.
599342SAndreas.Sandberg@arm.com *
609342SAndreas.Sandberg@arm.com * @note A System might not be completely drained even though the
619342SAndreas.Sandberg@arm.com * DrainManager has caused the simulation loop to exit. Draining needs
629342SAndreas.Sandberg@arm.com * to be restarted until all Drainable objects declare that they don't
639342SAndreas.Sandberg@arm.com * need further simulation to be completely drained. See Drainable for
649342SAndreas.Sandberg@arm.com * more information.
659342SAndreas.Sandberg@arm.com */
669342SAndreas.Sandberg@arm.comclass DrainManager
679342SAndreas.Sandberg@arm.com{
689342SAndreas.Sandberg@arm.com  public:
699342SAndreas.Sandberg@arm.com    DrainManager();
709342SAndreas.Sandberg@arm.com    virtual ~DrainManager();
719342SAndreas.Sandberg@arm.com
729342SAndreas.Sandberg@arm.com    /**
739342SAndreas.Sandberg@arm.com     * Get the number of objects registered with this DrainManager
749342SAndreas.Sandberg@arm.com     * that are currently draining their state.
759342SAndreas.Sandberg@arm.com     *
769342SAndreas.Sandberg@arm.com     * @return Number of objects currently draining.
779342SAndreas.Sandberg@arm.com     */
789342SAndreas.Sandberg@arm.com    unsigned int getCount() const { return _count; }
799342SAndreas.Sandberg@arm.com
809342SAndreas.Sandberg@arm.com    void setCount(int count) { _count = count; }
819342SAndreas.Sandberg@arm.com
829342SAndreas.Sandberg@arm.com    /**
839342SAndreas.Sandberg@arm.com     * Notify the DrainManager that a Drainable object has finished
849342SAndreas.Sandberg@arm.com     * draining.
859342SAndreas.Sandberg@arm.com     */
869342SAndreas.Sandberg@arm.com    void signalDrainDone() {
879342SAndreas.Sandberg@arm.com        assert(_count > 0);
889342SAndreas.Sandberg@arm.com        if (--_count == 0)
899342SAndreas.Sandberg@arm.com            drainCycleDone();
909342SAndreas.Sandberg@arm.com    }
919342SAndreas.Sandberg@arm.com
929342SAndreas.Sandberg@arm.com  protected:
939342SAndreas.Sandberg@arm.com    /**
949342SAndreas.Sandberg@arm.com     * Callback when all registered Drainable objects have completed a
959342SAndreas.Sandberg@arm.com     * drain cycle.
969342SAndreas.Sandberg@arm.com     */
979342SAndreas.Sandberg@arm.com    virtual void drainCycleDone();
989342SAndreas.Sandberg@arm.com
999342SAndreas.Sandberg@arm.com    /** Number of objects still draining. */
1009342SAndreas.Sandberg@arm.com    unsigned int _count;
1019342SAndreas.Sandberg@arm.com};
1029342SAndreas.Sandberg@arm.com
1039342SAndreas.Sandberg@arm.com/**
1049342SAndreas.Sandberg@arm.com * Interface for objects that might require draining before
1059342SAndreas.Sandberg@arm.com * checkpointing.
1069342SAndreas.Sandberg@arm.com *
1079342SAndreas.Sandberg@arm.com * An object's internal state needs to be drained when creating a
1089342SAndreas.Sandberg@arm.com * checkpoint, switching between CPU models, or switching between
1099342SAndreas.Sandberg@arm.com * timing models. Once the internal state has been drained from
1109342SAndreas.Sandberg@arm.com * <i>all</i> objects in the system, the objects are serialized to
1119342SAndreas.Sandberg@arm.com * disc or the configuration change takes place. The process works as
1129342SAndreas.Sandberg@arm.com * follows (see simulate.py for details):
1139342SAndreas.Sandberg@arm.com *
1149342SAndreas.Sandberg@arm.com * <ol>
1159342SAndreas.Sandberg@arm.com * <li>An instance of a DrainManager is created to keep track of how
1169342SAndreas.Sandberg@arm.com *     many objects need to be drained. The object maintains an
1179342SAndreas.Sandberg@arm.com *     internal counter that is decreased every time its
1189342SAndreas.Sandberg@arm.com *     CountedDrainEvent::signalDrainDone() method is called. When the
1199342SAndreas.Sandberg@arm.com *     counter reaches zero, the simulation is stopped.
1209342SAndreas.Sandberg@arm.com *
1219342SAndreas.Sandberg@arm.com * <li>Call Drainable::drain() for every object in the
1229342SAndreas.Sandberg@arm.com *     system. Draining has completed if all of them return
1239342SAndreas.Sandberg@arm.com *     zero. Otherwise, the sum of the return values is loaded into
1249342SAndreas.Sandberg@arm.com *     the counter of the DrainManager. A pointer to the drain
1259342SAndreas.Sandberg@arm.com *     manager is passed as an argument to the drain() method.
1269342SAndreas.Sandberg@arm.com *
1279342SAndreas.Sandberg@arm.com * <li>Continue simulation. When an object has finished draining its
1289342SAndreas.Sandberg@arm.com *     internal state, it calls CountedDrainEvent::signalDrainDone()
1299342SAndreas.Sandberg@arm.com *     on the manager. When the counter in the manager reaches zero,
1309342SAndreas.Sandberg@arm.com *     the simulation stops.
1319342SAndreas.Sandberg@arm.com *
1329342SAndreas.Sandberg@arm.com * <li>Check if any object still needs draining, if so repeat the
1339342SAndreas.Sandberg@arm.com *     process above.
1349342SAndreas.Sandberg@arm.com *
1359342SAndreas.Sandberg@arm.com * <li>Serialize objects, switch CPU model, or change timing model.
1369342SAndreas.Sandberg@arm.com *
1379342SAndreas.Sandberg@arm.com * <li>Call Drainable::drainResume() and continue the simulation.
1389342SAndreas.Sandberg@arm.com * </ol>
1399342SAndreas.Sandberg@arm.com *
1409342SAndreas.Sandberg@arm.com */
1419342SAndreas.Sandberg@arm.comclass Drainable
1429342SAndreas.Sandberg@arm.com{
1439342SAndreas.Sandberg@arm.com  public:
1449342SAndreas.Sandberg@arm.com    /**
1459342SAndreas.Sandberg@arm.com     * Object drain/handover states
1469342SAndreas.Sandberg@arm.com     *
1479342SAndreas.Sandberg@arm.com     * An object starts out in the Running state. When the simulator
1489342SAndreas.Sandberg@arm.com     * prepares to take a snapshot or prepares a CPU for handover, it
1499342SAndreas.Sandberg@arm.com     * calls the drain() method to transfer the object into the
1509342SAndreas.Sandberg@arm.com     * Draining or Drained state. If any object enters the Draining
1519342SAndreas.Sandberg@arm.com     * state (drain() returning >0), simulation continues until it all
1529342SAndreas.Sandberg@arm.com     * objects have entered the Drained state.
1539342SAndreas.Sandberg@arm.com     *
1549342SAndreas.Sandberg@arm.com     * Before resuming simulation, the simulator calls resume() to
1559342SAndreas.Sandberg@arm.com     * transfer the object to the Running state.
1569342SAndreas.Sandberg@arm.com     *
1579342SAndreas.Sandberg@arm.com     * \note Even though the state of an object (visible to the rest
1589342SAndreas.Sandberg@arm.com     * of the world through getState()) could be used to determine if
1599342SAndreas.Sandberg@arm.com     * all objects have entered the Drained state, the protocol is
1609342SAndreas.Sandberg@arm.com     * actually a bit more elaborate. See drain() for details.
1619342SAndreas.Sandberg@arm.com     */
1629342SAndreas.Sandberg@arm.com    enum State {
1639342SAndreas.Sandberg@arm.com        Running,  /** Running normally */
1649342SAndreas.Sandberg@arm.com        Draining, /** Draining buffers pending serialization/handover */
1659342SAndreas.Sandberg@arm.com        Drained   /** Buffers drained, ready for serialization/handover */
1669342SAndreas.Sandberg@arm.com    };
1679342SAndreas.Sandberg@arm.com
1689342SAndreas.Sandberg@arm.com    Drainable();
1699342SAndreas.Sandberg@arm.com    virtual ~Drainable();
1709342SAndreas.Sandberg@arm.com
1719342SAndreas.Sandberg@arm.com    /**
1729342SAndreas.Sandberg@arm.com     * Determine if an object needs draining and register a
1739342SAndreas.Sandberg@arm.com     * DrainManager.
1749342SAndreas.Sandberg@arm.com     *
1759342SAndreas.Sandberg@arm.com     * When draining the state of an object, the simulator calls drain
1769342SAndreas.Sandberg@arm.com     * with a pointer to a drain manager. If the object does not need
1779342SAndreas.Sandberg@arm.com     * further simulation to drain internal buffers, it switched to
1789342SAndreas.Sandberg@arm.com     * the Drained state and returns 0, otherwise it switches to the
1799342SAndreas.Sandberg@arm.com     * Draining state and returns the number of times that it will
1809342SAndreas.Sandberg@arm.com     * call Event::process() on the drain event. Most objects are
1819342SAndreas.Sandberg@arm.com     * expected to return either 0 or 1.
1829342SAndreas.Sandberg@arm.com     *
1839342SAndreas.Sandberg@arm.com     * @note An object that has entered the Drained state can be
1849342SAndreas.Sandberg@arm.com     * disturbed by other objects in the system and consequently be
1859342SAndreas.Sandberg@arm.com     * forced to enter the Draining state again. The simulator
1869342SAndreas.Sandberg@arm.com     * therefore repeats the draining process until all objects return
1879342SAndreas.Sandberg@arm.com     * 0 on the first call to drain().
1889342SAndreas.Sandberg@arm.com     *
1899342SAndreas.Sandberg@arm.com     * @param drainManager DrainManager to use to inform the simulator
1909342SAndreas.Sandberg@arm.com     * when draining has completed.
1919342SAndreas.Sandberg@arm.com     *
1929342SAndreas.Sandberg@arm.com     * @return 0 if the object is ready for serialization now, >0 if
1939342SAndreas.Sandberg@arm.com     * it needs further simulation.
1949342SAndreas.Sandberg@arm.com     */
1959342SAndreas.Sandberg@arm.com    virtual unsigned int drain(DrainManager *drainManager) = 0;
1969342SAndreas.Sandberg@arm.com
1979342SAndreas.Sandberg@arm.com    /**
1989342SAndreas.Sandberg@arm.com     * Resume execution after a successful drain.
1999342SAndreas.Sandberg@arm.com     *
2009342SAndreas.Sandberg@arm.com     * @note This method is normally only called from the simulation
2019342SAndreas.Sandberg@arm.com     * scripts.
2029342SAndreas.Sandberg@arm.com     */
2039342SAndreas.Sandberg@arm.com    virtual void drainResume();
2049342SAndreas.Sandberg@arm.com
2059346SAndreas.Sandberg@arm.com    /**
2069346SAndreas.Sandberg@arm.com     * Write back dirty buffers to memory using functional writes.
2079346SAndreas.Sandberg@arm.com     *
2089346SAndreas.Sandberg@arm.com     * After returning, an object implementing this method should have
2099346SAndreas.Sandberg@arm.com     * written all its dirty data back to memory. This method is
2109346SAndreas.Sandberg@arm.com     * typically used to prepare a system with caches for
2119346SAndreas.Sandberg@arm.com     * checkpointing.
2129346SAndreas.Sandberg@arm.com     */
2139346SAndreas.Sandberg@arm.com    virtual void memWriteback() {};
2149346SAndreas.Sandberg@arm.com
2159346SAndreas.Sandberg@arm.com    /**
2169346SAndreas.Sandberg@arm.com     * Invalidate the contents of memory buffers.
2179346SAndreas.Sandberg@arm.com     *
2189346SAndreas.Sandberg@arm.com     * When the switching to hardware virtualized CPU models, we need
2199346SAndreas.Sandberg@arm.com     * to make sure that we don't have any cached state in the system
2209346SAndreas.Sandberg@arm.com     * that might become stale when we return. This method is used to
2219346SAndreas.Sandberg@arm.com     * flush all such state back to main memory.
2229346SAndreas.Sandberg@arm.com     *
2239346SAndreas.Sandberg@arm.com     * @warn This does <i>not</i> cause any dirty state to be written
2249346SAndreas.Sandberg@arm.com     * back to memory.
2259346SAndreas.Sandberg@arm.com     */
2269346SAndreas.Sandberg@arm.com    virtual void memInvalidate() {};
2279346SAndreas.Sandberg@arm.com
2289342SAndreas.Sandberg@arm.com    State getDrainState() const { return _drainState; }
2299342SAndreas.Sandberg@arm.com
2309342SAndreas.Sandberg@arm.com  protected:
2319342SAndreas.Sandberg@arm.com    void setDrainState(State new_state) { _drainState = new_state; }
2329342SAndreas.Sandberg@arm.com
2339342SAndreas.Sandberg@arm.com
2349342SAndreas.Sandberg@arm.com  private:
2359342SAndreas.Sandberg@arm.com    State _drainState;
2369342SAndreas.Sandberg@arm.com
2379342SAndreas.Sandberg@arm.com};
2389342SAndreas.Sandberg@arm.com
2399554Sandreas.hansson@arm.comDrainManager *createDrainManager();
2409554Sandreas.hansson@arm.comvoid cleanupDrainManager(DrainManager *drain_manager);
2419554Sandreas.hansson@arm.com
2429342SAndreas.Sandberg@arm.com#endif
243