diff options
Diffstat (limited to 'src/sim/dvfs_handler.cc')
-rw-r--r-- | src/sim/dvfs_handler.cc | 216 |
1 files changed, 216 insertions, 0 deletions
diff --git a/src/sim/dvfs_handler.cc b/src/sim/dvfs_handler.cc new file mode 100644 index 000000000..bb60b1850 --- /dev/null +++ b/src/sim/dvfs_handler.cc @@ -0,0 +1,216 @@ +/* + * Copyright (c) 2013-2014 ARM Limited + * All rights reserved + * + * The license below extends only to copyright in the software and shall + * not be construed as granting a license to any other intellectual + * property including but not limited to intellectual property relating + * to a hardware implementation of the functionality of the software + * licensed hereunder. You may use the software subject to the license + * terms below provided that you ensure that this notice is replicated + * unmodified and in its entirety in all distributions of the software, + * modified or unmodified, in source code or in binary form. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer; + * redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution; + * neither the name of the copyright holders nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * Authors: Vasileios Spiliopoulos + * Akash Bagdia + * Stephan Diestelhorst + */ + +#include <set> +#include <utility> + +#include "base/misc.hh" +#include "debug/DVFS.hh" +#include "params/DVFSHandler.hh" +#include "sim/clock_domain.hh" +#include "sim/dvfs_handler.hh" +#include "sim/stat_control.hh" +#include "sim/voltage_domain.hh" + +// +// +// DVFSHandler methods implementation +// + +DVFSHandler::DVFSHandler(const Params *p) + : SimObject(p), + sysClkDomain(p->sys_clk_domain), + enableHandler(p->enable), + _transLatency(p->transition_latency) +{ + // Check supplied list of domains for sanity and add them to the + // domain ID -> domain* hash + for(auto dit = p->domains.begin(); dit != p->domains.end(); ++dit) { + SrcClockDomain *d = *dit; + DomainID domain_id = d->domainID(); + + fatal_if(sysClkDomain == d, "DVFS: Domain config list has a "\ + "system clk domain entry"); + fatal_if(domain_id == SrcClockDomain::emptyDomainID, + "DVFS: Controlled domain %s needs to have a properly "\ + " assigned ID.\n", d->name()); + + auto entry = std::make_pair(domain_id, d); + bool new_elem = domains.insert(entry).second; + fatal_if(!new_elem, "DVFS: Domain %s with ID %d does not have a "\ + "unique ID.\n", d->name(), domain_id); + + // Create a dedicated event slot per known domain ID + UpdateEvent *event = &updatePerfLevelEvents[domain_id]; + event->domainIDToSet = d->domainID(); + } + UpdateEvent::dvfsHandler = this; +} + +DVFSHandler *DVFSHandler::UpdateEvent::dvfsHandler; + +bool +DVFSHandler::validDomainID(DomainID domain_id) const +{ + assert(isEnabled()); + // This is ensure that the domain id as requested by the software is + // availabe in the handler. + if (domains.find(domain_id) != domains.end()) + return true; + warn("DVFS: invalid domain ID %d, the DVFS handler does not handle this "\ + "domain\n", domain_id); + return false; +} + +bool +DVFSHandler::perfLevel(DomainID domain_id, PerfLevel perf_level) +{ + assert(isEnabled()); + + DPRINTF(DVFS, "DVFS: setPerfLevel domain %d -> %d\n", domain_id, perf_level); + + auto d = findDomain(domain_id); + if (!d->validPerfLevel(perf_level)) { + warn("DVFS: invalid performance level %d for domain ID %d, request "\ + "ignored\n", perf_level, domain_id); + return false; + } + + UpdateEvent *update_event = &updatePerfLevelEvents[domain_id]; + // Drop an old DVFS change request once we have established that this is a + // reasonable request + if (update_event->scheduled()) { + DPRINTF(DVFS, "DVFS: Overwriting the previous DVFS event.\n"); + deschedule(update_event); + } + + update_event->perfLevelToSet = perf_level; + + // State changes that restore to the current state (and / or overwrite a not + // yet completed in-flight request) will be squashed + if (d->perfLevel() == perf_level) { + DPRINTF(DVFS, "DVFS: Ignoring ineffective performance level change "\ + "%d -> %d\n", d->perfLevel(), perf_level); + return false; + } + + // At this point, a new transition will certainly take place -> schedule + Tick when = curTick() + _transLatency; + DPRINTF(DVFS, "DVFS: Update for perf event scheduled for %ld\n", when); + + schedule(update_event, when); + return true; +} + +void +DVFSHandler::UpdateEvent::updatePerfLevel() +{ + // Perform explicit stats dump for power estimation before performance + // level migration + Stats::dump(); + Stats::reset(); + + // Update the performance level in the clock domain + auto d = dvfsHandler->findDomain(domainIDToSet); + assert(d->perfLevel() != perfLevelToSet); + + d->perfLevel(perfLevelToSet); +} + +void +DVFSHandler::serialize(std::ostream &os) +{ + //This is to ensure that the handler status is maintained during the + //entire simulation run and not changed from command line during checkpoint + //and restore + SERIALIZE_SCALAR(enableHandler); + + // Pull out the hashed data structure into easy-to-serialise arrays; + // ensuring that the data associated with any pending update event is saved + std::vector<DomainID> domain_ids; + std::vector<PerfLevel> perf_levels; + std::vector<Tick> whens; + for (auto it = updatePerfLevelEvents.begin(); + it != updatePerfLevelEvents.end(); ++it) { + DomainID id = it->first; + UpdateEvent *event = &it->second; + + assert(id == event->domainIDToSet); + domain_ids.push_back(id); + perf_levels.push_back(event->perfLevelToSet); + whens.push_back(event->scheduled() ? event->when() : 0); + } + arrayParamOut(os, "domain_ids", domain_ids); + arrayParamOut(os, "perf_levels", perf_levels); + arrayParamOut(os, "whens", whens); +} + +void +DVFSHandler::unserialize(Checkpoint *cp, const std::string §ion) +{ + UNSERIALIZE_SCALAR(enableHandler); + + // Reconstruct the map of domain IDs and their scheduled events + std::vector<DomainID> domain_ids; + std::vector<PerfLevel> perf_levels; + std::vector<Tick> whens; + arrayParamIn(cp, section, "domain_ids", domain_ids); + arrayParamIn(cp, section, "perf_levels", perf_levels); + arrayParamIn(cp, section, "whens", whens); + + for (size_t i = 0; i < domain_ids.size(); ++i) {; + UpdateEvent *event = &updatePerfLevelEvents[domain_ids[i]]; + + event->domainIDToSet = domain_ids[i]; + event->perfLevelToSet = perf_levels[i]; + + // Schedule all previously scheduled events + if (whens[i]) + schedule(event, whens[i]); + } + UpdateEvent::dvfsHandler = this; +} + +DVFSHandler* +DVFSHandlerParams::create() +{ + return new DVFSHandler(this); +} |