drain.hh revision 10912
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 */
14110912Sandreas.sandberg@arm.com    bool isDrained() { return _state == DrainState::Drained; }
14210912Sandreas.sandberg@arm.com
14310912Sandreas.sandberg@arm.com    /** Get the simulators global drain state */
14410912Sandreas.sandberg@arm.com    DrainState state() { 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>
1959342SAndreas.Sandberg@arm.com * <li>Call Drainable::drain() for every object in the
1969342SAndreas.Sandberg@arm.com *     system. Draining has completed if all of them return
1979342SAndreas.Sandberg@arm.com *     zero. Otherwise, the sum of the return values is loaded into
1989342SAndreas.Sandberg@arm.com *     the counter of the DrainManager. A pointer to the drain
1999342SAndreas.Sandberg@arm.com *     manager is passed as an argument to the drain() 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
20310912Sandreas.sandberg@arm.com *     manager. When the counter in the manager reaches zero, the
20410912Sandreas.sandberg@arm.com *     simulation stops.
2059342SAndreas.Sandberg@arm.com *
2069342SAndreas.Sandberg@arm.com * <li>Check if any object still needs draining, if so repeat the
2079342SAndreas.Sandberg@arm.com *     process above.
2089342SAndreas.Sandberg@arm.com *
2099342SAndreas.Sandberg@arm.com * <li>Serialize objects, switch CPU model, or change timing model.
2109342SAndreas.Sandberg@arm.com *
2119342SAndreas.Sandberg@arm.com * <li>Call Drainable::drainResume() and continue the simulation.
2129342SAndreas.Sandberg@arm.com * </ol>
2139342SAndreas.Sandberg@arm.com *
2149342SAndreas.Sandberg@arm.com */
2159342SAndreas.Sandberg@arm.comclass Drainable
2169342SAndreas.Sandberg@arm.com{
21710912Sandreas.sandberg@arm.com    friend class DrainManager;
21810912Sandreas.sandberg@arm.com
2199342SAndreas.Sandberg@arm.com  public:
2209342SAndreas.Sandberg@arm.com    Drainable();
2219342SAndreas.Sandberg@arm.com    virtual ~Drainable();
2229342SAndreas.Sandberg@arm.com
2239342SAndreas.Sandberg@arm.com    /**
2249342SAndreas.Sandberg@arm.com     * Determine if an object needs draining and register a
2259342SAndreas.Sandberg@arm.com     * DrainManager.
2269342SAndreas.Sandberg@arm.com     *
2279342SAndreas.Sandberg@arm.com     * When draining the state of an object, the simulator calls drain
2289342SAndreas.Sandberg@arm.com     * with a pointer to a drain manager. If the object does not need
2299342SAndreas.Sandberg@arm.com     * further simulation to drain internal buffers, it switched to
2309342SAndreas.Sandberg@arm.com     * the Drained state and returns 0, otherwise it switches to the
2319342SAndreas.Sandberg@arm.com     * Draining state and returns the number of times that it will
2329342SAndreas.Sandberg@arm.com     * call Event::process() on the drain event. Most objects are
2339342SAndreas.Sandberg@arm.com     * expected to return either 0 or 1.
2349342SAndreas.Sandberg@arm.com     *
2359342SAndreas.Sandberg@arm.com     * @note An object that has entered the Drained state can be
2369342SAndreas.Sandberg@arm.com     * disturbed by other objects in the system and consequently be
2379342SAndreas.Sandberg@arm.com     * forced to enter the Draining state again. The simulator
2389342SAndreas.Sandberg@arm.com     * therefore repeats the draining process until all objects return
2399342SAndreas.Sandberg@arm.com     * 0 on the first call to drain().
2409342SAndreas.Sandberg@arm.com     *
2419342SAndreas.Sandberg@arm.com     * @param drainManager DrainManager to use to inform the simulator
2429342SAndreas.Sandberg@arm.com     * when draining has completed.
2439342SAndreas.Sandberg@arm.com     *
2449342SAndreas.Sandberg@arm.com     * @return 0 if the object is ready for serialization now, >0 if
2459342SAndreas.Sandberg@arm.com     * it needs further simulation.
2469342SAndreas.Sandberg@arm.com     */
2479342SAndreas.Sandberg@arm.com    virtual unsigned int drain(DrainManager *drainManager) = 0;
2489342SAndreas.Sandberg@arm.com
2499342SAndreas.Sandberg@arm.com    /**
2509342SAndreas.Sandberg@arm.com     * Resume execution after a successful drain.
2519342SAndreas.Sandberg@arm.com     *
2529342SAndreas.Sandberg@arm.com     * @note This method is normally only called from the simulation
2539342SAndreas.Sandberg@arm.com     * scripts.
2549342SAndreas.Sandberg@arm.com     */
2559342SAndreas.Sandberg@arm.com    virtual void drainResume();
2569342SAndreas.Sandberg@arm.com
25710910Sandreas.sandberg@arm.com    DrainState getDrainState() const { return _drainState; }
2589342SAndreas.Sandberg@arm.com
2599342SAndreas.Sandberg@arm.com  protected:
26010910Sandreas.sandberg@arm.com    void setDrainState(DrainState new_state) { _drainState = new_state; }
2619342SAndreas.Sandberg@arm.com
2629342SAndreas.Sandberg@arm.com  private:
26310912Sandreas.sandberg@arm.com    DrainManager &_drainManager;
26410910Sandreas.sandberg@arm.com    DrainState _drainState;
2659342SAndreas.Sandberg@arm.com};
2669342SAndreas.Sandberg@arm.com
2679342SAndreas.Sandberg@arm.com#endif
268