drain.cc revision 11417
15647Sgblack@eecs.umich.edu/*
25647Sgblack@eecs.umich.edu * Copyright (c) 2012, 2015 ARM Limited
35647Sgblack@eecs.umich.edu * All rights reserved
45647Sgblack@eecs.umich.edu *
55647Sgblack@eecs.umich.edu * The license below extends only to copyright in the software and shall
65647Sgblack@eecs.umich.edu * not be construed as granting a license to any other intellectual
75647Sgblack@eecs.umich.edu * property including but not limited to intellectual property relating
85647Sgblack@eecs.umich.edu * to a hardware implementation of the functionality of the software
95647Sgblack@eecs.umich.edu * licensed hereunder.  You may use the software subject to the license
105647Sgblack@eecs.umich.edu * terms below provided that you ensure that this notice is replicated
115647Sgblack@eecs.umich.edu * unmodified and in its entirety in all distributions of the software,
125647Sgblack@eecs.umich.edu * modified or unmodified, in source code or in binary form.
135647Sgblack@eecs.umich.edu *
145647Sgblack@eecs.umich.edu * Redistribution and use in source and binary forms, with or without
155647Sgblack@eecs.umich.edu * modification, are permitted provided that the following conditions are
165647Sgblack@eecs.umich.edu * met: redistributions of source code must retain the above copyright
175647Sgblack@eecs.umich.edu * notice, this list of conditions and the following disclaimer;
185647Sgblack@eecs.umich.edu * redistributions in binary form must reproduce the above copyright
195647Sgblack@eecs.umich.edu * notice, this list of conditions and the following disclaimer in the
205647Sgblack@eecs.umich.edu * documentation and/or other materials provided with the distribution;
215647Sgblack@eecs.umich.edu * neither the name of the copyright holders nor the names of its
225647Sgblack@eecs.umich.edu * contributors may be used to endorse or promote products derived from
235647Sgblack@eecs.umich.edu * this software without specific prior written permission.
245647Sgblack@eecs.umich.edu *
255647Sgblack@eecs.umich.edu * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
265647Sgblack@eecs.umich.edu * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
275647Sgblack@eecs.umich.edu * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
285647Sgblack@eecs.umich.edu * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
295647Sgblack@eecs.umich.edu * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
305647Sgblack@eecs.umich.edu * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
315647Sgblack@eecs.umich.edu * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
325647Sgblack@eecs.umich.edu * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
335647Sgblack@eecs.umich.edu * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
345647Sgblack@eecs.umich.edu * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
355647Sgblack@eecs.umich.edu * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
365647Sgblack@eecs.umich.edu *
375647Sgblack@eecs.umich.edu * Authors: Andreas Sandberg
385647Sgblack@eecs.umich.edu */
395647Sgblack@eecs.umich.edu
405647Sgblack@eecs.umich.edu#include "sim/drain.hh"
415647Sgblack@eecs.umich.edu
425647Sgblack@eecs.umich.edu#include "base/misc.hh"
435647Sgblack@eecs.umich.edu#include "base/trace.hh"
445647Sgblack@eecs.umich.edu#include "debug/Drain.hh"
455647Sgblack@eecs.umich.edu#include "sim/sim_exit.hh"
465647Sgblack@eecs.umich.edu#include "sim/sim_object.hh"
475647Sgblack@eecs.umich.edu
485647Sgblack@eecs.umich.eduDrainManager DrainManager::_instance;
495647Sgblack@eecs.umich.edu
505647Sgblack@eecs.umich.eduDrainManager::DrainManager()
515647Sgblack@eecs.umich.edu    : _count(0),
525647Sgblack@eecs.umich.edu      _state(DrainState::Running)
535647Sgblack@eecs.umich.edu{
545647Sgblack@eecs.umich.edu}
555647Sgblack@eecs.umich.edu
565647Sgblack@eecs.umich.eduDrainManager::~DrainManager()
575647Sgblack@eecs.umich.edu{
585648Sgblack@eecs.umich.edu}
595647Sgblack@eecs.umich.edu
605654Sgblack@eecs.umich.edubool
615647Sgblack@eecs.umich.eduDrainManager::tryDrain()
625654Sgblack@eecs.umich.edu{
636046Sgblack@eecs.umich.edu    panic_if(_state == DrainState::Drained,
645647Sgblack@eecs.umich.edu             "Trying to drain a drained system\n");
655648Sgblack@eecs.umich.edu
665648Sgblack@eecs.umich.edu    panic_if(_count != 0,
675647Sgblack@eecs.umich.edu             "Drain counter must be zero at the start of a drain cycle\n");
685647Sgblack@eecs.umich.edu
695647Sgblack@eecs.umich.edu    DPRINTF(Drain, "Trying to drain %u objects.\n", drainableCount());
705647Sgblack@eecs.umich.edu    _state = DrainState::Draining;
715647Sgblack@eecs.umich.edu    for (auto *obj : _allDrainable) {
725647Sgblack@eecs.umich.edu        DrainState status = obj->dmDrain();
735647Sgblack@eecs.umich.edu        if (DTRACE(Drain) && status != DrainState::Drained) {
745647Sgblack@eecs.umich.edu            SimObject *temp = dynamic_cast<SimObject*>(obj);
755647Sgblack@eecs.umich.edu            if (temp)
765648Sgblack@eecs.umich.edu                DPRINTF(Drain, "Failed to drain %s\n", temp->name());
775647Sgblack@eecs.umich.edu        }
785648Sgblack@eecs.umich.edu        _count += status == DrainState::Drained ? 0 : 1;
795648Sgblack@eecs.umich.edu    }
805648Sgblack@eecs.umich.edu
815648Sgblack@eecs.umich.edu    if (_count == 0) {
825648Sgblack@eecs.umich.edu        DPRINTF(Drain, "Drain done.\n");
835648Sgblack@eecs.umich.edu        _state = DrainState::Drained;
845648Sgblack@eecs.umich.edu        return true;
855648Sgblack@eecs.umich.edu    } else {
865648Sgblack@eecs.umich.edu        DPRINTF(Drain, "Need another drain cycle. %u/%u objects not ready.\n",
875648Sgblack@eecs.umich.edu                _count, drainableCount());
885648Sgblack@eecs.umich.edu        return false;
895648Sgblack@eecs.umich.edu    }
905648Sgblack@eecs.umich.edu}
915648Sgblack@eecs.umich.edu
925648Sgblack@eecs.umich.eduvoid
935648Sgblack@eecs.umich.eduDrainManager::resume()
945648Sgblack@eecs.umich.edu{
955648Sgblack@eecs.umich.edu    panic_if(_state == DrainState::Running,
965648Sgblack@eecs.umich.edu             "Trying to resume a system that is already running\n");
975648Sgblack@eecs.umich.edu
985648Sgblack@eecs.umich.edu    warn_if(_state == DrainState::Draining,
995648Sgblack@eecs.umich.edu            "Resuming a system that isn't fully drained, this is untested and "
1005648Sgblack@eecs.umich.edu            "likely to break\n");
1015648Sgblack@eecs.umich.edu
1025648Sgblack@eecs.umich.edu    panic_if(_count != 0,
1035648Sgblack@eecs.umich.edu             "Resume called in the middle of a drain cycle. %u objects "
1045648Sgblack@eecs.umich.edu             "left to drain.\n", _count);
1055648Sgblack@eecs.umich.edu
1065648Sgblack@eecs.umich.edu    DPRINTF(Drain, "Resuming %u objects.\n", drainableCount());
1075648Sgblack@eecs.umich.edu    _state = DrainState::Running;
1085648Sgblack@eecs.umich.edu    for (auto *obj : _allDrainable)
1095648Sgblack@eecs.umich.edu        obj->dmDrainResume();
1105648Sgblack@eecs.umich.edu}
1115648Sgblack@eecs.umich.edu
1125648Sgblack@eecs.umich.eduvoid
1135648Sgblack@eecs.umich.eduDrainManager::preCheckpointRestore()
1145648Sgblack@eecs.umich.edu{
1155648Sgblack@eecs.umich.edu    panic_if(_state != DrainState::Running,
1165648Sgblack@eecs.umich.edu             "preCheckpointRestore() called on a system that isn't in the "
1175648Sgblack@eecs.umich.edu             "Running state.\n");
1185648Sgblack@eecs.umich.edu
1195648Sgblack@eecs.umich.edu    DPRINTF(Drain, "Applying pre-restore fixes to %u objects.\n",
1205648Sgblack@eecs.umich.edu            drainableCount());
1215648Sgblack@eecs.umich.edu    _state = DrainState::Drained;
1225648Sgblack@eecs.umich.edu    for (auto *obj : _allDrainable)
1235648Sgblack@eecs.umich.edu        obj->_drainState = DrainState::Drained;
1245648Sgblack@eecs.umich.edu}
1255648Sgblack@eecs.umich.edu
1265648Sgblack@eecs.umich.eduvoid
1275648Sgblack@eecs.umich.eduDrainManager::signalDrainDone()
1285648Sgblack@eecs.umich.edu{
1295648Sgblack@eecs.umich.edu    if (--_count == 0) {
1305648Sgblack@eecs.umich.edu        DPRINTF(Drain, "All %u objects drained..\n", drainableCount());
1315648Sgblack@eecs.umich.edu        exitSimLoop("Finished drain", 0);
1325648Sgblack@eecs.umich.edu    }
1335648Sgblack@eecs.umich.edu}
1345648Sgblack@eecs.umich.edu
1355648Sgblack@eecs.umich.edu
1365648Sgblack@eecs.umich.eduvoid
1375648Sgblack@eecs.umich.eduDrainManager::registerDrainable(Drainable *obj)
1385648Sgblack@eecs.umich.edu{
1395648Sgblack@eecs.umich.edu    std::lock_guard<std::mutex> lock(globalLock);
1405648Sgblack@eecs.umich.edu    _allDrainable.insert(obj);
1415648Sgblack@eecs.umich.edu}
1425648Sgblack@eecs.umich.edu
1435648Sgblack@eecs.umich.eduvoid
1445648Sgblack@eecs.umich.eduDrainManager::unregisterDrainable(Drainable *obj)
1455648Sgblack@eecs.umich.edu{
1465648Sgblack@eecs.umich.edu    std::lock_guard<std::mutex> lock(globalLock);
1475648Sgblack@eecs.umich.edu    _allDrainable.erase(obj);
1485648Sgblack@eecs.umich.edu}
1495648Sgblack@eecs.umich.edu
1505648Sgblack@eecs.umich.edusize_t
1515648Sgblack@eecs.umich.eduDrainManager::drainableCount() const
1525648Sgblack@eecs.umich.edu{
1535648Sgblack@eecs.umich.edu    std::lock_guard<std::mutex> lock(globalLock);
1545648Sgblack@eecs.umich.edu    return _allDrainable.size();
1555648Sgblack@eecs.umich.edu}
1565648Sgblack@eecs.umich.edu
1575648Sgblack@eecs.umich.edu
1585648Sgblack@eecs.umich.edu
1595648Sgblack@eecs.umich.eduDrainable::Drainable()
1605648Sgblack@eecs.umich.edu    : _drainManager(DrainManager::instance()),
1615648Sgblack@eecs.umich.edu      _drainState(_drainManager.state())
1625648Sgblack@eecs.umich.edu{
1635648Sgblack@eecs.umich.edu    _drainManager.registerDrainable(this);
1645648Sgblack@eecs.umich.edu}
1655648Sgblack@eecs.umich.edu
1665648Sgblack@eecs.umich.eduDrainable::~Drainable()
1675648Sgblack@eecs.umich.edu{
1685648Sgblack@eecs.umich.edu    _drainManager.unregisterDrainable(this);
1695648Sgblack@eecs.umich.edu}
1705648Sgblack@eecs.umich.edu
1715648Sgblack@eecs.umich.eduDrainState
1725648Sgblack@eecs.umich.eduDrainable::dmDrain()
1735648Sgblack@eecs.umich.edu{
1745648Sgblack@eecs.umich.edu    _drainState = DrainState::Draining;
1755648Sgblack@eecs.umich.edu    _drainState = drain();
1765648Sgblack@eecs.umich.edu    assert(_drainState == DrainState::Draining ||
1775648Sgblack@eecs.umich.edu           _drainState == DrainState::Drained);
1785648Sgblack@eecs.umich.edu
1795648Sgblack@eecs.umich.edu    return _drainState;
1805648Sgblack@eecs.umich.edu}
1815648Sgblack@eecs.umich.edu
1825648Sgblack@eecs.umich.eduvoid
1835648Sgblack@eecs.umich.eduDrainable::dmDrainResume()
1845648Sgblack@eecs.umich.edu{
1855648Sgblack@eecs.umich.edu    panic_if(_drainState != DrainState::Drained,
1865648Sgblack@eecs.umich.edu             "Trying to resume an object that hasn't been drained\n");
1875648Sgblack@eecs.umich.edu
1885648Sgblack@eecs.umich.edu    _drainState = DrainState::Running;
1895648Sgblack@eecs.umich.edu    drainResume();
1905648Sgblack@eecs.umich.edu}
1915648Sgblack@eecs.umich.edu