2 * Copyright (c) 2013-2014 ARM Limited
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.
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.
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.
37 * Authors: Vasileios Spiliopoulos
39 * Stephan Diestelhorst
42 #include "sim/dvfs_handler.hh"
47 #include "base/logging.hh"
48 #include "base/trace.hh"
49 #include "debug/DVFS.hh"
50 #include "params/DVFSHandler.hh"
51 #include "sim/clock_domain.hh"
52 #include "sim/eventq_impl.hh"
53 #include "sim/stat_control.hh"
54 #include "sim/voltage_domain.hh"
58 // DVFSHandler methods implementation
61 DVFSHandler::DVFSHandler(const Params
*p
)
63 sysClkDomain(p
->sys_clk_domain
),
64 enableHandler(p
->enable
),
65 _transLatency(p
->transition_latency
)
67 // Check supplied list of domains for sanity and add them to the
68 // domain ID -> domain* hash
69 for (auto dit
= p
->domains
.begin(); dit
!= p
->domains
.end(); ++dit
) {
70 SrcClockDomain
*d
= *dit
;
71 DomainID domain_id
= d
->domainID();
73 fatal_if(sysClkDomain
== d
, "DVFS: Domain config list has a "\
74 "system clk domain entry");
75 fatal_if(domain_id
== SrcClockDomain::emptyDomainID
,
76 "DVFS: Controlled domain %s needs to have a properly "\
77 " assigned ID.\n", d
->name());
79 auto entry
= std::make_pair(domain_id
, d
);
80 bool new_elem
= domains
.insert(entry
).second
;
81 fatal_if(!new_elem
, "DVFS: Domain %s with ID %d does not have a "\
82 "unique ID.\n", d
->name(), domain_id
);
84 // Create a dedicated event slot per known domain ID
85 UpdateEvent
*event
= &updatePerfLevelEvents
[domain_id
];
86 event
->domainIDToSet
= d
->domainID();
88 // Add domain ID to the list of domains
89 domainIDList
.push_back(d
->domainID());
91 UpdateEvent::dvfsHandler
= this;
94 DVFSHandler
*DVFSHandler::UpdateEvent::dvfsHandler
;
97 DVFSHandler::domainID(uint32_t index
) const
99 fatal_if(index
>= numDomains(), "DVFS: Requested index out of "\
100 "bound, max value %d\n", (domainIDList
.size() - 1));
102 assert(domains
.find(domainIDList
[index
]) != domains
.end());
104 return domainIDList
[index
];
108 DVFSHandler::validDomainID(DomainID domain_id
) const
111 // This is ensure that the domain id as requested by the software is
112 // availabe in the handler.
113 if (domains
.find(domain_id
) != domains
.end())
115 warn("DVFS: invalid domain ID %d, the DVFS handler does not handle this "\
116 "domain\n", domain_id
);
121 DVFSHandler::perfLevel(DomainID domain_id
, PerfLevel perf_level
)
125 DPRINTF(DVFS
, "DVFS: setPerfLevel domain %d -> %d\n", domain_id
, perf_level
);
127 auto d
= findDomain(domain_id
);
128 if (!d
->validPerfLevel(perf_level
)) {
129 warn("DVFS: invalid performance level %d for domain ID %d, request "\
130 "ignored\n", perf_level
, domain_id
);
134 UpdateEvent
*update_event
= &updatePerfLevelEvents
[domain_id
];
135 // Drop an old DVFS change request once we have established that this is a
136 // reasonable request
137 if (update_event
->scheduled()) {
138 DPRINTF(DVFS
, "DVFS: Overwriting the previous DVFS event.\n");
139 deschedule(update_event
);
142 update_event
->perfLevelToSet
= perf_level
;
144 // State changes that restore to the current state (and / or overwrite a not
145 // yet completed in-flight request) will be squashed
146 if (d
->perfLevel() == perf_level
) {
147 DPRINTF(DVFS
, "DVFS: Ignoring ineffective performance level change "\
148 "%d -> %d\n", d
->perfLevel(), perf_level
);
152 // At this point, a new transition will certainly take place -> schedule
153 Tick when
= curTick() + _transLatency
;
154 DPRINTF(DVFS
, "DVFS: Update for perf event scheduled for %ld\n", when
);
156 schedule(update_event
, when
);
161 DVFSHandler::UpdateEvent::updatePerfLevel()
163 // Perform explicit stats dump for power estimation before performance
168 // Update the performance level in the clock domain
169 auto d
= dvfsHandler
->findDomain(domainIDToSet
);
170 assert(d
->perfLevel() != perfLevelToSet
);
172 d
->perfLevel(perfLevelToSet
);
176 DVFSHandler::voltageAtPerfLevel(DomainID domain_id
, PerfLevel perf_level
) const
178 VoltageDomain
*d
= findDomain(domain_id
)->voltageDomain();
180 PerfLevel n
= d
->numVoltages();
182 return d
->voltage(perf_level
);
184 // Request outside of the range of the voltage domain
186 DPRINTF(DVFS
, "DVFS: Request for perf-level %i for single-point "\
187 "voltage domain %s. Returning voltage at level 0: %.2f "\
188 "V\n", perf_level
, d
->name(), d
->voltage(0));
189 // Special case for single point voltage domain -> same voltage for
191 return d
->voltage(0);
194 warn("DVFSHandler %s reads illegal voltage level %u from "\
195 "VoltageDomain %s. Returning 0 V\n", name(), perf_level
, d
->name());
200 DVFSHandler::serialize(CheckpointOut
&cp
) const
202 //This is to ensure that the handler status is maintained during the
203 //entire simulation run and not changed from command line during checkpoint
205 SERIALIZE_SCALAR(enableHandler
);
207 // Pull out the hashed data structure into easy-to-serialise arrays;
208 // ensuring that the data associated with any pending update event is saved
209 std::vector
<DomainID
> domain_ids
;
210 std::vector
<PerfLevel
> perf_levels
;
211 std::vector
<Tick
> whens
;
212 for (const auto &ev_pair
: updatePerfLevelEvents
) {
213 DomainID id
= ev_pair
.first
;
214 const UpdateEvent
*event
= &ev_pair
.second
;
216 assert(id
== event
->domainIDToSet
);
217 domain_ids
.push_back(id
);
218 perf_levels
.push_back(event
->perfLevelToSet
);
219 whens
.push_back(event
->scheduled() ? event
->when() : 0);
221 SERIALIZE_CONTAINER(domain_ids
);
222 SERIALIZE_CONTAINER(perf_levels
);
223 SERIALIZE_CONTAINER(whens
);
227 DVFSHandler::unserialize(CheckpointIn
&cp
)
229 bool temp
= enableHandler
;
231 UNSERIALIZE_SCALAR(enableHandler
);
233 if (temp
!= enableHandler
) {
234 warn("DVFS: Forcing enable handler status to unserialized value of %d",
238 // Reconstruct the map of domain IDs and their scheduled events
239 std::vector
<DomainID
> domain_ids
;
240 std::vector
<PerfLevel
> perf_levels
;
241 std::vector
<Tick
> whens
;
242 UNSERIALIZE_CONTAINER(domain_ids
);
243 UNSERIALIZE_CONTAINER(perf_levels
);
244 UNSERIALIZE_CONTAINER(whens
);
246 for (size_t i
= 0; i
< domain_ids
.size(); ++i
) {;
247 UpdateEvent
*event
= &updatePerfLevelEvents
[domain_ids
[i
]];
249 event
->domainIDToSet
= domain_ids
[i
];
250 event
->perfLevelToSet
= perf_levels
[i
];
252 // Schedule all previously scheduled events
254 schedule(event
, whens
[i
]);
256 UpdateEvent::dvfsHandler
= this;
260 DVFSHandlerParams::create()
262 return new DVFSHandler(this);