sim-se: Add prlimit system call
[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 * 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 "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"
55
56 //
57 //
58 // DVFSHandler methods implementation
59 //
60
61 DVFSHandler::DVFSHandler(const Params *p)
62 : SimObject(p),
63 sysClkDomain(p->sys_clk_domain),
64 enableHandler(p->enable),
65 _transLatency(p->transition_latency)
66 {
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();
72
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());
78
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);
83
84 // Create a dedicated event slot per known domain ID
85 UpdateEvent *event = &updatePerfLevelEvents[domain_id];
86 event->domainIDToSet = d->domainID();
87
88 // Add domain ID to the list of domains
89 domainIDList.push_back(d->domainID());
90 }
91 UpdateEvent::dvfsHandler = this;
92 }
93
94 DVFSHandler *DVFSHandler::UpdateEvent::dvfsHandler;
95
96 DVFSHandler::DomainID
97 DVFSHandler::domainID(uint32_t index) const
98 {
99 fatal_if(index >= numDomains(), "DVFS: Requested index out of "\
100 "bound, max value %d\n", (domainIDList.size() - 1));
101
102 assert(domains.find(domainIDList[index]) != domains.end());
103
104 return domainIDList[index];
105 }
106
107 bool
108 DVFSHandler::validDomainID(DomainID domain_id) const
109 {
110 assert(isEnabled());
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())
114 return true;
115 warn("DVFS: invalid domain ID %d, the DVFS handler does not handle this "\
116 "domain\n", domain_id);
117 return false;
118 }
119
120 bool
121 DVFSHandler::perfLevel(DomainID domain_id, PerfLevel perf_level)
122 {
123 assert(isEnabled());
124
125 DPRINTF(DVFS, "DVFS: setPerfLevel domain %d -> %d\n", domain_id, perf_level);
126
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);
131 return false;
132 }
133
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);
140 }
141
142 update_event->perfLevelToSet = perf_level;
143
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);
149 return false;
150 }
151
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);
155
156 schedule(update_event, when);
157 return true;
158 }
159
160 void
161 DVFSHandler::UpdateEvent::updatePerfLevel()
162 {
163 // Perform explicit stats dump for power estimation before performance
164 // level migration
165 Stats::dump();
166 Stats::reset();
167
168 // Update the performance level in the clock domain
169 auto d = dvfsHandler->findDomain(domainIDToSet);
170 assert(d->perfLevel() != perfLevelToSet);
171
172 d->perfLevel(perfLevelToSet);
173 }
174
175 double
176 DVFSHandler::voltageAtPerfLevel(DomainID domain_id, PerfLevel perf_level) const
177 {
178 VoltageDomain *d = findDomain(domain_id)->voltageDomain();
179 assert(d);
180 PerfLevel n = d->numVoltages();
181 if (perf_level < n)
182 return d->voltage(perf_level);
183
184 // Request outside of the range of the voltage domain
185 if (n == 1) {
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
190 // all points
191 return d->voltage(0);
192 }
193
194 warn("DVFSHandler %s reads illegal voltage level %u from "\
195 "VoltageDomain %s. Returning 0 V\n", name(), perf_level, d->name());
196 return 0.;
197 }
198
199 void
200 DVFSHandler::serialize(CheckpointOut &cp) const
201 {
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
204 //and restore
205 SERIALIZE_SCALAR(enableHandler);
206
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;
215
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);
220 }
221 SERIALIZE_CONTAINER(domain_ids);
222 SERIALIZE_CONTAINER(perf_levels);
223 SERIALIZE_CONTAINER(whens);
224 }
225
226 void
227 DVFSHandler::unserialize(CheckpointIn &cp)
228 {
229 bool temp = enableHandler;
230
231 UNSERIALIZE_SCALAR(enableHandler);
232
233 if (temp != enableHandler) {
234 warn("DVFS: Forcing enable handler status to unserialized value of %d",
235 enableHandler);
236 }
237
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);
245
246 for (size_t i = 0; i < domain_ids.size(); ++i) {;
247 UpdateEvent *event = &updatePerfLevelEvents[domain_ids[i]];
248
249 event->domainIDToSet = domain_ids[i];
250 event->perfLevelToSet = perf_levels[i];
251
252 // Schedule all previously scheduled events
253 if (whens[i])
254 schedule(event, whens[i]);
255 }
256 UpdateEvent::dvfsHandler = this;
257 }
258
259 DVFSHandler*
260 DVFSHandlerParams::create()
261 {
262 return new DVFSHandler(this);
263 }