drain.hh revision 11002
19342SAndreas.Sandberg@arm.com/*
210910Sandreas.sandberg@arm.com * Copyright (c) 2012, 2015 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>
4510912Sandreas.sandberg@arm.com#include <unordered_set>
469342SAndreas.Sandberg@arm.com
479342SAndreas.Sandberg@arm.com#include "base/flags.hh"
489342SAndreas.Sandberg@arm.com
4910910Sandreas.sandberg@arm.comclass Drainable;
5010910Sandreas.sandberg@arm.com
5110910Sandreas.sandberg@arm.com#ifndef SWIG // SWIG doesn't support strongly typed enums
5210910Sandreas.sandberg@arm.com/**
5310910Sandreas.sandberg@arm.com * Object drain/handover states
5410910Sandreas.sandberg@arm.com *
5510910Sandreas.sandberg@arm.com * An object starts out in the Running state. When the simulator
5610910Sandreas.sandberg@arm.com * prepares to take a snapshot or prepares a CPU for handover, it
5710910Sandreas.sandberg@arm.com * calls the drain() method to transfer the object into the Draining
5810910Sandreas.sandberg@arm.com * or Drained state. If any object enters the Draining state
5910910Sandreas.sandberg@arm.com * (Drainable::drain() returning >0), simulation continues until it
6010910Sandreas.sandberg@arm.com * all objects have entered the Drained state.
6110910Sandreas.sandberg@arm.com *
6210910Sandreas.sandberg@arm.com * Before resuming simulation, the simulator calls resume() to
6310910Sandreas.sandberg@arm.com * transfer the object to the Running state.
6410910Sandreas.sandberg@arm.com *
6510910Sandreas.sandberg@arm.com * \note Even though the state of an object (visible to the rest of
6610910Sandreas.sandberg@arm.com * the world through Drainable::getState()) could be used to determine
6710910Sandreas.sandberg@arm.com * if all objects have entered the Drained state, the protocol is
6810910Sandreas.sandberg@arm.com * actually a bit more elaborate. See Drainable::drain() for details.
6910910Sandreas.sandberg@arm.com */
7010910Sandreas.sandberg@arm.comenum class DrainState {
7110910Sandreas.sandberg@arm.com    Running,  /** Running normally */
7210910Sandreas.sandberg@arm.com    Draining, /** Draining buffers pending serialization/handover */
7310910Sandreas.sandberg@arm.com    Drained   /** Buffers drained, ready for serialization/handover */
7410910Sandreas.sandberg@arm.com};
7510910Sandreas.sandberg@arm.com#endif
769342SAndreas.Sandberg@arm.com
779342SAndreas.Sandberg@arm.com/**
789342SAndreas.Sandberg@arm.com * This class coordinates draining of a System.
799342SAndreas.Sandberg@arm.com *
8010912Sandreas.sandberg@arm.com * When draining the simulator, we need to make sure that all
8110912Sandreas.sandberg@arm.com * Drainable objects within the system have ended up in the drained
8210912Sandreas.sandberg@arm.com * state before declaring the operation to be successful. This class
8310912Sandreas.sandberg@arm.com * keeps track of how many objects are still in the process of
8410912Sandreas.sandberg@arm.com * draining. Once it determines that all objects have drained their
8510912Sandreas.sandberg@arm.com * state, it exits the simulation loop.
869342SAndreas.Sandberg@arm.com *
879342SAndreas.Sandberg@arm.com * @note A System might not be completely drained even though the
889342SAndreas.Sandberg@arm.com * DrainManager has caused the simulation loop to exit. Draining needs
899342SAndreas.Sandberg@arm.com * to be restarted until all Drainable objects declare that they don't
909342SAndreas.Sandberg@arm.com * need further simulation to be completely drained. See Drainable for
919342SAndreas.Sandberg@arm.com * more information.
929342SAndreas.Sandberg@arm.com */
939342SAndreas.Sandberg@arm.comclass DrainManager
949342SAndreas.Sandberg@arm.com{
9510912Sandreas.sandberg@arm.com  private:
9610912Sandreas.sandberg@arm.com    DrainManager();
9710912Sandreas.sandberg@arm.com#ifndef SWIG
9810912Sandreas.sandberg@arm.com    DrainManager(DrainManager &) = delete;
9910912Sandreas.sandberg@arm.com#endif
10010912Sandreas.sandberg@arm.com    ~DrainManager();
10110912Sandreas.sandberg@arm.com
1029342SAndreas.Sandberg@arm.com  public:
10310912Sandreas.sandberg@arm.com    /** Get the singleton DrainManager instance */
10410912Sandreas.sandberg@arm.com    static DrainManager &instance() { return _instance; }
1059342SAndreas.Sandberg@arm.com
1069342SAndreas.Sandberg@arm.com    /**
10710912Sandreas.sandberg@arm.com     * Try to drain the system.
1089342SAndreas.Sandberg@arm.com     *
10910912Sandreas.sandberg@arm.com     * Try to drain the system and return true if all objects are in a
11010912Sandreas.sandberg@arm.com     * the Drained state at which point the whole simulator is in a
11110912Sandreas.sandberg@arm.com     * consistent state and ready for checkpointing or CPU
11210912Sandreas.sandberg@arm.com     * handover. The simulation script must continue simulating until
11310912Sandreas.sandberg@arm.com     * the simulation loop returns "Finished drain", at which point
11410912Sandreas.sandberg@arm.com     * this method should be called again. This cycle should continue
11510912Sandreas.sandberg@arm.com     * until this method returns true.
11610912Sandreas.sandberg@arm.com     *
11710912Sandreas.sandberg@arm.com     * @return true if all objects were drained successfully, false if
11810912Sandreas.sandberg@arm.com     * more simulation is needed.
1199342SAndreas.Sandberg@arm.com     */
12010912Sandreas.sandberg@arm.com    bool tryDrain();
1219342SAndreas.Sandberg@arm.com
12210912Sandreas.sandberg@arm.com    /**
12310912Sandreas.sandberg@arm.com     * Resume normal simulation in a Drained system.
12410912Sandreas.sandberg@arm.com     */
12510912Sandreas.sandberg@arm.com    void resume();
12610912Sandreas.sandberg@arm.com
12710912Sandreas.sandberg@arm.com    /**
12810912Sandreas.sandberg@arm.com     * Run state fixups before a checkpoint restore operation
12910912Sandreas.sandberg@arm.com     *
13010912Sandreas.sandberg@arm.com     * The drain state of an object isn't stored in a checkpoint since
13110912Sandreas.sandberg@arm.com     * the whole system is always going to be in the Drained state
13210912Sandreas.sandberg@arm.com     * when the checkpoint is created. When the checkpoint is restored
13310912Sandreas.sandberg@arm.com     * at a later stage, recreated objects will be in the Running
13410912Sandreas.sandberg@arm.com     * state since the state isn't stored in checkpoints. This method
13510912Sandreas.sandberg@arm.com     * performs state fixups on all Drainable objects and the
13610912Sandreas.sandberg@arm.com     * DrainManager itself.
13710912Sandreas.sandberg@arm.com     */
13810912Sandreas.sandberg@arm.com    void preCheckpointRestore();
13910912Sandreas.sandberg@arm.com
14010912Sandreas.sandberg@arm.com    /** Check if the system is drained */
14111002Sandreas.sandberg@arm.com    bool isDrained() const { return _state == DrainState::Drained; }
14210912Sandreas.sandberg@arm.com
14310912Sandreas.sandberg@arm.com    /** Get the simulators global drain state */
14411002Sandreas.sandberg@arm.com    DrainState state() const { return _state; }
1459342SAndreas.Sandberg@arm.com
1469342SAndreas.Sandberg@arm.com    /**
1479342SAndreas.Sandberg@arm.com     * Notify the DrainManager that a Drainable object has finished
1489342SAndreas.Sandberg@arm.com     * draining.
1499342SAndreas.Sandberg@arm.com     */
15010912Sandreas.sandberg@arm.com    void signalDrainDone();
1519342SAndreas.Sandberg@arm.com
15210912Sandreas.sandberg@arm.com  public:
15310912Sandreas.sandberg@arm.com    void registerDrainable(Drainable *obj);
15410912Sandreas.sandberg@arm.com    void unregisterDrainable(Drainable *obj);
15510912Sandreas.sandberg@arm.com
15610912Sandreas.sandberg@arm.com  private:
1579342SAndreas.Sandberg@arm.com    /**
15810912Sandreas.sandberg@arm.com     * Thread-safe helper function to get the number of Drainable
15910912Sandreas.sandberg@arm.com     * objects in a system.
1609342SAndreas.Sandberg@arm.com     */
16110912Sandreas.sandberg@arm.com    size_t drainableCount() const;
1629342SAndreas.Sandberg@arm.com
16310912Sandreas.sandberg@arm.com    /** Lock protecting the set of drainable objects */
16410912Sandreas.sandberg@arm.com    mutable std::mutex globalLock;
16510912Sandreas.sandberg@arm.com
16610912Sandreas.sandberg@arm.com    /** Set of all drainable objects */
16710912Sandreas.sandberg@arm.com    std::unordered_set<Drainable *> _allDrainable;
16810912Sandreas.sandberg@arm.com
16910912Sandreas.sandberg@arm.com    /**
17010912Sandreas.sandberg@arm.com     * Number of objects still draining. This is flagged atomic since
17110912Sandreas.sandberg@arm.com     * it can be manipulated by SimObjects living in different
17210912Sandreas.sandberg@arm.com     * threads.
17310912Sandreas.sandberg@arm.com     */
17410912Sandreas.sandberg@arm.com    std::atomic_uint _count;
17510912Sandreas.sandberg@arm.com
17610912Sandreas.sandberg@arm.com    /** Global simulator drain state */
17710912Sandreas.sandberg@arm.com    DrainState _state;
17810912Sandreas.sandberg@arm.com
17910912Sandreas.sandberg@arm.com    /** Singleton instance of the drain manager */
18010912Sandreas.sandberg@arm.com    static DrainManager _instance;
1819342SAndreas.Sandberg@arm.com};
1829342SAndreas.Sandberg@arm.com
1839342SAndreas.Sandberg@arm.com/**
1849342SAndreas.Sandberg@arm.com * Interface for objects that might require draining before
1859342SAndreas.Sandberg@arm.com * checkpointing.
1869342SAndreas.Sandberg@arm.com *
1879342SAndreas.Sandberg@arm.com * An object's internal state needs to be drained when creating a
1889342SAndreas.Sandberg@arm.com * checkpoint, switching between CPU models, or switching between
1899342SAndreas.Sandberg@arm.com * timing models. Once the internal state has been drained from
19010912Sandreas.sandberg@arm.com * <i>all</i> objects in the simulator, the objects are serialized to
1919342SAndreas.Sandberg@arm.com * disc or the configuration change takes place. The process works as
1929342SAndreas.Sandberg@arm.com * follows (see simulate.py for details):
1939342SAndreas.Sandberg@arm.com *
1949342SAndreas.Sandberg@arm.com * <ol>
19510913Sandreas.sandberg@arm.com * <li>DrainManager::tryDrain() calls Drainable::drain() for every
19610913Sandreas.sandberg@arm.com *     object in the system. Draining has completed if all of them
19710913Sandreas.sandberg@arm.com *     return true. Otherwise, the drain manager keeps track of the
19810913Sandreas.sandberg@arm.com *     objects that requested draining and waits for them to signal
19910913Sandreas.sandberg@arm.com *     that they are done draining using the signalDrainDone() method.
2009342SAndreas.Sandberg@arm.com *
2019342SAndreas.Sandberg@arm.com * <li>Continue simulation. When an object has finished draining its
20210912Sandreas.sandberg@arm.com *     internal state, it calls DrainManager::signalDrainDone() on the
20310913Sandreas.sandberg@arm.com *     manager. The drain manager keeps track of the objects that
20410913Sandreas.sandberg@arm.com *     haven't drained yet, simulation stops when the set of
20510913Sandreas.sandberg@arm.com *     non-drained objects becomes empty.
2069342SAndreas.Sandberg@arm.com *
20710913Sandreas.sandberg@arm.com * <li>Check if any object still needs draining
20810913Sandreas.sandberg@arm.com *     (DrainManager::tryDrain()), if so repeat the process above.
2099342SAndreas.Sandberg@arm.com *
2109342SAndreas.Sandberg@arm.com * <li>Serialize objects, switch CPU model, or change timing model.
2119342SAndreas.Sandberg@arm.com *
21211002Sandreas.sandberg@arm.com * <li>Call DrainManager::resume(), which in turn calls
21311002Sandreas.sandberg@arm.com *     Drainable::drainResume() for all objects, and then continue the
21410913Sandreas.sandberg@arm.com *     simulation.
2159342SAndreas.Sandberg@arm.com * </ol>
2169342SAndreas.Sandberg@arm.com *
2179342SAndreas.Sandberg@arm.com */
2189342SAndreas.Sandberg@arm.comclass Drainable
2199342SAndreas.Sandberg@arm.com{
22010912Sandreas.sandberg@arm.com    friend class DrainManager;
22110912Sandreas.sandberg@arm.com
22210913Sandreas.sandberg@arm.com  protected:
2239342SAndreas.Sandberg@arm.com    Drainable();
2249342SAndreas.Sandberg@arm.com    virtual ~Drainable();
2259342SAndreas.Sandberg@arm.com
2269342SAndreas.Sandberg@arm.com    /**
22711002Sandreas.sandberg@arm.com     * Notify an object that it needs to drain its state.
2289342SAndreas.Sandberg@arm.com     *
22910913Sandreas.sandberg@arm.com     * If the object does not need further simulation to drain
23011002Sandreas.sandberg@arm.com     * internal buffers, it returns DrainState::Drained and
23111002Sandreas.sandberg@arm.com     * automatically switches to the Drained state. If the object
23211002Sandreas.sandberg@arm.com     * needs more simulation, it returns DrainState::Draining and
23311002Sandreas.sandberg@arm.com     * automatically enters the Draining state. Other return values
23411002Sandreas.sandberg@arm.com     * are invalid.
2359342SAndreas.Sandberg@arm.com     *
2369342SAndreas.Sandberg@arm.com     * @note An object that has entered the Drained state can be
23711002Sandreas.sandberg@arm.com     * disturbed by other objects in the system and consequently stop
23811002Sandreas.sandberg@arm.com     * being drained. These perturbations are not visible in the drain
23911002Sandreas.sandberg@arm.com     * state. The simulator therefore repeats the draining process
24011002Sandreas.sandberg@arm.com     * until all objects return DrainState::Drained on the first call
24111002Sandreas.sandberg@arm.com     * to drain().
2429342SAndreas.Sandberg@arm.com     *
24311002Sandreas.sandberg@arm.com     * @return DrainState::Drained if the object is drained at this
24411002Sandreas.sandberg@arm.com     * point in time, DrainState::Draining if it needs further
24510913Sandreas.sandberg@arm.com     * simulation.
2469342SAndreas.Sandberg@arm.com     */
24710913Sandreas.sandberg@arm.com    virtual DrainState drain() = 0;
2489342SAndreas.Sandberg@arm.com
2499342SAndreas.Sandberg@arm.com    /**
2509342SAndreas.Sandberg@arm.com     * Resume execution after a successful drain.
25110913Sandreas.sandberg@arm.com     */
25210913Sandreas.sandberg@arm.com    virtual void drainResume() {};
25310913Sandreas.sandberg@arm.com
25410913Sandreas.sandberg@arm.com    /**
25510913Sandreas.sandberg@arm.com     * Signal that an object is drained
2569342SAndreas.Sandberg@arm.com     *
25710913Sandreas.sandberg@arm.com     * This method is designed to be called whenever an object enters
25810913Sandreas.sandberg@arm.com     * into a state where it is ready to be drained. The method is
25910913Sandreas.sandberg@arm.com     * safe to call multiple times and there is no need to check that
26010913Sandreas.sandberg@arm.com     * draining has been requested before calling this method.
2619342SAndreas.Sandberg@arm.com     */
26210913Sandreas.sandberg@arm.com    void signalDrainDone() const {
26310913Sandreas.sandberg@arm.com        switch (_drainState) {
26410913Sandreas.sandberg@arm.com          case DrainState::Running:
26510913Sandreas.sandberg@arm.com          case DrainState::Drained:
26610913Sandreas.sandberg@arm.com            return;
26710913Sandreas.sandberg@arm.com          case DrainState::Draining:
26810913Sandreas.sandberg@arm.com            _drainState = DrainState::Drained;
26910913Sandreas.sandberg@arm.com            _drainManager.signalDrainDone();
27010913Sandreas.sandberg@arm.com            return;
27110913Sandreas.sandberg@arm.com        }
27210913Sandreas.sandberg@arm.com    }
2739342SAndreas.Sandberg@arm.com
27410913Sandreas.sandberg@arm.com  public:
27510913Sandreas.sandberg@arm.com    /** Return the current drain state of an object. */
27610913Sandreas.sandberg@arm.com    DrainState drainState() const { return _drainState; }
2779342SAndreas.Sandberg@arm.com
2789342SAndreas.Sandberg@arm.com  private:
27910913Sandreas.sandberg@arm.com    /** DrainManager interface to request a drain operation */
28010913Sandreas.sandberg@arm.com    DrainState dmDrain();
28110913Sandreas.sandberg@arm.com    /** DrainManager interface to request a resume operation */
28210913Sandreas.sandberg@arm.com    void dmDrainResume();
28310913Sandreas.sandberg@arm.com
28410913Sandreas.sandberg@arm.com    /** Convenience reference to the drain manager */
28510912Sandreas.sandberg@arm.com    DrainManager &_drainManager;
28610913Sandreas.sandberg@arm.com
28710913Sandreas.sandberg@arm.com    /**
28810913Sandreas.sandberg@arm.com     * Current drain state of the object. Needs to be mutable since
28910913Sandreas.sandberg@arm.com     * objects need to be able to signal that they have transitioned
29010913Sandreas.sandberg@arm.com     * into a Drained state even if the calling method is const.
29110913Sandreas.sandberg@arm.com     */
29210913Sandreas.sandberg@arm.com    mutable DrainState _drainState;
2939342SAndreas.Sandberg@arm.com};
2949342SAndreas.Sandberg@arm.com
2959342SAndreas.Sandberg@arm.com#endif
296