base: Rename Flags::update as Flags::replace
[gem5.git] / src / sim / power_state.cc
1 /*
2 * Copyright (c) 2015-2017, 2019-2020 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/power_state.hh"
39
40 #include <cassert>
41
42 #include "base/logging.hh"
43 #include "base/trace.hh"
44 #include "debug/PowerDomain.hh"
45 #include "sim/power_domain.hh"
46 #include "sim/serialize.hh"
47
48 PowerState::PowerState(const PowerStateParams &p) :
49 SimObject(p), _currState(p.default_state),
50 possibleStates(p.possible_states.begin(),
51 p.possible_states.end()),
52 stats(*this)
53 {
54 for (auto &pm: p.leaders) {
55 // Register this object as a follower. This object is
56 // dependent on pm for power state transitions
57 pm->addFollower(this);
58 }
59 }
60
61 void
62 PowerState::setControlledDomain(PowerDomain* pwr_dom)
63 {
64 // Only a power domain can register as dependant of a power stated
65 // object
66 controlledDomain = pwr_dom;
67 DPRINTF(PowerDomain, "%s is registered as controlled by %s \n",
68 pwr_dom->name(), name());
69 }
70
71 void
72 PowerState::serialize(CheckpointOut &cp) const
73 {
74 unsigned int currState = (unsigned int)_currState;
75
76 SERIALIZE_SCALAR(currState);
77 SERIALIZE_SCALAR(prvEvalTick);
78 }
79
80 void
81 PowerState::unserialize(CheckpointIn &cp)
82 {
83 unsigned int currState;
84
85 UNSERIALIZE_SCALAR(currState);
86 UNSERIALIZE_SCALAR(prvEvalTick);
87
88 _currState = Enums::PwrState(currState);
89 }
90
91 void
92 PowerState::set(Enums::PwrState p)
93 {
94 // Check if this power state is actually allowed by checking whether it is
95 // present in pwrStateToIndex-dictionary
96 panic_if(possibleStates.find(p) == possibleStates.end(),
97 "Cannot go to %s in %s \n", Enums::PwrStateStrings[p], name());
98
99 // Function should ideally be called only when there is a state change
100 if (_currState == p) {
101 warn_once("PowerState: Already in the requested power state, "
102 "request ignored");
103 return;
104 }
105
106 // No need to compute stats if in the same tick, update state though. This
107 // can happen in cases like a) during start of the simulation multiple
108 // state changes happens in init/startup phase, b) one takes a decision to
109 // migrate state but decides to reverts back to the original state in the
110 // same tick if other conditions are not met elsewhere.
111 // Any state change related stats would have been recorded on previous call
112 // to this function.
113 if (prvEvalTick == curTick() && curTick() != 0) {
114 warn("PowerState: More than one power state change request "
115 "encountered within the same simulation tick");
116 _currState = p;
117 return;
118 }
119
120 // Record stats for previous state.
121 computeStats();
122
123 _currState = p;
124
125 stats.numTransitions++;
126
127 // Update the domain this object controls, if there is one
128 if (controlledDomain) {
129 controlledDomain->pwrStateChangeCallback(p, this);
130 }
131
132 }
133
134 Enums::PwrState
135 PowerState::matchPwrState(Enums::PwrState p)
136 {
137 // If the object is asked to match a power state, it has to be a follower
138 // and hence should not have a pointer to a powerDomain
139 assert(controlledDomain == nullptr);
140
141 // If we are already in this power state, ignore request
142 if (_currState == p) {
143 DPRINTF(PowerDomain, "Already in p-state %s requested to match \n",
144 Enums::PwrStateStrings[p]);
145 return _currState;
146 }
147
148 Enums::PwrState old_state = _currState;
149 if (possibleStates.find(p) != possibleStates.end()) {
150 // If this power state is allowed in this object, just go there
151 set(p);
152 } else {
153 // Loop over all power states in this object and find a power state
154 // which is more performant than the requested one (considering we
155 // cannot match it exactly)
156 for (auto rev_it = possibleStates.crbegin();
157 rev_it != possibleStates.crend(); rev_it++) {
158 if (*(rev_it) <= p) {
159 // This power state is the least performant power state that is
160 // still more performant than the requested one
161 DPRINTF(PowerDomain, "Best match for %s is %s \n",
162 Enums::PwrStateStrings[p],
163 Enums::PwrStateStrings[*(rev_it)]);
164 set(*(rev_it));
165 break;
166 }
167 }
168 }
169 // Check if the transition happened
170 // The only case in which the power state cannot change is if the
171 // object is already at in its most performant state.
172 warn_if((_currState == old_state) &&
173 possibleStates.find(_currState) != possibleStates.begin(),
174 "Transition to power state %s was not possible, SimObject already"
175 " in the most performance state %s",
176 Enums::PwrStateStrings[p], Enums::PwrStateStrings[_currState]);
177
178 stats.numPwrMatchStateTransitions++;
179 return _currState;
180 }
181
182 void
183 PowerState::computeStats()
184 {
185 // Calculate time elapsed from last (valid) state change
186 Tick elapsed_time = curTick() - prvEvalTick;
187
188 stats.pwrStateResidencyTicks[_currState] += elapsed_time;
189
190 // Time spent in CLK_GATED state, this might change depending on
191 // transition to other low power states in respective simulation
192 // objects.
193 if (_currState == Enums::PwrState::CLK_GATED) {
194 stats.ticksClkGated.sample(elapsed_time);
195 }
196
197 prvEvalTick = curTick();
198 }
199
200 std::vector<double>
201 PowerState::getWeights() const
202 {
203 // Get residency stats
204 std::vector<double> ret;
205 Stats::VCounter residencies;
206 stats.pwrStateResidencyTicks.value(residencies);
207
208 // Account for current state too!
209 Tick elapsed_time = curTick() - prvEvalTick;
210 residencies[_currState] += elapsed_time;
211
212 ret.resize(Enums::PwrState::Num_PwrState);
213 for (unsigned i = 0; i < Enums::PwrState::Num_PwrState; i++)
214 ret[i] = residencies[i] / \
215 (stats.pwrStateResidencyTicks.total() + elapsed_time);
216
217 return ret;
218 }
219
220 PowerState::PowerStateStats::PowerStateStats(PowerState &co)
221 : Stats::Group(&co),
222 powerState(co),
223 ADD_STAT(numTransitions,
224 "Number of power state transitions"),
225 ADD_STAT(numPwrMatchStateTransitions,
226 "Number of power state transitions due match request"),
227 ADD_STAT(ticksClkGated,
228 "Distribution of time spent in the clock gated state"),
229 ADD_STAT(pwrStateResidencyTicks,
230 "Cumulative time (in ticks) in various power states")
231 {
232 }
233
234 void
235 PowerState::PowerStateStats::regStats()
236 {
237 Stats::Group::regStats();
238
239 using namespace Stats;
240
241 const PowerStateParams &p = powerState.params();
242
243 numTransitions.flags(nozero);
244 numPwrMatchStateTransitions.flags(nozero);
245
246 // Each sample is time in ticks
247 unsigned num_bins = std::max(p.clk_gate_bins, 10U);
248 ticksClkGated
249 .init(p.clk_gate_min, p.clk_gate_max, (p.clk_gate_max / num_bins))
250 .flags(pdf | nozero | nonan)
251 ;
252
253 pwrStateResidencyTicks
254 .init(Enums::PwrState::Num_PwrState)
255 .flags(nozero)
256 ;
257 for (int i = 0; i < Enums::PwrState::Num_PwrState; i++) {
258 pwrStateResidencyTicks.subname(i, Enums::PwrStateStrings[i]);
259 }
260
261 numTransitions = 0;
262 }
263
264 void
265 PowerState::PowerStateStats::preDumpStats()
266 {
267 Stats::Group::preDumpStats();
268
269 /**
270 * For every stats dump, the power state residency and other distribution
271 * stats should be computed just before the dump to ensure correct stats
272 * value being reported for current dump window. It avoids things like
273 * having any unreported time spent in a power state to be forwarded to the
274 * next dump window which might have rather unpleasant effects (like
275 * perturbing the distribution stats).
276 */
277 powerState.computeStats();
278 }