summaryrefslogtreecommitdiff
path: root/src/sim/dvfs_handler.cc
diff options
context:
space:
mode:
Diffstat (limited to 'src/sim/dvfs_handler.cc')
-rw-r--r--src/sim/dvfs_handler.cc216
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 &section)
+{
+ 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);
+}