drain.hh revision 11937
19342SAndreas.Sandberg@arm.com/*
211937Sandreas.sandberg@arm.com * Copyright (c) 2012, 2015, 2017 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
4310912Sandreas.sandberg@arm.com#include <atomic>
4410912Sandreas.sandberg@arm.com#include <mutex>
4511859Sandreas.hansson@arm.com#include <vector>
469342SAndreas.Sandberg@arm.com
4710910Sandreas.sandberg@arm.comclass Drainable;
4810910Sandreas.sandberg@arm.com
4910910Sandreas.sandberg@arm.com#ifndef SWIG // SWIG doesn't support strongly typed enums
5010910Sandreas.sandberg@arm.com/**
5110910Sandreas.sandberg@arm.com * Object drain/handover states
5210910Sandreas.sandberg@arm.com *
5310910Sandreas.sandberg@arm.com * An object starts out in the Running state. When the simulator
5410910Sandreas.sandberg@arm.com * prepares to take a snapshot or prepares a CPU for handover, it
5510910Sandreas.sandberg@arm.com * calls the drain() method to transfer the object into the Draining
5610910Sandreas.sandberg@arm.com * or Drained state. If any object enters the Draining state
5710910Sandreas.sandberg@arm.com * (Drainable::drain() returning >0), simulation continues until it
5810910Sandreas.sandberg@arm.com * all objects have entered the Drained state.
5910910Sandreas.sandberg@arm.com *
6010910Sandreas.sandberg@arm.com * Before resuming simulation, the simulator calls resume() to
6111937Sandreas.sandberg@arm.com * transfer the object to the Running state. This in turn results in a
6211937Sandreas.sandberg@arm.com * call to drainResume() for all Drainable objects in the
6311937Sandreas.sandberg@arm.com * simulator. New Drainable objects may be created while resuming. In
6411937Sandreas.sandberg@arm.com * such cases, the new objects will be created in the Resuming state
6511937Sandreas.sandberg@arm.com * and later resumed.
6610910Sandreas.sandberg@arm.com *
6710910Sandreas.sandberg@arm.com * \note Even though the state of an object (visible to the rest of
6810910Sandreas.sandberg@arm.com * the world through Drainable::getState()) could be used to determine
6910910Sandreas.sandberg@arm.com * if all objects have entered the Drained state, the protocol is
7010910Sandreas.sandberg@arm.com * actually a bit more elaborate. See Drainable::drain() for details.
7110910Sandreas.sandberg@arm.com */
7210910Sandreas.sandberg@arm.comenum class DrainState {
7310910Sandreas.sandberg@arm.com    Running,  /** Running normally */
7410910Sandreas.sandberg@arm.com    Draining, /** Draining buffers pending serialization/handover */
7511937Sandreas.sandberg@arm.com    Drained,  /** Buffers drained, ready for serialization/handover */
7611937Sandreas.sandberg@arm.com    Resuming, /** Transient state while the simulator is resuming */
7710910Sandreas.sandberg@arm.com};
7810910Sandreas.sandberg@arm.com#endif
799342SAndreas.Sandberg@arm.com
809342SAndreas.Sandberg@arm.com/**
819342SAndreas.Sandberg@arm.com * This class coordinates draining of a System.
829342SAndreas.Sandberg@arm.com *
8310912Sandreas.sandberg@arm.com * When draining the simulator, we need to make sure that all
8410912Sandreas.sandberg@arm.com * Drainable objects within the system have ended up in the drained
8510912Sandreas.sandberg@arm.com * state before declaring the operation to be successful. This class
8610912Sandreas.sandberg@arm.com * keeps track of how many objects are still in the process of
8710912Sandreas.sandberg@arm.com * draining. Once it determines that all objects have drained their
8810912Sandreas.sandberg@arm.com * state, it exits the simulation loop.
899342SAndreas.Sandberg@arm.com *
909342SAndreas.Sandberg@arm.com * @note A System might not be completely drained even though the
919342SAndreas.Sandberg@arm.com * DrainManager has caused the simulation loop to exit. Draining needs
929342SAndreas.Sandberg@arm.com * to be restarted until all Drainable objects declare that they don't
939342SAndreas.Sandberg@arm.com * need further simulation to be completely drained. See Drainable for
949342SAndreas.Sandberg@arm.com * more information.
959342SAndreas.Sandberg@arm.com */
969342SAndreas.Sandberg@arm.comclass DrainManager
979342SAndreas.Sandberg@arm.com{
9810912Sandreas.sandberg@arm.com  private:
9910912Sandreas.sandberg@arm.com    DrainManager();
10010912Sandreas.sandberg@arm.com#ifndef SWIG
10110912Sandreas.sandberg@arm.com    DrainManager(DrainManager &) = delete;
10210912Sandreas.sandberg@arm.com#endif
10310912Sandreas.sandberg@arm.com    ~DrainManager();
10410912Sandreas.sandberg@arm.com
1059342SAndreas.Sandberg@arm.com  public:
10610912Sandreas.sandberg@arm.com    /** Get the singleton DrainManager instance */
10710912Sandreas.sandberg@arm.com    static DrainManager &instance() { return _instance; }
1089342SAndreas.Sandberg@arm.com
1099342SAndreas.Sandberg@arm.com    /**
11010912Sandreas.sandberg@arm.com     * Try to drain the system.
1119342SAndreas.Sandberg@arm.com     *
11210912Sandreas.sandberg@arm.com     * Try to drain the system and return true if all objects are in a
11310912Sandreas.sandberg@arm.com     * the Drained state at which point the whole simulator is in a
11410912Sandreas.sandberg@arm.com     * consistent state and ready for checkpointing or CPU
11510912Sandreas.sandberg@arm.com     * handover. The simulation script must continue simulating until
11610912Sandreas.sandberg@arm.com     * the simulation loop returns "Finished drain", at which point
11710912Sandreas.sandberg@arm.com     * this method should be called again. This cycle should continue
11810912Sandreas.sandberg@arm.com     * until this method returns true.
11910912Sandreas.sandberg@arm.com     *
12010912Sandreas.sandberg@arm.com     * @return true if all objects were drained successfully, false if
12110912Sandreas.sandberg@arm.com     * more simulation is needed.
1229342SAndreas.Sandberg@arm.com     */
12310912Sandreas.sandberg@arm.com    bool tryDrain();
1249342SAndreas.Sandberg@arm.com
12510912Sandreas.sandberg@arm.com    /**
12610912Sandreas.sandberg@arm.com     * Resume normal simulation in a Drained system.
12710912Sandreas.sandberg@arm.com     */
12810912Sandreas.sandberg@arm.com    void resume();
12910912Sandreas.sandberg@arm.com
13010912Sandreas.sandberg@arm.com    /**
13110912Sandreas.sandberg@arm.com     * Run state fixups before a checkpoint restore operation
13210912Sandreas.sandberg@arm.com     *
13310912Sandreas.sandberg@arm.com     * The drain state of an object isn't stored in a checkpoint since
13410912Sandreas.sandberg@arm.com     * the whole system is always going to be in the Drained state
13510912Sandreas.sandberg@arm.com     * when the checkpoint is created. When the checkpoint is restored
13610912Sandreas.sandberg@arm.com     * at a later stage, recreated objects will be in the Running
13710912Sandreas.sandberg@arm.com     * state since the state isn't stored in checkpoints. This method
13810912Sandreas.sandberg@arm.com     * performs state fixups on all Drainable objects and the
13910912Sandreas.sandberg@arm.com     * DrainManager itself.
14010912Sandreas.sandberg@arm.com     */
14110912Sandreas.sandberg@arm.com    void preCheckpointRestore();
14210912Sandreas.sandberg@arm.com
14310912Sandreas.sandberg@arm.com    /** Check if the system is drained */
14411002Sandreas.sandberg@arm.com    bool isDrained() const { return _state == DrainState::Drained; }
14510912Sandreas.sandberg@arm.com
14610912Sandreas.sandberg@arm.com    /** Get the simulators global drain state */
14711002Sandreas.sandberg@arm.com    DrainState state() const { return _state; }
1489342SAndreas.Sandberg@arm.com
1499342SAndreas.Sandberg@arm.com    /**
1509342SAndreas.Sandberg@arm.com     * Notify the DrainManager that a Drainable object has finished
1519342SAndreas.Sandberg@arm.com     * draining.
1529342SAndreas.Sandberg@arm.com     */
15310912Sandreas.sandberg@arm.com    void signalDrainDone();
1549342SAndreas.Sandberg@arm.com
15510912Sandreas.sandberg@arm.com  public:
15610912Sandreas.sandberg@arm.com    void registerDrainable(Drainable *obj);
15710912Sandreas.sandberg@arm.com    void unregisterDrainable(Drainable *obj);
15810912Sandreas.sandberg@arm.com
15910912Sandreas.sandberg@arm.com  private:
1609342SAndreas.Sandberg@arm.com    /**
16111937Sandreas.sandberg@arm.com     * Helper function to check if all Drainable objects are in a
16211937Sandreas.sandberg@arm.com     * specific state.
16311937Sandreas.sandberg@arm.com     */
16411937Sandreas.sandberg@arm.com    bool allInState(DrainState state) const;
16511937Sandreas.sandberg@arm.com
16611937Sandreas.sandberg@arm.com    /**
16710912Sandreas.sandberg@arm.com     * Thread-safe helper function to get the number of Drainable
16810912Sandreas.sandberg@arm.com     * objects in a system.
1699342SAndreas.Sandberg@arm.com     */
17010912Sandreas.sandberg@arm.com    size_t drainableCount() const;
1719342SAndreas.Sandberg@arm.com
17210912Sandreas.sandberg@arm.com    /** Lock protecting the set of drainable objects */
17310912Sandreas.sandberg@arm.com    mutable std::mutex globalLock;
17410912Sandreas.sandberg@arm.com
17510912Sandreas.sandberg@arm.com    /** Set of all drainable objects */
17611859Sandreas.hansson@arm.com    std::vector<Drainable *> _allDrainable;
17710912Sandreas.sandberg@arm.com
17810912Sandreas.sandberg@arm.com    /**
17910912Sandreas.sandberg@arm.com     * Number of objects still draining. This is flagged atomic since
18010912Sandreas.sandberg@arm.com     * it can be manipulated by SimObjects living in different
18110912Sandreas.sandberg@arm.com     * threads.
18210912Sandreas.sandberg@arm.com     */
18310912Sandreas.sandberg@arm.com    std::atomic_uint _count;
18410912Sandreas.sandberg@arm.com
18510912Sandreas.sandberg@arm.com    /** Global simulator drain state */
18610912Sandreas.sandberg@arm.com    DrainState _state;
18710912Sandreas.sandberg@arm.com
18810912Sandreas.sandberg@arm.com    /** Singleton instance of the drain manager */
18910912Sandreas.sandberg@arm.com    static DrainManager _instance;
1909342SAndreas.Sandberg@arm.com};
1919342SAndreas.Sandberg@arm.com
1929342SAndreas.Sandberg@arm.com/**
1939342SAndreas.Sandberg@arm.com * Interface for objects that might require draining before
1949342SAndreas.Sandberg@arm.com * checkpointing.
1959342SAndreas.Sandberg@arm.com *
1969342SAndreas.Sandberg@arm.com * An object's internal state needs to be drained when creating a
1979342SAndreas.Sandberg@arm.com * checkpoint, switching between CPU models, or switching between
1989342SAndreas.Sandberg@arm.com * timing models. Once the internal state has been drained from
19910912Sandreas.sandberg@arm.com * <i>all</i> objects in the simulator, the objects are serialized to
2009342SAndreas.Sandberg@arm.com * disc or the configuration change takes place. The process works as
2019342SAndreas.Sandberg@arm.com * follows (see simulate.py for details):
2029342SAndreas.Sandberg@arm.com *
2039342SAndreas.Sandberg@arm.com * <ol>
20410913Sandreas.sandberg@arm.com * <li>DrainManager::tryDrain() calls Drainable::drain() for every
20510913Sandreas.sandberg@arm.com *     object in the system. Draining has completed if all of them
20610913Sandreas.sandberg@arm.com *     return true. Otherwise, the drain manager keeps track of the
20710913Sandreas.sandberg@arm.com *     objects that requested draining and waits for them to signal
20810913Sandreas.sandberg@arm.com *     that they are done draining using the signalDrainDone() method.
2099342SAndreas.Sandberg@arm.com *
2109342SAndreas.Sandberg@arm.com * <li>Continue simulation. When an object has finished draining its
21110912Sandreas.sandberg@arm.com *     internal state, it calls DrainManager::signalDrainDone() on the
21210913Sandreas.sandberg@arm.com *     manager. The drain manager keeps track of the objects that
21310913Sandreas.sandberg@arm.com *     haven't drained yet, simulation stops when the set of
21410913Sandreas.sandberg@arm.com *     non-drained objects becomes empty.
2159342SAndreas.Sandberg@arm.com *
21610913Sandreas.sandberg@arm.com * <li>Check if any object still needs draining
21710913Sandreas.sandberg@arm.com *     (DrainManager::tryDrain()), if so repeat the process above.
2189342SAndreas.Sandberg@arm.com *
2199342SAndreas.Sandberg@arm.com * <li>Serialize objects, switch CPU model, or change timing model.
2209342SAndreas.Sandberg@arm.com *
22111002Sandreas.sandberg@arm.com * <li>Call DrainManager::resume(), which in turn calls
22211002Sandreas.sandberg@arm.com *     Drainable::drainResume() for all objects, and then continue the
22310913Sandreas.sandberg@arm.com *     simulation.
2249342SAndreas.Sandberg@arm.com * </ol>
2259342SAndreas.Sandberg@arm.com *
2269342SAndreas.Sandberg@arm.com */
2279342SAndreas.Sandberg@arm.comclass Drainable
2289342SAndreas.Sandberg@arm.com{
22910912Sandreas.sandberg@arm.com    friend class DrainManager;
23010912Sandreas.sandberg@arm.com
23110913Sandreas.sandberg@arm.com  protected:
2329342SAndreas.Sandberg@arm.com    Drainable();
2339342SAndreas.Sandberg@arm.com    virtual ~Drainable();
2349342SAndreas.Sandberg@arm.com
2359342SAndreas.Sandberg@arm.com    /**
23611002Sandreas.sandberg@arm.com     * Notify an object that it needs to drain its state.
2379342SAndreas.Sandberg@arm.com     *
23810913Sandreas.sandberg@arm.com     * If the object does not need further simulation to drain
23911002Sandreas.sandberg@arm.com     * internal buffers, it returns DrainState::Drained and
24011002Sandreas.sandberg@arm.com     * automatically switches to the Drained state. If the object
24111002Sandreas.sandberg@arm.com     * needs more simulation, it returns DrainState::Draining and
24211002Sandreas.sandberg@arm.com     * automatically enters the Draining state. Other return values
24311002Sandreas.sandberg@arm.com     * are invalid.
2449342SAndreas.Sandberg@arm.com     *
2459342SAndreas.Sandberg@arm.com     * @note An object that has entered the Drained state can be
24611002Sandreas.sandberg@arm.com     * disturbed by other objects in the system and consequently stop
24711002Sandreas.sandberg@arm.com     * being drained. These perturbations are not visible in the drain
24811002Sandreas.sandberg@arm.com     * state. The simulator therefore repeats the draining process
24911002Sandreas.sandberg@arm.com     * until all objects return DrainState::Drained on the first call
25011002Sandreas.sandberg@arm.com     * to drain().
2519342SAndreas.Sandberg@arm.com     *
25211002Sandreas.sandberg@arm.com     * @return DrainState::Drained if the object is drained at this
25311002Sandreas.sandberg@arm.com     * point in time, DrainState::Draining if it needs further
25410913Sandreas.sandberg@arm.com     * simulation.
2559342SAndreas.Sandberg@arm.com     */
25610913Sandreas.sandberg@arm.com    virtual DrainState drain() = 0;
2579342SAndreas.Sandberg@arm.com
2589342SAndreas.Sandberg@arm.com    /**
2599342SAndreas.Sandberg@arm.com     * Resume execution after a successful drain.
26010913Sandreas.sandberg@arm.com     */
26110913Sandreas.sandberg@arm.com    virtual void drainResume() {};
26210913Sandreas.sandberg@arm.com
26310913Sandreas.sandberg@arm.com    /**
26410913Sandreas.sandberg@arm.com     * Signal that an object is drained
2659342SAndreas.Sandberg@arm.com     *
26610913Sandreas.sandberg@arm.com     * This method is designed to be called whenever an object enters
26710913Sandreas.sandberg@arm.com     * into a state where it is ready to be drained. The method is
26810913Sandreas.sandberg@arm.com     * safe to call multiple times and there is no need to check that
26910913Sandreas.sandberg@arm.com     * draining has been requested before calling this method.
2709342SAndreas.Sandberg@arm.com     */
27110913Sandreas.sandberg@arm.com    void signalDrainDone() const {
27210913Sandreas.sandberg@arm.com        switch (_drainState) {
27310913Sandreas.sandberg@arm.com          case DrainState::Running:
27410913Sandreas.sandberg@arm.com          case DrainState::Drained:
27511937Sandreas.sandberg@arm.com          case DrainState::Resuming:
27610913Sandreas.sandberg@arm.com            return;
27710913Sandreas.sandberg@arm.com          case DrainState::Draining:
27810913Sandreas.sandberg@arm.com            _drainState = DrainState::Drained;
27910913Sandreas.sandberg@arm.com            _drainManager.signalDrainDone();
28010913Sandreas.sandberg@arm.com            return;
28110913Sandreas.sandberg@arm.com        }
28210913Sandreas.sandberg@arm.com    }
2839342SAndreas.Sandberg@arm.com
28410913Sandreas.sandberg@arm.com  public:
28510913Sandreas.sandberg@arm.com    /** Return the current drain state of an object. */
28610913Sandreas.sandberg@arm.com    DrainState drainState() const { return _drainState; }
2879342SAndreas.Sandberg@arm.com
28811360Sandreas@sandberg.pp.se    /**
28911360Sandreas@sandberg.pp.se     * Notify a child process of a fork.
29011360Sandreas@sandberg.pp.se     *
29111360Sandreas@sandberg.pp.se     * When calling fork in gem5, we need to ensure that resources
29211360Sandreas@sandberg.pp.se     * shared between the parent and the child are consistent. This
29311360Sandreas@sandberg.pp.se     * method is intended to be overloaded to handle that. For
29411360Sandreas@sandberg.pp.se     * example, an object could use this method to re-open input files
29511360Sandreas@sandberg.pp.se     * to get a separate file description with a private file offset.
29611360Sandreas@sandberg.pp.se     *
29711360Sandreas@sandberg.pp.se     * This method is only called in the child of the fork. The call
29811360Sandreas@sandberg.pp.se     * takes place in a drained system.
29911360Sandreas@sandberg.pp.se     */
30011360Sandreas@sandberg.pp.se    virtual void notifyFork() {};
30111360Sandreas@sandberg.pp.se
3029342SAndreas.Sandberg@arm.com  private:
30310913Sandreas.sandberg@arm.com    /** DrainManager interface to request a drain operation */
30410913Sandreas.sandberg@arm.com    DrainState dmDrain();
30510913Sandreas.sandberg@arm.com    /** DrainManager interface to request a resume operation */
30610913Sandreas.sandberg@arm.com    void dmDrainResume();
30710913Sandreas.sandberg@arm.com
30810913Sandreas.sandberg@arm.com    /** Convenience reference to the drain manager */
30910912Sandreas.sandberg@arm.com    DrainManager &_drainManager;
31010913Sandreas.sandberg@arm.com
31110913Sandreas.sandberg@arm.com    /**
31210913Sandreas.sandberg@arm.com     * Current drain state of the object. Needs to be mutable since
31310913Sandreas.sandberg@arm.com     * objects need to be able to signal that they have transitioned
31410913Sandreas.sandberg@arm.com     * into a Drained state even if the calling method is const.
31510913Sandreas.sandberg@arm.com     */
31610913Sandreas.sandberg@arm.com    mutable DrainState _drainState;
3179342SAndreas.Sandberg@arm.com};
3189342SAndreas.Sandberg@arm.com
3199342SAndreas.Sandberg@arm.com#endif
320