drain.hh revision 11360
1955SN/A/*
2955SN/A * Copyright (c) 2012, 2015 ARM Limited
311408Sandreas.sandberg@arm.com * All rights reserved
49812Sandreas.hansson@arm.com *
59812Sandreas.hansson@arm.com * The license below extends only to copyright in the software and shall
69812Sandreas.hansson@arm.com * not be construed as granting a license to any other intellectual
79812Sandreas.hansson@arm.com * property including but not limited to intellectual property relating
89812Sandreas.hansson@arm.com * to a hardware implementation of the functionality of the software
99812Sandreas.hansson@arm.com * licensed hereunder.  You may use the software subject to the license
109812Sandreas.hansson@arm.com * terms below provided that you ensure that this notice is replicated
119812Sandreas.hansson@arm.com * unmodified and in its entirety in all distributions of the software,
129812Sandreas.hansson@arm.com * modified or unmodified, in source code or in binary form.
139812Sandreas.hansson@arm.com *
149812Sandreas.hansson@arm.com * Redistribution and use in source and binary forms, with or without
157816Ssteve.reinhardt@amd.com * modification, are permitted provided that the following conditions are
165871Snate@binkert.org * met: redistributions of source code must retain the above copyright
171762SN/A * notice, this list of conditions and the following disclaimer;
18955SN/A * redistributions in binary form must reproduce the above copyright
19955SN/A * notice, this list of conditions and the following disclaimer in the
20955SN/A * documentation and/or other materials provided with the distribution;
21955SN/A * neither the name of the copyright holders nor the names of its
22955SN/A * contributors may be used to endorse or promote products derived from
23955SN/A * this software without specific prior written permission.
24955SN/A *
25955SN/A * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
26955SN/A * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
27955SN/A * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
28955SN/A * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
29955SN/A * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
30955SN/A * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
31955SN/A * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
32955SN/A * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
33955SN/A * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
34955SN/A * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
35955SN/A * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
36955SN/A *
37955SN/A * Authors: Andreas Sandberg
38955SN/A */
39955SN/A
40955SN/A#ifndef __SIM_DRAIN_HH__
41955SN/A#define __SIM_DRAIN_HH__
422665Ssaidi@eecs.umich.edu
432665Ssaidi@eecs.umich.edu#include <atomic>
445863Snate@binkert.org#include <mutex>
45955SN/A#include <unordered_set>
46955SN/A
47955SN/A#include "base/flags.hh"
48955SN/A
49955SN/Aclass Drainable;
508878Ssteve.reinhardt@amd.com
512632Sstever@eecs.umich.edu#ifndef SWIG // SWIG doesn't support strongly typed enums
528878Ssteve.reinhardt@amd.com/**
532632Sstever@eecs.umich.edu * Object drain/handover states
54955SN/A *
558878Ssteve.reinhardt@amd.com * An object starts out in the Running state. When the simulator
562632Sstever@eecs.umich.edu * prepares to take a snapshot or prepares a CPU for handover, it
572761Sstever@eecs.umich.edu * calls the drain() method to transfer the object into the Draining
582632Sstever@eecs.umich.edu * or Drained state. If any object enters the Draining state
592632Sstever@eecs.umich.edu * (Drainable::drain() returning >0), simulation continues until it
602632Sstever@eecs.umich.edu * all objects have entered the Drained state.
612761Sstever@eecs.umich.edu *
622761Sstever@eecs.umich.edu * Before resuming simulation, the simulator calls resume() to
632761Sstever@eecs.umich.edu * transfer the object to the Running state.
648878Ssteve.reinhardt@amd.com *
658878Ssteve.reinhardt@amd.com * \note Even though the state of an object (visible to the rest of
662761Sstever@eecs.umich.edu * the world through Drainable::getState()) could be used to determine
672761Sstever@eecs.umich.edu * if all objects have entered the Drained state, the protocol is
682761Sstever@eecs.umich.edu * actually a bit more elaborate. See Drainable::drain() for details.
692761Sstever@eecs.umich.edu */
702761Sstever@eecs.umich.eduenum class DrainState {
718878Ssteve.reinhardt@amd.com    Running,  /** Running normally */
728878Ssteve.reinhardt@amd.com    Draining, /** Draining buffers pending serialization/handover */
732632Sstever@eecs.umich.edu    Drained   /** Buffers drained, ready for serialization/handover */
742632Sstever@eecs.umich.edu};
758878Ssteve.reinhardt@amd.com#endif
768878Ssteve.reinhardt@amd.com
772632Sstever@eecs.umich.edu/**
78955SN/A * This class coordinates draining of a System.
79955SN/A *
80955SN/A * When draining the simulator, we need to make sure that all
815863Snate@binkert.org * Drainable objects within the system have ended up in the drained
825863Snate@binkert.org * state before declaring the operation to be successful. This class
835863Snate@binkert.org * keeps track of how many objects are still in the process of
845863Snate@binkert.org * draining. Once it determines that all objects have drained their
855863Snate@binkert.org * state, it exits the simulation loop.
865863Snate@binkert.org *
875863Snate@binkert.org * @note A System might not be completely drained even though the
885863Snate@binkert.org * DrainManager has caused the simulation loop to exit. Draining needs
895863Snate@binkert.org * to be restarted until all Drainable objects declare that they don't
905863Snate@binkert.org * need further simulation to be completely drained. See Drainable for
915863Snate@binkert.org * more information.
928878Ssteve.reinhardt@amd.com */
935863Snate@binkert.orgclass DrainManager
945863Snate@binkert.org{
955863Snate@binkert.org  private:
969812Sandreas.hansson@arm.com    DrainManager();
979812Sandreas.hansson@arm.com#ifndef SWIG
985863Snate@binkert.org    DrainManager(DrainManager &) = delete;
999812Sandreas.hansson@arm.com#endif
1005863Snate@binkert.org    ~DrainManager();
1015863Snate@binkert.org
1025863Snate@binkert.org  public:
1039812Sandreas.hansson@arm.com    /** Get the singleton DrainManager instance */
1049812Sandreas.hansson@arm.com    static DrainManager &instance() { return _instance; }
1055863Snate@binkert.org
1065863Snate@binkert.org    /**
1078878Ssteve.reinhardt@amd.com     * Try to drain the system.
1085863Snate@binkert.org     *
1095863Snate@binkert.org     * Try to drain the system and return true if all objects are in a
1105863Snate@binkert.org     * the Drained state at which point the whole simulator is in a
1116654Snate@binkert.org     * consistent state and ready for checkpointing or CPU
11210196SCurtis.Dunham@arm.com     * handover. The simulation script must continue simulating until
113955SN/A     * the simulation loop returns "Finished drain", at which point
1145396Ssaidi@eecs.umich.edu     * this method should be called again. This cycle should continue
11511401Sandreas.sandberg@arm.com     * until this method returns true.
1165863Snate@binkert.org     *
1175863Snate@binkert.org     * @return true if all objects were drained successfully, false if
1184202Sbinkertn@umich.edu     * more simulation is needed.
1195863Snate@binkert.org     */
1205863Snate@binkert.org    bool tryDrain();
1215863Snate@binkert.org
1225863Snate@binkert.org    /**
123955SN/A     * Resume normal simulation in a Drained system.
1246654Snate@binkert.org     */
1255273Sstever@gmail.com    void resume();
1265871Snate@binkert.org
1275273Sstever@gmail.com    /**
1286655Snate@binkert.org     * Run state fixups before a checkpoint restore operation
1298878Ssteve.reinhardt@amd.com     *
1306655Snate@binkert.org     * The drain state of an object isn't stored in a checkpoint since
1316655Snate@binkert.org     * the whole system is always going to be in the Drained state
1329219Spower.jg@gmail.com     * when the checkpoint is created. When the checkpoint is restored
1336655Snate@binkert.org     * at a later stage, recreated objects will be in the Running
1345871Snate@binkert.org     * state since the state isn't stored in checkpoints. This method
1356654Snate@binkert.org     * performs state fixups on all Drainable objects and the
1368947Sandreas.hansson@arm.com     * DrainManager itself.
1375396Ssaidi@eecs.umich.edu     */
1388120Sgblack@eecs.umich.edu    void preCheckpointRestore();
1398120Sgblack@eecs.umich.edu
1408120Sgblack@eecs.umich.edu    /** Check if the system is drained */
1418120Sgblack@eecs.umich.edu    bool isDrained() const { return _state == DrainState::Drained; }
1428120Sgblack@eecs.umich.edu
1438120Sgblack@eecs.umich.edu    /** Get the simulators global drain state */
1448120Sgblack@eecs.umich.edu    DrainState state() const { return _state; }
1458120Sgblack@eecs.umich.edu
1468879Ssteve.reinhardt@amd.com    /**
1478879Ssteve.reinhardt@amd.com     * Notify the DrainManager that a Drainable object has finished
1488879Ssteve.reinhardt@amd.com     * draining.
1498879Ssteve.reinhardt@amd.com     */
1508879Ssteve.reinhardt@amd.com    void signalDrainDone();
1518879Ssteve.reinhardt@amd.com
1528879Ssteve.reinhardt@amd.com  public:
1538879Ssteve.reinhardt@amd.com    void registerDrainable(Drainable *obj);
1548879Ssteve.reinhardt@amd.com    void unregisterDrainable(Drainable *obj);
1558879Ssteve.reinhardt@amd.com
1568879Ssteve.reinhardt@amd.com  private:
1578879Ssteve.reinhardt@amd.com    /**
1588879Ssteve.reinhardt@amd.com     * Thread-safe helper function to get the number of Drainable
1598120Sgblack@eecs.umich.edu     * objects in a system.
1608120Sgblack@eecs.umich.edu     */
1618120Sgblack@eecs.umich.edu    size_t drainableCount() const;
1628120Sgblack@eecs.umich.edu
1638120Sgblack@eecs.umich.edu    /** Lock protecting the set of drainable objects */
1648120Sgblack@eecs.umich.edu    mutable std::mutex globalLock;
1658120Sgblack@eecs.umich.edu
1668120Sgblack@eecs.umich.edu    /** Set of all drainable objects */
1678120Sgblack@eecs.umich.edu    std::unordered_set<Drainable *> _allDrainable;
1688120Sgblack@eecs.umich.edu
1698120Sgblack@eecs.umich.edu    /**
1708120Sgblack@eecs.umich.edu     * Number of objects still draining. This is flagged atomic since
1718120Sgblack@eecs.umich.edu     * it can be manipulated by SimObjects living in different
1728120Sgblack@eecs.umich.edu     * threads.
1738879Ssteve.reinhardt@amd.com     */
1748879Ssteve.reinhardt@amd.com    std::atomic_uint _count;
1758879Ssteve.reinhardt@amd.com
1768879Ssteve.reinhardt@amd.com    /** Global simulator drain state */
17710458Sandreas.hansson@arm.com    DrainState _state;
17810458Sandreas.hansson@arm.com
17910458Sandreas.hansson@arm.com    /** Singleton instance of the drain manager */
1808879Ssteve.reinhardt@amd.com    static DrainManager _instance;
1818879Ssteve.reinhardt@amd.com};
1828879Ssteve.reinhardt@amd.com
1838879Ssteve.reinhardt@amd.com/**
1849227Sandreas.hansson@arm.com * Interface for objects that might require draining before
1859227Sandreas.hansson@arm.com * checkpointing.
1868879Ssteve.reinhardt@amd.com *
1878879Ssteve.reinhardt@amd.com * An object's internal state needs to be drained when creating a
1888879Ssteve.reinhardt@amd.com * checkpoint, switching between CPU models, or switching between
1898879Ssteve.reinhardt@amd.com * timing models. Once the internal state has been drained from
19010453SAndrew.Bardsley@arm.com * <i>all</i> objects in the simulator, the objects are serialized to
19110453SAndrew.Bardsley@arm.com * disc or the configuration change takes place. The process works as
19210453SAndrew.Bardsley@arm.com * follows (see simulate.py for details):
19310456SCurtis.Dunham@arm.com *
19410456SCurtis.Dunham@arm.com * <ol>
19510456SCurtis.Dunham@arm.com * <li>DrainManager::tryDrain() calls Drainable::drain() for every
19610457Sandreas.hansson@arm.com *     object in the system. Draining has completed if all of them
19710457Sandreas.hansson@arm.com *     return true. Otherwise, the drain manager keeps track of the
19811342Sandreas.hansson@arm.com *     objects that requested draining and waits for them to signal
19911342Sandreas.hansson@arm.com *     that they are done draining using the signalDrainDone() method.
2008120Sgblack@eecs.umich.edu *
2018947Sandreas.hansson@arm.com * <li>Continue simulation. When an object has finished draining its
2027816Ssteve.reinhardt@amd.com *     internal state, it calls DrainManager::signalDrainDone() on the
2035871Snate@binkert.org *     manager. The drain manager keeps track of the objects that
2045871Snate@binkert.org *     haven't drained yet, simulation stops when the set of
2056121Snate@binkert.org *     non-drained objects becomes empty.
2065871Snate@binkert.org *
2075871Snate@binkert.org * <li>Check if any object still needs draining
2089926Sstan.czerniawski@arm.com *     (DrainManager::tryDrain()), if so repeat the process above.
2099926Sstan.czerniawski@arm.com *
2109119Sandreas.hansson@arm.com * <li>Serialize objects, switch CPU model, or change timing model.
21110068Sandreas.hansson@arm.com *
21210068Sandreas.hansson@arm.com * <li>Call DrainManager::resume(), which in turn calls
213955SN/A *     Drainable::drainResume() for all objects, and then continue the
2149416SAndreas.Sandberg@ARM.com *     simulation.
21511342Sandreas.hansson@arm.com * </ol>
21611212Sjoseph.gross@amd.com *
21711212Sjoseph.gross@amd.com */
21811212Sjoseph.gross@amd.comclass Drainable
21911212Sjoseph.gross@amd.com{
22011212Sjoseph.gross@amd.com    friend class DrainManager;
2219416SAndreas.Sandberg@ARM.com
2229416SAndreas.Sandberg@ARM.com  protected:
2235871Snate@binkert.org    Drainable();
22410584Sandreas.hansson@arm.com    virtual ~Drainable();
2259416SAndreas.Sandberg@ARM.com
2269416SAndreas.Sandberg@ARM.com    /**
2275871Snate@binkert.org     * Notify an object that it needs to drain its state.
228955SN/A     *
22910671Sandreas.hansson@arm.com     * If the object does not need further simulation to drain
23010671Sandreas.hansson@arm.com     * internal buffers, it returns DrainState::Drained and
23110671Sandreas.hansson@arm.com     * automatically switches to the Drained state. If the object
23210671Sandreas.hansson@arm.com     * needs more simulation, it returns DrainState::Draining and
2338881Smarc.orr@gmail.com     * automatically enters the Draining state. Other return values
2346121Snate@binkert.org     * are invalid.
2356121Snate@binkert.org     *
2361533SN/A     * @note An object that has entered the Drained state can be
2379239Sandreas.hansson@arm.com     * disturbed by other objects in the system and consequently stop
2389239Sandreas.hansson@arm.com     * being drained. These perturbations are not visible in the drain
2399239Sandreas.hansson@arm.com     * state. The simulator therefore repeats the draining process
2409239Sandreas.hansson@arm.com     * until all objects return DrainState::Drained on the first call
2419239Sandreas.hansson@arm.com     * to drain().
2429239Sandreas.hansson@arm.com     *
2439239Sandreas.hansson@arm.com     * @return DrainState::Drained if the object is drained at this
2449239Sandreas.hansson@arm.com     * point in time, DrainState::Draining if it needs further
2459239Sandreas.hansson@arm.com     * simulation.
2469239Sandreas.hansson@arm.com     */
2479239Sandreas.hansson@arm.com    virtual DrainState drain() = 0;
2489239Sandreas.hansson@arm.com
2496655Snate@binkert.org    /**
2506655Snate@binkert.org     * Resume execution after a successful drain.
2516655Snate@binkert.org     */
2526655Snate@binkert.org    virtual void drainResume() {};
2535871Snate@binkert.org
2545871Snate@binkert.org    /**
2555863Snate@binkert.org     * Signal that an object is drained
2565871Snate@binkert.org     *
2578878Ssteve.reinhardt@amd.com     * This method is designed to be called whenever an object enters
2585871Snate@binkert.org     * into a state where it is ready to be drained. The method is
2595871Snate@binkert.org     * safe to call multiple times and there is no need to check that
2605871Snate@binkert.org     * draining has been requested before calling this method.
2615863Snate@binkert.org     */
2626121Snate@binkert.org    void signalDrainDone() const {
2635863Snate@binkert.org        switch (_drainState) {
26411408Sandreas.sandberg@arm.com          case DrainState::Running:
26511408Sandreas.sandberg@arm.com          case DrainState::Drained:
2668336Ssteve.reinhardt@amd.com            return;
26711469SCurtis.Dunham@arm.com          case DrainState::Draining:
26811469SCurtis.Dunham@arm.com            _drainState = DrainState::Drained;
2698336Ssteve.reinhardt@amd.com            _drainManager.signalDrainDone();
2704678Snate@binkert.org            return;
27111887Sandreas.sandberg@arm.com        }
27211887Sandreas.sandberg@arm.com    }
27311887Sandreas.sandberg@arm.com
27411887Sandreas.sandberg@arm.com  public:
27511887Sandreas.sandberg@arm.com    /** Return the current drain state of an object. */
27611887Sandreas.sandberg@arm.com    DrainState drainState() const { return _drainState; }
27711887Sandreas.sandberg@arm.com
27811887Sandreas.sandberg@arm.com    /**
27911887Sandreas.sandberg@arm.com     * Notify a child process of a fork.
28011887Sandreas.sandberg@arm.com     *
28111887Sandreas.sandberg@arm.com     * When calling fork in gem5, we need to ensure that resources
28211408Sandreas.sandberg@arm.com     * shared between the parent and the child are consistent. This
28311401Sandreas.sandberg@arm.com     * method is intended to be overloaded to handle that. For
28411401Sandreas.sandberg@arm.com     * example, an object could use this method to re-open input files
28511401Sandreas.sandberg@arm.com     * to get a separate file description with a private file offset.
28611401Sandreas.sandberg@arm.com     *
28711401Sandreas.sandberg@arm.com     * This method is only called in the child of the fork. The call
28811401Sandreas.sandberg@arm.com     * takes place in a drained system.
2898336Ssteve.reinhardt@amd.com     */
2908336Ssteve.reinhardt@amd.com    virtual void notifyFork() {};
2918336Ssteve.reinhardt@amd.com
2924678Snate@binkert.org  private:
29311401Sandreas.sandberg@arm.com    /** DrainManager interface to request a drain operation */
2944678Snate@binkert.org    DrainState dmDrain();
2954678Snate@binkert.org    /** DrainManager interface to request a resume operation */
29611401Sandreas.sandberg@arm.com    void dmDrainResume();
29711401Sandreas.sandberg@arm.com
2988336Ssteve.reinhardt@amd.com    /** Convenience reference to the drain manager */
2994678Snate@binkert.org    DrainManager &_drainManager;
3008336Ssteve.reinhardt@amd.com
3018336Ssteve.reinhardt@amd.com    /**
3028336Ssteve.reinhardt@amd.com     * Current drain state of the object. Needs to be mutable since
3038336Ssteve.reinhardt@amd.com     * objects need to be able to signal that they have transitioned
3048336Ssteve.reinhardt@amd.com     * into a Drained state even if the calling method is const.
3058336Ssteve.reinhardt@amd.com     */
3065871Snate@binkert.org    mutable DrainState _drainState;
3075871Snate@binkert.org};
3088336Ssteve.reinhardt@amd.com
30911408Sandreas.sandberg@arm.com#endif
31011408Sandreas.sandberg@arm.com