cpu: Add HTM Instruction Flags
[gem5.git] / src / sim / dvfs_handler.cc
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
38 #include "sim/dvfs_handler.hh"
39
40 #include <set>
41 #include <utility>
42
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"
51
52 //
53 //
54 // DVFSHandler methods implementation
55 //
56
57 DVFSHandler::DVFSHandler(const Params *p)
58 : SimObject(p),
59 sysClkDomain(p->sys_clk_domain),
60 enableHandler(p->enable),
61 _transLatency(p->transition_latency)
62 {
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();
68
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());
74
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);
79
80 // Create a dedicated event slot per known domain ID
81 UpdateEvent *event = &updatePerfLevelEvents[domain_id];
82 event->domainIDToSet = d->domainID();
83
84 // Add domain ID to the list of domains
85 domainIDList.push_back(d->domainID());
86 }
87 UpdateEvent::dvfsHandler = this;
88 }
89
90 DVFSHandler *DVFSHandler::UpdateEvent::dvfsHandler;
91
92 DVFSHandler::DomainID
93 DVFSHandler::domainID(uint32_t index) const
94 {
95 fatal_if(index >= numDomains(), "DVFS: Requested index out of "\
96 "bound, max value %d\n", (domainIDList.size() - 1));
97
98 assert(domains.find(domainIDList[index]) != domains.end());
99
100 return domainIDList[index];
101 }
102
103 bool
104 DVFSHandler::validDomainID(DomainID domain_id) const
105 {
106 assert(isEnabled());
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())
110 return true;
111 warn("DVFS: invalid domain ID %d, the DVFS handler does not handle this "\
112 "domain\n", domain_id);
113 return false;
114 }
115
116 bool
117 DVFSHandler::perfLevel(DomainID domain_id, PerfLevel perf_level)
118 {
119 assert(isEnabled());
120
121 DPRINTF(DVFS, "DVFS: setPerfLevel domain %d -> %d\n", domain_id, perf_level);
122
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);
127 return false;
128 }
129
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);
136 }
137
138 update_event->perfLevelToSet = perf_level;
139
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);
145 return false;
146 }
147
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);
151
152 schedule(update_event, when);
153 return true;
154 }
155
156 void
157 DVFSHandler::UpdateEvent::updatePerfLevel()
158 {
159 // Perform explicit stats dump for power estimation before performance
160 // level migration
161 Stats::dump();
162 Stats::reset();
163
164 // Update the performance level in the clock domain
165 auto d = dvfsHandler->findDomain(domainIDToSet);
166 assert(d->perfLevel() != perfLevelToSet);
167
168 d->perfLevel(perfLevelToSet);
169 }
170
171 double
172 DVFSHandler::voltageAtPerfLevel(DomainID domain_id, PerfLevel perf_level) const
173 {
174 VoltageDomain *d = findDomain(domain_id)->voltageDomain();
175 assert(d);
176 PerfLevel n = d->numVoltages();
177 if (perf_level < n)
178 return d->voltage(perf_level);
179
180 // Request outside of the range of the voltage domain
181 if (n == 1) {
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
186 // all points
187 return d->voltage(0);
188 }
189
190 warn("DVFSHandler %s reads illegal voltage level %u from "\
191 "VoltageDomain %s. Returning 0 V\n", name(), perf_level, d->name());
192 return 0.;
193 }
194
195 void
196 DVFSHandler::serialize(CheckpointOut &cp) const
197 {
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
200 //and restore
201 SERIALIZE_SCALAR(enableHandler);
202
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;
211
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);
216 }
217 SERIALIZE_CONTAINER(domain_ids);
218 SERIALIZE_CONTAINER(perf_levels);
219 SERIALIZE_CONTAINER(whens);
220 }
221
222 void
223 DVFSHandler::unserialize(CheckpointIn &cp)
224 {
225 bool temp = enableHandler;
226
227 UNSERIALIZE_SCALAR(enableHandler);
228
229 if (temp != enableHandler) {
230 warn("DVFS: Forcing enable handler status to unserialized value of %d",
231 enableHandler);
232 }
233
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);
241
242 for (size_t i = 0; i < domain_ids.size(); ++i) {;
243 UpdateEvent *event = &updatePerfLevelEvents[domain_ids[i]];
244
245 event->domainIDToSet = domain_ids[i];
246 event->perfLevelToSet = perf_levels[i];
247
248 // Schedule all previously scheduled events
249 if (whens[i])
250 schedule(event, whens[i]);
251 }
252 UpdateEvent::dvfsHandler = this;
253 }
254
255 DVFSHandler*
256 DVFSHandlerParams::create()
257 {
258 return new DVFSHandler(this);
259 }