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