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.
38 #include "sim/dvfs_handler.hh"
43 #include "base/logging.hh"
44 #include "base/trace.hh"
45 #include "debug/DVFS.hh"
46 #include "params/DVFSHandler.hh"
47 #include "sim/clock_domain.hh"
48 #include "sim/eventq.hh"
49 #include "sim/stat_control.hh"
50 #include "sim/voltage_domain.hh"
54 // DVFSHandler methods implementation
57 DVFSHandler::DVFSHandler(const Params
&p
)
59 sysClkDomain(p
.sys_clk_domain
),
60 enableHandler(p
.enable
),
61 _transLatency(p
.transition_latency
)
63 // Check supplied list of domains for sanity and add them to the
64 // domain ID -> domain* hash
65 for (auto dit
= p
.domains
.begin(); dit
!= p
.domains
.end(); ++dit
) {
66 SrcClockDomain
*d
= *dit
;
67 DomainID domain_id
= d
->domainID();
69 fatal_if(sysClkDomain
== d
, "DVFS: Domain config list has a "\
70 "system clk domain entry");
71 fatal_if(domain_id
== SrcClockDomain::emptyDomainID
,
72 "DVFS: Controlled domain %s needs to have a properly "\
73 " assigned ID.\n", d
->name());
75 auto entry
= std::make_pair(domain_id
, d
);
76 bool new_elem
= domains
.insert(entry
).second
;
77 fatal_if(!new_elem
, "DVFS: Domain %s with ID %d does not have a "\
78 "unique ID.\n", d
->name(), domain_id
);
80 // Create a dedicated event slot per known domain ID
81 UpdateEvent
*event
= &updatePerfLevelEvents
[domain_id
];
82 event
->domainIDToSet
= d
->domainID();
84 // Add domain ID to the list of domains
85 domainIDList
.push_back(d
->domainID());
87 UpdateEvent::dvfsHandler
= this;
90 DVFSHandler
*DVFSHandler::UpdateEvent::dvfsHandler
;
93 DVFSHandler::domainID(uint32_t index
) const
95 fatal_if(index
>= numDomains(), "DVFS: Requested index out of "\
96 "bound, max value %d\n", (domainIDList
.size() - 1));
98 assert(domains
.find(domainIDList
[index
]) != domains
.end());
100 return domainIDList
[index
];
104 DVFSHandler::validDomainID(DomainID domain_id
) const
107 // This is ensure that the domain id as requested by the software is
108 // availabe in the handler.
109 if (domains
.find(domain_id
) != domains
.end())
111 warn("DVFS: invalid domain ID %d, the DVFS handler does not handle this "\
112 "domain\n", domain_id
);
117 DVFSHandler::perfLevel(DomainID domain_id
, PerfLevel perf_level
)
121 DPRINTF(DVFS
, "DVFS: setPerfLevel domain %d -> %d\n", domain_id
, perf_level
);
123 auto d
= findDomain(domain_id
);
124 if (!d
->validPerfLevel(perf_level
)) {
125 warn("DVFS: invalid performance level %d for domain ID %d, request "\
126 "ignored\n", perf_level
, domain_id
);
130 UpdateEvent
*update_event
= &updatePerfLevelEvents
[domain_id
];
131 // Drop an old DVFS change request once we have established that this is a
132 // reasonable request
133 if (update_event
->scheduled()) {
134 DPRINTF(DVFS
, "DVFS: Overwriting the previous DVFS event.\n");
135 deschedule(update_event
);
138 update_event
->perfLevelToSet
= perf_level
;
140 // State changes that restore to the current state (and / or overwrite a not
141 // yet completed in-flight request) will be squashed
142 if (d
->perfLevel() == perf_level
) {
143 DPRINTF(DVFS
, "DVFS: Ignoring ineffective performance level change "\
144 "%d -> %d\n", d
->perfLevel(), perf_level
);
148 // At this point, a new transition will certainly take place -> schedule
149 Tick when
= curTick() + _transLatency
;
150 DPRINTF(DVFS
, "DVFS: Update for perf event scheduled for %ld\n", when
);
152 schedule(update_event
, when
);
157 DVFSHandler::UpdateEvent::updatePerfLevel()
159 // Perform explicit stats dump for power estimation before performance
164 // Update the performance level in the clock domain
165 auto d
= dvfsHandler
->findDomain(domainIDToSet
);
166 assert(d
->perfLevel() != perfLevelToSet
);
168 d
->perfLevel(perfLevelToSet
);
172 DVFSHandler::voltageAtPerfLevel(DomainID domain_id
, PerfLevel perf_level
) const
174 VoltageDomain
*d
= findDomain(domain_id
)->voltageDomain();
176 PerfLevel n
= d
->numVoltages();
178 return d
->voltage(perf_level
);
180 // Request outside of the range of the voltage domain
182 DPRINTF(DVFS
, "DVFS: Request for perf-level %i for single-point "\
183 "voltage domain %s. Returning voltage at level 0: %.2f "\
184 "V\n", perf_level
, d
->name(), d
->voltage(0));
185 // Special case for single point voltage domain -> same voltage for
187 return d
->voltage(0);
190 warn("DVFSHandler %s reads illegal voltage level %u from "\
191 "VoltageDomain %s. Returning 0 V\n", name(), perf_level
, d
->name());
196 DVFSHandler::serialize(CheckpointOut
&cp
) const
198 //This is to ensure that the handler status is maintained during the
199 //entire simulation run and not changed from command line during checkpoint
201 SERIALIZE_SCALAR(enableHandler
);
203 // Pull out the hashed data structure into easy-to-serialise arrays;
204 // ensuring that the data associated with any pending update event is saved
205 std::vector
<DomainID
> domain_ids
;
206 std::vector
<PerfLevel
> perf_levels
;
207 std::vector
<Tick
> whens
;
208 for (const auto &ev_pair
: updatePerfLevelEvents
) {
209 DomainID id
= ev_pair
.first
;
210 const UpdateEvent
*event
= &ev_pair
.second
;
212 assert(id
== event
->domainIDToSet
);
213 domain_ids
.push_back(id
);
214 perf_levels
.push_back(event
->perfLevelToSet
);
215 whens
.push_back(event
->scheduled() ? event
->when() : 0);
217 SERIALIZE_CONTAINER(domain_ids
);
218 SERIALIZE_CONTAINER(perf_levels
);
219 SERIALIZE_CONTAINER(whens
);
223 DVFSHandler::unserialize(CheckpointIn
&cp
)
225 bool temp
= enableHandler
;
227 UNSERIALIZE_SCALAR(enableHandler
);
229 if (temp
!= enableHandler
) {
230 warn("DVFS: Forcing enable handler status to unserialized value of %d",
234 // Reconstruct the map of domain IDs and their scheduled events
235 std::vector
<DomainID
> domain_ids
;
236 std::vector
<PerfLevel
> perf_levels
;
237 std::vector
<Tick
> whens
;
238 UNSERIALIZE_CONTAINER(domain_ids
);
239 UNSERIALIZE_CONTAINER(perf_levels
);
240 UNSERIALIZE_CONTAINER(whens
);
242 for (size_t i
= 0; i
< domain_ids
.size(); ++i
) {;
243 UpdateEvent
*event
= &updatePerfLevelEvents
[domain_ids
[i
]];
245 event
->domainIDToSet
= domain_ids
[i
];
246 event
->perfLevelToSet
= perf_levels
[i
];
248 // Schedule all previously scheduled events
250 schedule(event
, whens
[i
]);
252 UpdateEvent::dvfsHandler
= this;