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