dvfs_handler.cc revision 11793:ef606668d247
1/*
2 * Copyright (c) 2013-2014 ARM Limited
3 * All rights reserved
4 *
5 * The license below extends only to copyright in the software and shall
6 * not be construed as granting a license to any other intellectual
7 * property including but not limited to intellectual property relating
8 * to a hardware implementation of the functionality of the software
9 * licensed hereunder.  You may use the software subject to the license
10 * terms below provided that you ensure that this notice is replicated
11 * unmodified and in its entirety in all distributions of the software,
12 * modified or unmodified, in source code or in binary form.
13 *
14 * Redistribution and use in source and binary forms, with or without
15 * modification, are permitted provided that the following conditions are
16 * met: redistributions of source code must retain the above copyright
17 * notice, this list of conditions and the following disclaimer;
18 * redistributions in binary form must reproduce the above copyright
19 * notice, this list of conditions and the following disclaimer in the
20 * documentation and/or other materials provided with the distribution;
21 * neither the name of the copyright holders nor the names of its
22 * contributors may be used to endorse or promote products derived from
23 * this software without specific prior written permission.
24 *
25 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
26 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
27 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
28 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
29 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
30 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
31 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
32 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
33 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
34 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
35 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
36 *
37 * Authors: Vasileios Spiliopoulos
38 *          Akash Bagdia
39 *          Stephan Diestelhorst
40 */
41
42#include "sim/dvfs_handler.hh"
43
44#include <set>
45#include <utility>
46
47#include "base/misc.hh"
48#include "debug/DVFS.hh"
49#include "params/DVFSHandler.hh"
50#include "sim/clock_domain.hh"
51#include "sim/stat_control.hh"
52#include "sim/voltage_domain.hh"
53
54//
55//
56// DVFSHandler methods implementation
57//
58
59DVFSHandler::DVFSHandler(const Params *p)
60    : SimObject(p),
61      sysClkDomain(p->sys_clk_domain),
62      enableHandler(p->enable),
63      _transLatency(p->transition_latency)
64{
65    // Check supplied list of domains for sanity and add them to the
66    // domain ID -> domain* hash
67    for (auto dit = p->domains.begin(); dit != p->domains.end(); ++dit) {
68        SrcClockDomain *d = *dit;
69        DomainID domain_id = d->domainID();
70
71        fatal_if(sysClkDomain == d, "DVFS: Domain config list has a "\
72                 "system clk domain entry");
73        fatal_if(domain_id == SrcClockDomain::emptyDomainID,
74                 "DVFS: Controlled domain %s needs to have a properly "\
75                 " assigned ID.\n", d->name());
76
77        auto entry = std::make_pair(domain_id, d);
78        bool new_elem = domains.insert(entry).second;
79        fatal_if(!new_elem, "DVFS: Domain %s with ID %d does not have a "\
80                 "unique ID.\n", d->name(), domain_id);
81
82        // Create a dedicated event slot per known domain ID
83        UpdateEvent *event = &updatePerfLevelEvents[domain_id];
84        event->domainIDToSet = d->domainID();
85
86        // Add domain ID to the list of domains
87        domainIDList.push_back(d->domainID());
88    }
89    UpdateEvent::dvfsHandler = this;
90}
91
92DVFSHandler *DVFSHandler::UpdateEvent::dvfsHandler;
93
94DVFSHandler::DomainID
95DVFSHandler::domainID(uint32_t index) const
96{
97    fatal_if(index >= numDomains(), "DVFS: Requested index out of "\
98             "bound, max value %d\n", (domainIDList.size() - 1));
99
100    assert(domains.find(domainIDList[index]) != domains.end());
101
102    return domainIDList[index];
103}
104
105bool
106DVFSHandler::validDomainID(DomainID domain_id) const
107{
108    assert(isEnabled());
109    // This is ensure that the domain id as requested by the software is
110    // availabe in the handler.
111    if (domains.find(domain_id) != domains.end())
112        return true;
113    warn("DVFS: invalid domain ID %d, the DVFS handler does not handle this "\
114         "domain\n", domain_id);
115    return false;
116}
117
118bool
119DVFSHandler::perfLevel(DomainID domain_id, PerfLevel perf_level)
120{
121    assert(isEnabled());
122
123    DPRINTF(DVFS, "DVFS: setPerfLevel domain %d -> %d\n", domain_id, perf_level);
124
125    auto d = findDomain(domain_id);
126    if (!d->validPerfLevel(perf_level)) {
127        warn("DVFS: invalid performance level %d for domain ID %d, request "\
128             "ignored\n", perf_level, domain_id);
129        return false;
130    }
131
132    UpdateEvent *update_event = &updatePerfLevelEvents[domain_id];
133    // Drop an old DVFS change request once we have established that this is a
134    // reasonable request
135    if (update_event->scheduled()) {
136        DPRINTF(DVFS, "DVFS: Overwriting the previous DVFS event.\n");
137        deschedule(update_event);
138    }
139
140    update_event->perfLevelToSet = perf_level;
141
142    // State changes that restore to the current state (and / or overwrite a not
143    // yet completed in-flight request) will be squashed
144    if (d->perfLevel() == perf_level) {
145        DPRINTF(DVFS, "DVFS: Ignoring ineffective performance level change "\
146                "%d -> %d\n", d->perfLevel(), perf_level);
147        return false;
148    }
149
150    // At this point, a new transition will certainly take place -> schedule
151    Tick when = curTick() + _transLatency;
152    DPRINTF(DVFS, "DVFS: Update for perf event scheduled for %ld\n", when);
153
154    schedule(update_event, when);
155    return true;
156}
157
158void
159DVFSHandler::UpdateEvent::updatePerfLevel()
160{
161    // Perform explicit stats dump for power estimation before performance
162    // level migration
163    Stats::dump();
164    Stats::reset();
165
166    // Update the performance level in the clock domain
167    auto d = dvfsHandler->findDomain(domainIDToSet);
168    assert(d->perfLevel() != perfLevelToSet);
169
170    d->perfLevel(perfLevelToSet);
171}
172
173void
174DVFSHandler::serialize(CheckpointOut &cp) const
175{
176    //This is to ensure that the handler status is maintained during the
177    //entire simulation run and not changed from command line during checkpoint
178    //and restore
179    SERIALIZE_SCALAR(enableHandler);
180
181    // Pull out the hashed data structure into easy-to-serialise arrays;
182    // ensuring that the data associated with any pending update event is saved
183    std::vector<DomainID> domain_ids;
184    std::vector<PerfLevel> perf_levels;
185    std::vector<Tick> whens;
186    for (const auto &ev_pair : updatePerfLevelEvents) {
187        DomainID id = ev_pair.first;
188        const UpdateEvent *event = &ev_pair.second;
189
190        assert(id == event->domainIDToSet);
191        domain_ids.push_back(id);
192        perf_levels.push_back(event->perfLevelToSet);
193        whens.push_back(event->scheduled() ? event->when() : 0);
194    }
195    SERIALIZE_CONTAINER(domain_ids);
196    SERIALIZE_CONTAINER(perf_levels);
197    SERIALIZE_CONTAINER(whens);
198}
199
200void
201DVFSHandler::unserialize(CheckpointIn &cp)
202{
203    bool temp = enableHandler;
204
205    UNSERIALIZE_SCALAR(enableHandler);
206
207    if (temp != enableHandler) {
208        warn("DVFS: Forcing enable handler status to unserialized value of %d",
209             enableHandler);
210    }
211
212    // Reconstruct the map of domain IDs and their scheduled events
213    std::vector<DomainID> domain_ids;
214    std::vector<PerfLevel> perf_levels;
215    std::vector<Tick> whens;
216    UNSERIALIZE_CONTAINER(domain_ids);
217    UNSERIALIZE_CONTAINER(perf_levels);
218    UNSERIALIZE_CONTAINER(whens);
219
220    for (size_t i = 0; i < domain_ids.size(); ++i) {;
221        UpdateEvent *event = &updatePerfLevelEvents[domain_ids[i]];
222
223        event->domainIDToSet = domain_ids[i];
224        event->perfLevelToSet = perf_levels[i];
225
226        // Schedule all previously scheduled events
227        if (whens[i])
228            schedule(event, whens[i]);
229    }
230    UpdateEvent::dvfsHandler = this;
231}
232
233DVFSHandler*
234DVFSHandlerParams::create()
235{
236    return new DVFSHandler(this);
237}
238