dvfs_handler.cc revision 11321
16145Snate@binkert.org/* 26145Snate@binkert.org * Copyright (c) 2013-2014 ARM Limited 36145Snate@binkert.org * All rights reserved 46145Snate@binkert.org * 56145Snate@binkert.org * The license below extends only to copyright in the software and shall 66145Snate@binkert.org * not be construed as granting a license to any other intellectual 76145Snate@binkert.org * property including but not limited to intellectual property relating 86145Snate@binkert.org * to a hardware implementation of the functionality of the software 96145Snate@binkert.org * licensed hereunder. You may use the software subject to the license 106145Snate@binkert.org * terms below provided that you ensure that this notice is replicated 116145Snate@binkert.org * unmodified and in its entirety in all distributions of the software, 126145Snate@binkert.org * modified or unmodified, in source code or in binary form. 136145Snate@binkert.org * 146145Snate@binkert.org * Redistribution and use in source and binary forms, with or without 156145Snate@binkert.org * modification, are permitted provided that the following conditions are 166145Snate@binkert.org * met: redistributions of source code must retain the above copyright 176145Snate@binkert.org * notice, this list of conditions and the following disclaimer; 186145Snate@binkert.org * redistributions in binary form must reproduce the above copyright 196145Snate@binkert.org * notice, this list of conditions and the following disclaimer in the 206145Snate@binkert.org * documentation and/or other materials provided with the distribution; 216145Snate@binkert.org * neither the name of the copyright holders nor the names of its 226145Snate@binkert.org * contributors may be used to endorse or promote products derived from 236145Snate@binkert.org * this software without specific prior written permission. 246145Snate@binkert.org * 256145Snate@binkert.org * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 266145Snate@binkert.org * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 276145Snate@binkert.org * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 286145Snate@binkert.org * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 297054Snate@binkert.org * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 307054Snate@binkert.org * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 316145Snate@binkert.org * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 327055Snate@binkert.org * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 337454Snate@binkert.org * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 347055Snate@binkert.org * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 356154Snate@binkert.org * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 367054Snate@binkert.org * 376145Snate@binkert.org * Authors: Vasileios Spiliopoulos 386145Snate@binkert.org * Akash Bagdia 396145Snate@binkert.org * Stephan Diestelhorst 406145Snate@binkert.org */ 416145Snate@binkert.org 426145Snate@binkert.org#include <set> 437054Snate@binkert.org#include <utility> 447054Snate@binkert.org 457054Snate@binkert.org#include "base/misc.hh" 466876Ssteve.reinhardt@amd.com#include "debug/DVFS.hh" 476876Ssteve.reinhardt@amd.com#include "params/DVFSHandler.hh" 487054Snate@binkert.org#include "sim/clock_domain.hh" 496145Snate@binkert.org#include "sim/dvfs_handler.hh" 507054Snate@binkert.org#include "sim/stat_control.hh" 516145Snate@binkert.org#include "sim/voltage_domain.hh" 528259SBrad.Beckmann@amd.com 538259SBrad.Beckmann@amd.com// 548259SBrad.Beckmann@amd.com// 558259SBrad.Beckmann@amd.com// DVFSHandler methods implementation 569863Snilay@cs.wisc.edu// 579863Snilay@cs.wisc.edu 586145Snate@binkert.orgDVFSHandler::DVFSHandler(const Params *p) 5910311Snilay@cs.wisc.edu : SimObject(p), 6010311Snilay@cs.wisc.edu sysClkDomain(p->sys_clk_domain), 6110311Snilay@cs.wisc.edu enableHandler(p->enable), 6210311Snilay@cs.wisc.edu _transLatency(p->transition_latency) 6310311Snilay@cs.wisc.edu{ 646145Snate@binkert.org // Check supplied list of domains for sanity and add them to the 657054Snate@binkert.org // domain ID -> domain* hash 667054Snate@binkert.org for (auto dit = p->domains.begin(); dit != p->domains.end(); ++dit) { 676145Snate@binkert.org SrcClockDomain *d = *dit; 687054Snate@binkert.org DomainID domain_id = d->domainID(); 698257SBrad.Beckmann@amd.com 708257SBrad.Beckmann@amd.com fatal_if(sysClkDomain == d, "DVFS: Domain config list has a "\ 719799Snilay@cs.wisc.edu "system clk domain entry"); 729799Snilay@cs.wisc.edu fatal_if(domain_id == SrcClockDomain::emptyDomainID, 738257SBrad.Beckmann@amd.com "DVFS: Controlled domain %s needs to have a properly "\ 749799Snilay@cs.wisc.edu " assigned ID.\n", d->name()); 758257SBrad.Beckmann@amd.com 768257SBrad.Beckmann@amd.com auto entry = std::make_pair(domain_id, d); 779799Snilay@cs.wisc.edu bool new_elem = domains.insert(entry).second; 786145Snate@binkert.org fatal_if(!new_elem, "DVFS: Domain %s with ID %d does not have a "\ 797055Snate@binkert.org "unique ID.\n", d->name(), domain_id); 806145Snate@binkert.org 819302Snilay@cs.wisc.edu // Create a dedicated event slot per known domain ID 829302Snilay@cs.wisc.edu UpdateEvent *event = &updatePerfLevelEvents[domain_id]; 839302Snilay@cs.wisc.edu event->domainIDToSet = d->domainID(); 847054Snate@binkert.org 857054Snate@binkert.org // Add domain ID to the list of domains 867054Snate@binkert.org domainIDList.push_back(d->domainID()); 877054Snate@binkert.org } 887054Snate@binkert.org UpdateEvent::dvfsHandler = this; 897054Snate@binkert.org} 906145Snate@binkert.org 917054Snate@binkert.orgDVFSHandler *DVFSHandler::UpdateEvent::dvfsHandler; 927054Snate@binkert.org 937054Snate@binkert.orgDVFSHandler::DomainID 9410311Snilay@cs.wisc.eduDVFSHandler::domainID(uint32_t index) const 959858Snilay@cs.wisc.edu{ 967454Snate@binkert.org fatal_if(index >= numDomains(), "DVFS: Requested index out of "\ 977454Snate@binkert.org "bound, max value %d\n", (domainIDList.size() - 1)); 988259SBrad.Beckmann@amd.com 998259SBrad.Beckmann@amd.com assert(domains.find(domainIDList[index]) != domains.end()); 1008259SBrad.Beckmann@amd.com 1018259SBrad.Beckmann@amd.com return domainIDList[index]; 1029863Snilay@cs.wisc.edu} 1039863Snilay@cs.wisc.edu 1049866Sjthestness@gmail.combool 1059866Sjthestness@gmail.comDVFSHandler::validDomainID(DomainID domain_id) const 1066145Snate@binkert.org{ 1076145Snate@binkert.org assert(isEnabled()); 1087055Snate@binkert.org // This is ensure that the domain id as requested by the software is 1097055Snate@binkert.org // availabe in the handler. 1106145Snate@binkert.org if (domains.find(domain_id) != domains.end()) 1117054Snate@binkert.org return true; 1127055Snate@binkert.org warn("DVFS: invalid domain ID %d, the DVFS handler does not handle this "\ 1137054Snate@binkert.org "domain\n", domain_id); 1146145Snate@binkert.org return false; 1156145Snate@binkert.org} 1167054Snate@binkert.org 117bool 118DVFSHandler::perfLevel(DomainID domain_id, PerfLevel perf_level) 119{ 120 assert(isEnabled()); 121 122 DPRINTF(DVFS, "DVFS: setPerfLevel domain %d -> %d\n", domain_id, perf_level); 123 124 auto d = findDomain(domain_id); 125 if (!d->validPerfLevel(perf_level)) { 126 warn("DVFS: invalid performance level %d for domain ID %d, request "\ 127 "ignored\n", perf_level, domain_id); 128 return false; 129 } 130 131 UpdateEvent *update_event = &updatePerfLevelEvents[domain_id]; 132 // Drop an old DVFS change request once we have established that this is a 133 // reasonable request 134 if (update_event->scheduled()) { 135 DPRINTF(DVFS, "DVFS: Overwriting the previous DVFS event.\n"); 136 deschedule(update_event); 137 } 138 139 update_event->perfLevelToSet = perf_level; 140 141 // State changes that restore to the current state (and / or overwrite a not 142 // yet completed in-flight request) will be squashed 143 if (d->perfLevel() == perf_level) { 144 DPRINTF(DVFS, "DVFS: Ignoring ineffective performance level change "\ 145 "%d -> %d\n", d->perfLevel(), perf_level); 146 return false; 147 } 148 149 // At this point, a new transition will certainly take place -> schedule 150 Tick when = curTick() + _transLatency; 151 DPRINTF(DVFS, "DVFS: Update for perf event scheduled for %ld\n", when); 152 153 schedule(update_event, when); 154 return true; 155} 156 157void 158DVFSHandler::UpdateEvent::updatePerfLevel() 159{ 160 // Perform explicit stats dump for power estimation before performance 161 // level migration 162 Stats::dump(); 163 Stats::reset(); 164 165 // Update the performance level in the clock domain 166 auto d = dvfsHandler->findDomain(domainIDToSet); 167 assert(d->perfLevel() != perfLevelToSet); 168 169 d->perfLevel(perfLevelToSet); 170} 171 172void 173DVFSHandler::serialize(CheckpointOut &cp) const 174{ 175 //This is to ensure that the handler status is maintained during the 176 //entire simulation run and not changed from command line during checkpoint 177 //and restore 178 SERIALIZE_SCALAR(enableHandler); 179 180 // Pull out the hashed data structure into easy-to-serialise arrays; 181 // ensuring that the data associated with any pending update event is saved 182 std::vector<DomainID> domain_ids; 183 std::vector<PerfLevel> perf_levels; 184 std::vector<Tick> whens; 185 for (const auto &ev_pair : updatePerfLevelEvents) { 186 DomainID id = ev_pair.first; 187 const UpdateEvent *event = &ev_pair.second; 188 189 assert(id == event->domainIDToSet); 190 domain_ids.push_back(id); 191 perf_levels.push_back(event->perfLevelToSet); 192 whens.push_back(event->scheduled() ? event->when() : 0); 193 } 194 SERIALIZE_CONTAINER(domain_ids); 195 SERIALIZE_CONTAINER(perf_levels); 196 SERIALIZE_CONTAINER(whens); 197} 198 199void 200DVFSHandler::unserialize(CheckpointIn &cp) 201{ 202 bool temp = enableHandler; 203 204 UNSERIALIZE_SCALAR(enableHandler); 205 206 if (temp != enableHandler) { 207 warn("DVFS: Forcing enable handler status to unserialized value of %d", 208 enableHandler); 209 } 210 211 // Reconstruct the map of domain IDs and their scheduled events 212 std::vector<DomainID> domain_ids; 213 std::vector<PerfLevel> perf_levels; 214 std::vector<Tick> whens; 215 UNSERIALIZE_CONTAINER(domain_ids); 216 UNSERIALIZE_CONTAINER(perf_levels); 217 UNSERIALIZE_CONTAINER(whens); 218 219 for (size_t i = 0; i < domain_ids.size(); ++i) {; 220 UpdateEvent *event = &updatePerfLevelEvents[domain_ids[i]]; 221 222 event->domainIDToSet = domain_ids[i]; 223 event->perfLevelToSet = perf_levels[i]; 224 225 // Schedule all previously scheduled events 226 if (whens[i]) 227 schedule(event, whens[i]); 228 } 229 UpdateEvent::dvfsHandler = this; 230} 231 232DVFSHandler* 233DVFSHandlerParams::create() 234{ 235 return new DVFSHandler(this); 236} 237