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#include "sim/drain.hh" 4110912Sandreas.sandberg@arm.com 4211859Sandreas.hansson@arm.com#include <algorithm> 4311859Sandreas.hansson@arm.com 4412334Sgabeblack@google.com#include "base/logging.hh" 4510912Sandreas.sandberg@arm.com#include "base/trace.hh" 4610912Sandreas.sandberg@arm.com#include "debug/Drain.hh" 479342SAndreas.Sandberg@arm.com#include "sim/sim_exit.hh" 4811417Ssascha.bischoff@arm.com#include "sim/sim_object.hh" 499342SAndreas.Sandberg@arm.com 5010912Sandreas.sandberg@arm.comDrainManager DrainManager::_instance; 5110912Sandreas.sandberg@arm.com 529342SAndreas.Sandberg@arm.comDrainManager::DrainManager() 5310912Sandreas.sandberg@arm.com : _count(0), 5410912Sandreas.sandberg@arm.com _state(DrainState::Running) 559342SAndreas.Sandberg@arm.com{ 569342SAndreas.Sandberg@arm.com} 579342SAndreas.Sandberg@arm.com 589342SAndreas.Sandberg@arm.comDrainManager::~DrainManager() 599342SAndreas.Sandberg@arm.com{ 609342SAndreas.Sandberg@arm.com} 619342SAndreas.Sandberg@arm.com 6210912Sandreas.sandberg@arm.combool 6310912Sandreas.sandberg@arm.comDrainManager::tryDrain() 649342SAndreas.Sandberg@arm.com{ 6510912Sandreas.sandberg@arm.com panic_if(_state == DrainState::Drained, 6610912Sandreas.sandberg@arm.com "Trying to drain a drained system\n"); 6710912Sandreas.sandberg@arm.com 6810912Sandreas.sandberg@arm.com panic_if(_count != 0, 6910912Sandreas.sandberg@arm.com "Drain counter must be zero at the start of a drain cycle\n"); 7010912Sandreas.sandberg@arm.com 7110912Sandreas.sandberg@arm.com DPRINTF(Drain, "Trying to drain %u objects.\n", drainableCount()); 7210912Sandreas.sandberg@arm.com _state = DrainState::Draining; 7311417Ssascha.bischoff@arm.com for (auto *obj : _allDrainable) { 7411417Ssascha.bischoff@arm.com DrainState status = obj->dmDrain(); 7511417Ssascha.bischoff@arm.com if (DTRACE(Drain) && status != DrainState::Drained) { 7611417Ssascha.bischoff@arm.com SimObject *temp = dynamic_cast<SimObject*>(obj); 7711417Ssascha.bischoff@arm.com if (temp) 7811417Ssascha.bischoff@arm.com DPRINTF(Drain, "Failed to drain %s\n", temp->name()); 7911417Ssascha.bischoff@arm.com } 8011417Ssascha.bischoff@arm.com _count += status == DrainState::Drained ? 0 : 1; 8111417Ssascha.bischoff@arm.com } 8210912Sandreas.sandberg@arm.com 8310912Sandreas.sandberg@arm.com if (_count == 0) { 8410912Sandreas.sandberg@arm.com DPRINTF(Drain, "Drain done.\n"); 8510912Sandreas.sandberg@arm.com _state = DrainState::Drained; 8610912Sandreas.sandberg@arm.com return true; 8710912Sandreas.sandberg@arm.com } else { 8810912Sandreas.sandberg@arm.com DPRINTF(Drain, "Need another drain cycle. %u/%u objects not ready.\n", 8910912Sandreas.sandberg@arm.com _count, drainableCount()); 9010912Sandreas.sandberg@arm.com return false; 9110912Sandreas.sandberg@arm.com } 929342SAndreas.Sandberg@arm.com} 939342SAndreas.Sandberg@arm.com 9410912Sandreas.sandberg@arm.comvoid 9510912Sandreas.sandberg@arm.comDrainManager::resume() 9610912Sandreas.sandberg@arm.com{ 9710912Sandreas.sandberg@arm.com panic_if(_state == DrainState::Running, 9810912Sandreas.sandberg@arm.com "Trying to resume a system that is already running\n"); 9910912Sandreas.sandberg@arm.com 10010912Sandreas.sandberg@arm.com warn_if(_state == DrainState::Draining, 10110912Sandreas.sandberg@arm.com "Resuming a system that isn't fully drained, this is untested and " 10210912Sandreas.sandberg@arm.com "likely to break\n"); 10310912Sandreas.sandberg@arm.com 10411937Sandreas.sandberg@arm.com panic_if(_state == DrainState::Resuming, 10511937Sandreas.sandberg@arm.com "Resuming a system that is already trying to resume. This should " 10611937Sandreas.sandberg@arm.com "never happen.\n"); 10711937Sandreas.sandberg@arm.com 10810912Sandreas.sandberg@arm.com panic_if(_count != 0, 10910912Sandreas.sandberg@arm.com "Resume called in the middle of a drain cycle. %u objects " 11010912Sandreas.sandberg@arm.com "left to drain.\n", _count); 11110912Sandreas.sandberg@arm.com 11211937Sandreas.sandberg@arm.com // At this point in time the DrainManager and all objects will be 11311937Sandreas.sandberg@arm.com // in the the Drained state. New objects (i.e., objects created 11411937Sandreas.sandberg@arm.com // while resuming) will inherit the Resuming state from the 11511937Sandreas.sandberg@arm.com // DrainManager, which means we have to resume objects until all 11611937Sandreas.sandberg@arm.com // objects are in the Running state. 11711937Sandreas.sandberg@arm.com _state = DrainState::Resuming; 11811937Sandreas.sandberg@arm.com 11911937Sandreas.sandberg@arm.com do { 12011937Sandreas.sandberg@arm.com DPRINTF(Drain, "Resuming %u objects.\n", drainableCount()); 12111937Sandreas.sandberg@arm.com for (auto *obj : _allDrainable) { 12211937Sandreas.sandberg@arm.com if (obj->drainState() != DrainState::Running) { 12311937Sandreas.sandberg@arm.com assert(obj->drainState() == DrainState::Drained || 12411937Sandreas.sandberg@arm.com obj->drainState() == DrainState::Resuming); 12511937Sandreas.sandberg@arm.com obj->dmDrainResume(); 12611937Sandreas.sandberg@arm.com } 12711937Sandreas.sandberg@arm.com } 12811937Sandreas.sandberg@arm.com } while (!allInState(DrainState::Running)); 12911937Sandreas.sandberg@arm.com 13010912Sandreas.sandberg@arm.com _state = DrainState::Running; 13110912Sandreas.sandberg@arm.com} 13210912Sandreas.sandberg@arm.com 13310912Sandreas.sandberg@arm.comvoid 13410912Sandreas.sandberg@arm.comDrainManager::preCheckpointRestore() 13510912Sandreas.sandberg@arm.com{ 13610912Sandreas.sandberg@arm.com panic_if(_state != DrainState::Running, 13710912Sandreas.sandberg@arm.com "preCheckpointRestore() called on a system that isn't in the " 13810912Sandreas.sandberg@arm.com "Running state.\n"); 13910912Sandreas.sandberg@arm.com 14010912Sandreas.sandberg@arm.com DPRINTF(Drain, "Applying pre-restore fixes to %u objects.\n", 14110912Sandreas.sandberg@arm.com drainableCount()); 14210912Sandreas.sandberg@arm.com _state = DrainState::Drained; 14310912Sandreas.sandberg@arm.com for (auto *obj : _allDrainable) 14410912Sandreas.sandberg@arm.com obj->_drainState = DrainState::Drained; 14510912Sandreas.sandberg@arm.com} 14610912Sandreas.sandberg@arm.com 14710912Sandreas.sandberg@arm.comvoid 14810912Sandreas.sandberg@arm.comDrainManager::signalDrainDone() 14910912Sandreas.sandberg@arm.com{ 15011859Sandreas.hansson@arm.com assert(_count > 0); 15110912Sandreas.sandberg@arm.com if (--_count == 0) { 15210912Sandreas.sandberg@arm.com DPRINTF(Drain, "All %u objects drained..\n", drainableCount()); 15310912Sandreas.sandberg@arm.com exitSimLoop("Finished drain", 0); 15410912Sandreas.sandberg@arm.com } 15510912Sandreas.sandberg@arm.com} 15610912Sandreas.sandberg@arm.com 15710912Sandreas.sandberg@arm.com 15810912Sandreas.sandberg@arm.comvoid 15910912Sandreas.sandberg@arm.comDrainManager::registerDrainable(Drainable *obj) 16010912Sandreas.sandberg@arm.com{ 16110912Sandreas.sandberg@arm.com std::lock_guard<std::mutex> lock(globalLock); 16211859Sandreas.hansson@arm.com assert(std::find(_allDrainable.begin(), _allDrainable.end(), obj) == 16311859Sandreas.hansson@arm.com _allDrainable.end()); 16411859Sandreas.hansson@arm.com _allDrainable.push_back(obj); 16510912Sandreas.sandberg@arm.com} 16610912Sandreas.sandberg@arm.com 16710912Sandreas.sandberg@arm.comvoid 16810912Sandreas.sandberg@arm.comDrainManager::unregisterDrainable(Drainable *obj) 16910912Sandreas.sandberg@arm.com{ 17010912Sandreas.sandberg@arm.com std::lock_guard<std::mutex> lock(globalLock); 17111859Sandreas.hansson@arm.com auto o = std::find(_allDrainable.begin(), _allDrainable.end(), obj); 17211859Sandreas.hansson@arm.com assert(o != _allDrainable.end()); 17311859Sandreas.hansson@arm.com _allDrainable.erase(o); 17410912Sandreas.sandberg@arm.com} 17510912Sandreas.sandberg@arm.com 17611937Sandreas.sandberg@arm.combool 17711937Sandreas.sandberg@arm.comDrainManager::allInState(DrainState state) const 17811937Sandreas.sandberg@arm.com{ 17911937Sandreas.sandberg@arm.com for (const auto *obj : _allDrainable) { 18011937Sandreas.sandberg@arm.com if (obj->drainState() != state) 18111937Sandreas.sandberg@arm.com return false; 18211937Sandreas.sandberg@arm.com } 18311937Sandreas.sandberg@arm.com 18411937Sandreas.sandberg@arm.com return true; 18511937Sandreas.sandberg@arm.com} 18611937Sandreas.sandberg@arm.com 18710912Sandreas.sandberg@arm.comsize_t 18810912Sandreas.sandberg@arm.comDrainManager::drainableCount() const 18910912Sandreas.sandberg@arm.com{ 19010912Sandreas.sandberg@arm.com std::lock_guard<std::mutex> lock(globalLock); 19110912Sandreas.sandberg@arm.com return _allDrainable.size(); 19210912Sandreas.sandberg@arm.com} 19310912Sandreas.sandberg@arm.com 1949342SAndreas.Sandberg@arm.com 1959342SAndreas.Sandberg@arm.com 1969342SAndreas.Sandberg@arm.comDrainable::Drainable() 19710912Sandreas.sandberg@arm.com : _drainManager(DrainManager::instance()), 19810998Sandreas.sandberg@arm.com _drainState(_drainManager.state()) 1999342SAndreas.Sandberg@arm.com{ 20010912Sandreas.sandberg@arm.com _drainManager.registerDrainable(this); 2019342SAndreas.Sandberg@arm.com} 2029342SAndreas.Sandberg@arm.com 2039342SAndreas.Sandberg@arm.comDrainable::~Drainable() 2049342SAndreas.Sandberg@arm.com{ 20510912Sandreas.sandberg@arm.com _drainManager.unregisterDrainable(this); 2069342SAndreas.Sandberg@arm.com} 2079342SAndreas.Sandberg@arm.com 20810913Sandreas.sandberg@arm.comDrainState 20910913Sandreas.sandberg@arm.comDrainable::dmDrain() 21010913Sandreas.sandberg@arm.com{ 21110913Sandreas.sandberg@arm.com _drainState = DrainState::Draining; 21210913Sandreas.sandberg@arm.com _drainState = drain(); 21310913Sandreas.sandberg@arm.com assert(_drainState == DrainState::Draining || 21410913Sandreas.sandberg@arm.com _drainState == DrainState::Drained); 21510913Sandreas.sandberg@arm.com 21610913Sandreas.sandberg@arm.com return _drainState; 21710913Sandreas.sandberg@arm.com} 21810913Sandreas.sandberg@arm.com 2199342SAndreas.Sandberg@arm.comvoid 22010913Sandreas.sandberg@arm.comDrainable::dmDrainResume() 2219342SAndreas.Sandberg@arm.com{ 22211937Sandreas.sandberg@arm.com panic_if(_drainState != DrainState::Drained && 22311937Sandreas.sandberg@arm.com _drainState != DrainState::Resuming, 22410913Sandreas.sandberg@arm.com "Trying to resume an object that hasn't been drained\n"); 22510913Sandreas.sandberg@arm.com 22610910Sandreas.sandberg@arm.com _drainState = DrainState::Running; 22710913Sandreas.sandberg@arm.com drainResume(); 2289342SAndreas.Sandberg@arm.com} 229