110249Sstephan.diestelhorst@arm.com/* 210249Sstephan.diestelhorst@arm.com * Copyright (c) 2013-2014 ARM Limited 310249Sstephan.diestelhorst@arm.com * All rights reserved 410249Sstephan.diestelhorst@arm.com * 510249Sstephan.diestelhorst@arm.com * The license below extends only to copyright in the software and shall 610249Sstephan.diestelhorst@arm.com * not be construed as granting a license to any other intellectual 710249Sstephan.diestelhorst@arm.com * property including but not limited to intellectual property relating 810249Sstephan.diestelhorst@arm.com * to a hardware implementation of the functionality of the software 910249Sstephan.diestelhorst@arm.com * licensed hereunder. You may use the software subject to the license 1010249Sstephan.diestelhorst@arm.com * terms below provided that you ensure that this notice is replicated 1110249Sstephan.diestelhorst@arm.com * unmodified and in its entirety in all distributions of the software, 1210249Sstephan.diestelhorst@arm.com * modified or unmodified, in source code or in binary form. 1310249Sstephan.diestelhorst@arm.com * 1410249Sstephan.diestelhorst@arm.com * Redistribution and use in source and binary forms, with or without 1510249Sstephan.diestelhorst@arm.com * modification, are permitted provided that the following conditions are 1610249Sstephan.diestelhorst@arm.com * met: redistributions of source code must retain the above copyright 1710249Sstephan.diestelhorst@arm.com * notice, this list of conditions and the following disclaimer; 1810249Sstephan.diestelhorst@arm.com * redistributions in binary form must reproduce the above copyright 1910249Sstephan.diestelhorst@arm.com * notice, this list of conditions and the following disclaimer in the 2010249Sstephan.diestelhorst@arm.com * documentation and/or other materials provided with the distribution; 2110249Sstephan.diestelhorst@arm.com * neither the name of the copyright holders nor the names of its 2210249Sstephan.diestelhorst@arm.com * contributors may be used to endorse or promote products derived from 2310249Sstephan.diestelhorst@arm.com * this software without specific prior written permission. 2410249Sstephan.diestelhorst@arm.com * 2510249Sstephan.diestelhorst@arm.com * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 2610249Sstephan.diestelhorst@arm.com * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 2710249Sstephan.diestelhorst@arm.com * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 2810249Sstephan.diestelhorst@arm.com * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 2910249Sstephan.diestelhorst@arm.com * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 3010249Sstephan.diestelhorst@arm.com * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 3110249Sstephan.diestelhorst@arm.com * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 3210249Sstephan.diestelhorst@arm.com * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 3310249Sstephan.diestelhorst@arm.com * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 3410249Sstephan.diestelhorst@arm.com * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 3510249Sstephan.diestelhorst@arm.com * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 3610249Sstephan.diestelhorst@arm.com * 3710249Sstephan.diestelhorst@arm.com * Authors: Vasileios Spiliopoulos 3810249Sstephan.diestelhorst@arm.com * Akash Bagdia 3910249Sstephan.diestelhorst@arm.com * Stephan Diestelhorst 4010249Sstephan.diestelhorst@arm.com */ 4110249Sstephan.diestelhorst@arm.com 4211793Sbrandon.potter@amd.com#include "sim/dvfs_handler.hh" 4311793Sbrandon.potter@amd.com 4410249Sstephan.diestelhorst@arm.com#include <set> 4510249Sstephan.diestelhorst@arm.com#include <utility> 4610249Sstephan.diestelhorst@arm.com 4712334Sgabeblack@google.com#include "base/logging.hh" 4811800Sbrandon.potter@amd.com#include "base/trace.hh" 4910249Sstephan.diestelhorst@arm.com#include "debug/DVFS.hh" 5010249Sstephan.diestelhorst@arm.com#include "params/DVFSHandler.hh" 5110249Sstephan.diestelhorst@arm.com#include "sim/clock_domain.hh" 5211800Sbrandon.potter@amd.com#include "sim/eventq_impl.hh" 5310249Sstephan.diestelhorst@arm.com#include "sim/stat_control.hh" 5410249Sstephan.diestelhorst@arm.com#include "sim/voltage_domain.hh" 5510249Sstephan.diestelhorst@arm.com 5610249Sstephan.diestelhorst@arm.com// 5710249Sstephan.diestelhorst@arm.com// 5810249Sstephan.diestelhorst@arm.com// DVFSHandler methods implementation 5910249Sstephan.diestelhorst@arm.com// 6010249Sstephan.diestelhorst@arm.com 6110249Sstephan.diestelhorst@arm.comDVFSHandler::DVFSHandler(const Params *p) 6210249Sstephan.diestelhorst@arm.com : SimObject(p), 6310249Sstephan.diestelhorst@arm.com sysClkDomain(p->sys_clk_domain), 6410249Sstephan.diestelhorst@arm.com enableHandler(p->enable), 6510249Sstephan.diestelhorst@arm.com _transLatency(p->transition_latency) 6610249Sstephan.diestelhorst@arm.com{ 6710249Sstephan.diestelhorst@arm.com // Check supplied list of domains for sanity and add them to the 6810249Sstephan.diestelhorst@arm.com // domain ID -> domain* hash 6911321Ssteve.reinhardt@amd.com for (auto dit = p->domains.begin(); dit != p->domains.end(); ++dit) { 7010249Sstephan.diestelhorst@arm.com SrcClockDomain *d = *dit; 7110249Sstephan.diestelhorst@arm.com DomainID domain_id = d->domainID(); 7210249Sstephan.diestelhorst@arm.com 7310249Sstephan.diestelhorst@arm.com fatal_if(sysClkDomain == d, "DVFS: Domain config list has a "\ 7410249Sstephan.diestelhorst@arm.com "system clk domain entry"); 7510249Sstephan.diestelhorst@arm.com fatal_if(domain_id == SrcClockDomain::emptyDomainID, 7610249Sstephan.diestelhorst@arm.com "DVFS: Controlled domain %s needs to have a properly "\ 7710249Sstephan.diestelhorst@arm.com " assigned ID.\n", d->name()); 7810249Sstephan.diestelhorst@arm.com 7910249Sstephan.diestelhorst@arm.com auto entry = std::make_pair(domain_id, d); 8010249Sstephan.diestelhorst@arm.com bool new_elem = domains.insert(entry).second; 8110249Sstephan.diestelhorst@arm.com fatal_if(!new_elem, "DVFS: Domain %s with ID %d does not have a "\ 8210249Sstephan.diestelhorst@arm.com "unique ID.\n", d->name(), domain_id); 8310249Sstephan.diestelhorst@arm.com 8410249Sstephan.diestelhorst@arm.com // Create a dedicated event slot per known domain ID 8510249Sstephan.diestelhorst@arm.com UpdateEvent *event = &updatePerfLevelEvents[domain_id]; 8610249Sstephan.diestelhorst@arm.com event->domainIDToSet = d->domainID(); 8710395Sstephan.diestelhorst@arm.com 8810395Sstephan.diestelhorst@arm.com // Add domain ID to the list of domains 8910395Sstephan.diestelhorst@arm.com domainIDList.push_back(d->domainID()); 9010249Sstephan.diestelhorst@arm.com } 9110249Sstephan.diestelhorst@arm.com UpdateEvent::dvfsHandler = this; 9210249Sstephan.diestelhorst@arm.com} 9310249Sstephan.diestelhorst@arm.com 9410249Sstephan.diestelhorst@arm.comDVFSHandler *DVFSHandler::UpdateEvent::dvfsHandler; 9510249Sstephan.diestelhorst@arm.com 9610395Sstephan.diestelhorst@arm.comDVFSHandler::DomainID 9710395Sstephan.diestelhorst@arm.comDVFSHandler::domainID(uint32_t index) const 9810395Sstephan.diestelhorst@arm.com{ 9910395Sstephan.diestelhorst@arm.com fatal_if(index >= numDomains(), "DVFS: Requested index out of "\ 10010395Sstephan.diestelhorst@arm.com "bound, max value %d\n", (domainIDList.size() - 1)); 10110395Sstephan.diestelhorst@arm.com 10210395Sstephan.diestelhorst@arm.com assert(domains.find(domainIDList[index]) != domains.end()); 10310395Sstephan.diestelhorst@arm.com 10410395Sstephan.diestelhorst@arm.com return domainIDList[index]; 10510395Sstephan.diestelhorst@arm.com} 10610395Sstephan.diestelhorst@arm.com 10710249Sstephan.diestelhorst@arm.combool 10810249Sstephan.diestelhorst@arm.comDVFSHandler::validDomainID(DomainID domain_id) const 10910249Sstephan.diestelhorst@arm.com{ 11010249Sstephan.diestelhorst@arm.com assert(isEnabled()); 11110249Sstephan.diestelhorst@arm.com // This is ensure that the domain id as requested by the software is 11210249Sstephan.diestelhorst@arm.com // availabe in the handler. 11310249Sstephan.diestelhorst@arm.com if (domains.find(domain_id) != domains.end()) 11410249Sstephan.diestelhorst@arm.com return true; 11510249Sstephan.diestelhorst@arm.com warn("DVFS: invalid domain ID %d, the DVFS handler does not handle this "\ 11610249Sstephan.diestelhorst@arm.com "domain\n", domain_id); 11710249Sstephan.diestelhorst@arm.com return false; 11810249Sstephan.diestelhorst@arm.com} 11910249Sstephan.diestelhorst@arm.com 12010249Sstephan.diestelhorst@arm.combool 12110249Sstephan.diestelhorst@arm.comDVFSHandler::perfLevel(DomainID domain_id, PerfLevel perf_level) 12210249Sstephan.diestelhorst@arm.com{ 12310249Sstephan.diestelhorst@arm.com assert(isEnabled()); 12410249Sstephan.diestelhorst@arm.com 12510249Sstephan.diestelhorst@arm.com DPRINTF(DVFS, "DVFS: setPerfLevel domain %d -> %d\n", domain_id, perf_level); 12610249Sstephan.diestelhorst@arm.com 12710249Sstephan.diestelhorst@arm.com auto d = findDomain(domain_id); 12810249Sstephan.diestelhorst@arm.com if (!d->validPerfLevel(perf_level)) { 12910249Sstephan.diestelhorst@arm.com warn("DVFS: invalid performance level %d for domain ID %d, request "\ 13010249Sstephan.diestelhorst@arm.com "ignored\n", perf_level, domain_id); 13110249Sstephan.diestelhorst@arm.com return false; 13210249Sstephan.diestelhorst@arm.com } 13310249Sstephan.diestelhorst@arm.com 13410249Sstephan.diestelhorst@arm.com UpdateEvent *update_event = &updatePerfLevelEvents[domain_id]; 13510249Sstephan.diestelhorst@arm.com // Drop an old DVFS change request once we have established that this is a 13610249Sstephan.diestelhorst@arm.com // reasonable request 13710249Sstephan.diestelhorst@arm.com if (update_event->scheduled()) { 13810249Sstephan.diestelhorst@arm.com DPRINTF(DVFS, "DVFS: Overwriting the previous DVFS event.\n"); 13910249Sstephan.diestelhorst@arm.com deschedule(update_event); 14010249Sstephan.diestelhorst@arm.com } 14110249Sstephan.diestelhorst@arm.com 14210249Sstephan.diestelhorst@arm.com update_event->perfLevelToSet = perf_level; 14310249Sstephan.diestelhorst@arm.com 14410249Sstephan.diestelhorst@arm.com // State changes that restore to the current state (and / or overwrite a not 14510249Sstephan.diestelhorst@arm.com // yet completed in-flight request) will be squashed 14610249Sstephan.diestelhorst@arm.com if (d->perfLevel() == perf_level) { 14710249Sstephan.diestelhorst@arm.com DPRINTF(DVFS, "DVFS: Ignoring ineffective performance level change "\ 14810249Sstephan.diestelhorst@arm.com "%d -> %d\n", d->perfLevel(), perf_level); 14910249Sstephan.diestelhorst@arm.com return false; 15010249Sstephan.diestelhorst@arm.com } 15110249Sstephan.diestelhorst@arm.com 15210249Sstephan.diestelhorst@arm.com // At this point, a new transition will certainly take place -> schedule 15310249Sstephan.diestelhorst@arm.com Tick when = curTick() + _transLatency; 15410249Sstephan.diestelhorst@arm.com DPRINTF(DVFS, "DVFS: Update for perf event scheduled for %ld\n", when); 15510249Sstephan.diestelhorst@arm.com 15610249Sstephan.diestelhorst@arm.com schedule(update_event, when); 15710249Sstephan.diestelhorst@arm.com return true; 15810249Sstephan.diestelhorst@arm.com} 15910249Sstephan.diestelhorst@arm.com 16010249Sstephan.diestelhorst@arm.comvoid 16110249Sstephan.diestelhorst@arm.comDVFSHandler::UpdateEvent::updatePerfLevel() 16210249Sstephan.diestelhorst@arm.com{ 16310249Sstephan.diestelhorst@arm.com // Perform explicit stats dump for power estimation before performance 16410249Sstephan.diestelhorst@arm.com // level migration 16510249Sstephan.diestelhorst@arm.com Stats::dump(); 16610249Sstephan.diestelhorst@arm.com Stats::reset(); 16710249Sstephan.diestelhorst@arm.com 16810249Sstephan.diestelhorst@arm.com // Update the performance level in the clock domain 16910249Sstephan.diestelhorst@arm.com auto d = dvfsHandler->findDomain(domainIDToSet); 17010249Sstephan.diestelhorst@arm.com assert(d->perfLevel() != perfLevelToSet); 17110249Sstephan.diestelhorst@arm.com 17210249Sstephan.diestelhorst@arm.com d->perfLevel(perfLevelToSet); 17310249Sstephan.diestelhorst@arm.com} 17410249Sstephan.diestelhorst@arm.com 17511800Sbrandon.potter@amd.comdouble 17611800Sbrandon.potter@amd.comDVFSHandler::voltageAtPerfLevel(DomainID domain_id, PerfLevel perf_level) const 17711800Sbrandon.potter@amd.com{ 17811800Sbrandon.potter@amd.com VoltageDomain *d = findDomain(domain_id)->voltageDomain(); 17911800Sbrandon.potter@amd.com assert(d); 18011800Sbrandon.potter@amd.com PerfLevel n = d->numVoltages(); 18111800Sbrandon.potter@amd.com if (perf_level < n) 18211800Sbrandon.potter@amd.com return d->voltage(perf_level); 18311800Sbrandon.potter@amd.com 18411800Sbrandon.potter@amd.com // Request outside of the range of the voltage domain 18511800Sbrandon.potter@amd.com if (n == 1) { 18611800Sbrandon.potter@amd.com DPRINTF(DVFS, "DVFS: Request for perf-level %i for single-point "\ 18711800Sbrandon.potter@amd.com "voltage domain %s. Returning voltage at level 0: %.2f "\ 18811800Sbrandon.potter@amd.com "V\n", perf_level, d->name(), d->voltage(0)); 18911800Sbrandon.potter@amd.com // Special case for single point voltage domain -> same voltage for 19011800Sbrandon.potter@amd.com // all points 19111800Sbrandon.potter@amd.com return d->voltage(0); 19211800Sbrandon.potter@amd.com } 19311800Sbrandon.potter@amd.com 19411800Sbrandon.potter@amd.com warn("DVFSHandler %s reads illegal voltage level %u from "\ 19511800Sbrandon.potter@amd.com "VoltageDomain %s. Returning 0 V\n", name(), perf_level, d->name()); 19611800Sbrandon.potter@amd.com return 0.; 19711800Sbrandon.potter@amd.com} 19811800Sbrandon.potter@amd.com 19910249Sstephan.diestelhorst@arm.comvoid 20010905Sandreas.sandberg@arm.comDVFSHandler::serialize(CheckpointOut &cp) const 20110249Sstephan.diestelhorst@arm.com{ 20210249Sstephan.diestelhorst@arm.com //This is to ensure that the handler status is maintained during the 20310249Sstephan.diestelhorst@arm.com //entire simulation run and not changed from command line during checkpoint 20410249Sstephan.diestelhorst@arm.com //and restore 20510249Sstephan.diestelhorst@arm.com SERIALIZE_SCALAR(enableHandler); 20610249Sstephan.diestelhorst@arm.com 20710249Sstephan.diestelhorst@arm.com // Pull out the hashed data structure into easy-to-serialise arrays; 20810249Sstephan.diestelhorst@arm.com // ensuring that the data associated with any pending update event is saved 20910249Sstephan.diestelhorst@arm.com std::vector<DomainID> domain_ids; 21010249Sstephan.diestelhorst@arm.com std::vector<PerfLevel> perf_levels; 21110249Sstephan.diestelhorst@arm.com std::vector<Tick> whens; 21210905Sandreas.sandberg@arm.com for (const auto &ev_pair : updatePerfLevelEvents) { 21310905Sandreas.sandberg@arm.com DomainID id = ev_pair.first; 21410905Sandreas.sandberg@arm.com const UpdateEvent *event = &ev_pair.second; 21510249Sstephan.diestelhorst@arm.com 21610249Sstephan.diestelhorst@arm.com assert(id == event->domainIDToSet); 21710249Sstephan.diestelhorst@arm.com domain_ids.push_back(id); 21810249Sstephan.diestelhorst@arm.com perf_levels.push_back(event->perfLevelToSet); 21910249Sstephan.diestelhorst@arm.com whens.push_back(event->scheduled() ? event->when() : 0); 22010249Sstephan.diestelhorst@arm.com } 22110905Sandreas.sandberg@arm.com SERIALIZE_CONTAINER(domain_ids); 22210905Sandreas.sandberg@arm.com SERIALIZE_CONTAINER(perf_levels); 22310905Sandreas.sandberg@arm.com SERIALIZE_CONTAINER(whens); 22410249Sstephan.diestelhorst@arm.com} 22510249Sstephan.diestelhorst@arm.com 22610249Sstephan.diestelhorst@arm.comvoid 22710905Sandreas.sandberg@arm.comDVFSHandler::unserialize(CheckpointIn &cp) 22810249Sstephan.diestelhorst@arm.com{ 22910395Sstephan.diestelhorst@arm.com bool temp = enableHandler; 23010395Sstephan.diestelhorst@arm.com 23110249Sstephan.diestelhorst@arm.com UNSERIALIZE_SCALAR(enableHandler); 23210249Sstephan.diestelhorst@arm.com 23311321Ssteve.reinhardt@amd.com if (temp != enableHandler) { 23410395Sstephan.diestelhorst@arm.com warn("DVFS: Forcing enable handler status to unserialized value of %d", 23510395Sstephan.diestelhorst@arm.com enableHandler); 23610395Sstephan.diestelhorst@arm.com } 23710395Sstephan.diestelhorst@arm.com 23810249Sstephan.diestelhorst@arm.com // Reconstruct the map of domain IDs and their scheduled events 23910249Sstephan.diestelhorst@arm.com std::vector<DomainID> domain_ids; 24010249Sstephan.diestelhorst@arm.com std::vector<PerfLevel> perf_levels; 24110249Sstephan.diestelhorst@arm.com std::vector<Tick> whens; 24210905Sandreas.sandberg@arm.com UNSERIALIZE_CONTAINER(domain_ids); 24310905Sandreas.sandberg@arm.com UNSERIALIZE_CONTAINER(perf_levels); 24410905Sandreas.sandberg@arm.com UNSERIALIZE_CONTAINER(whens); 24510249Sstephan.diestelhorst@arm.com 24610249Sstephan.diestelhorst@arm.com for (size_t i = 0; i < domain_ids.size(); ++i) {; 24710249Sstephan.diestelhorst@arm.com UpdateEvent *event = &updatePerfLevelEvents[domain_ids[i]]; 24810249Sstephan.diestelhorst@arm.com 24910249Sstephan.diestelhorst@arm.com event->domainIDToSet = domain_ids[i]; 25010249Sstephan.diestelhorst@arm.com event->perfLevelToSet = perf_levels[i]; 25110249Sstephan.diestelhorst@arm.com 25210249Sstephan.diestelhorst@arm.com // Schedule all previously scheduled events 25310249Sstephan.diestelhorst@arm.com if (whens[i]) 25410249Sstephan.diestelhorst@arm.com schedule(event, whens[i]); 25510249Sstephan.diestelhorst@arm.com } 25610249Sstephan.diestelhorst@arm.com UpdateEvent::dvfsHandler = this; 25710249Sstephan.diestelhorst@arm.com} 25810249Sstephan.diestelhorst@arm.com 25910249Sstephan.diestelhorst@arm.comDVFSHandler* 26010249Sstephan.diestelhorst@arm.comDVFSHandlerParams::create() 26110249Sstephan.diestelhorst@arm.com{ 26210249Sstephan.diestelhorst@arm.com return new DVFSHandler(this); 26310249Sstephan.diestelhorst@arm.com} 264