tests: arch-power: Add 64-bit hello binaries
[gem5.git] / src / sim / power_domain.cc
1 /*
2 * Copyright (c) 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_domain.hh"
39
40 #include <unordered_map>
41
42 #include "base/trace.hh"
43 #include "debug/PowerDomain.hh"
44
45 PowerDomain::PowerDomain(const PowerDomainParams &p) :
46 PowerState(p),
47 leaders(p.leaders),
48 pwrStateUpdateEvent(*this),
49 stats(*this)
50 {
51 // Check if there is at least one leader
52 fatal_if(leaders.empty(), "No leaders registered in %s!)", name());
53
54 // Go over the leaders and register this power domain with them
55 for (auto leader : leaders) {
56 leader->setControlledDomain(this);
57 }
58
59 // We will assume a power domain to start in the most performant p-state
60 // This will be corrected during startup()
61 leaderTargetState = Enums::PwrState::ON;
62 _currState = Enums::PwrState::ON;
63 }
64
65 void
66 PowerDomain::addFollower(PowerState* pwr_obj)
67 {
68 DPRINTF(PowerDomain, "%s is a follower in %s\n", pwr_obj->name(), name());
69 followers.push_back(pwr_obj);
70 }
71
72 void
73 PowerDomain::startup()
74 {
75 DPRINTF(PowerDomain, "Checks at startup\n");
76 // Check if the leaders and followers have the correct power states.
77 DPRINTF(PowerDomain, "Checking power state of leaders & followers\n");
78 for (const auto &objs : { leaders, followers }) {
79 for (const auto &obj : objs) {
80 const auto & states = obj->getPossibleStates();
81 auto it = states.find(Enums::PwrState::ON);
82 fatal_if(it == states.end(),
83 "%s in %s does not have the required power states to be "
84 "part of a PowerDomain i.e. the ON state!", obj->name(),
85 name());
86 }
87 }
88
89 // Now all objects have been checked for the minimally required power
90 // states, calculate the possible power states for the domain. This is the
91 // intersection between the possible power states of the followers and
92 // leaders.
93 calculatePossiblePwrStates();
94
95 // Check that there is no objects which is both a leader and a
96 // follower.
97 DPRINTF(PowerDomain, "Checking for double entries\n");
98 for (auto follower : followers) {
99 for (auto leader : leaders) {
100 fatal_if(leader == follower, "%s is both a leader and follower"
101 " in %s\n!", leader->name(), name());
102 }
103 }
104 // Record the power states of the leaders and followers
105 DPRINTF(PowerDomain, "Recording the current power states in domain\n");
106 for (auto leader : leaders) {
107 Enums::PwrState pws = leader->get();
108 fatal_if(pws == Enums::PwrState::UNDEFINED,
109 "%s is in the UNDEFINED power state, not acceptable as "
110 "leader!", leader->name());
111 }
112
113 // Calculate the power state of the domain, only looking at leader
114 leaderTargetState = calculatePowerDomainState();
115 // Set the power states of the followers, based upon leaderTargetState.
116 setFollowerPowerStates();
117 }
118
119 bool
120 PowerDomain::isPossiblePwrState(Enums::PwrState p_state)
121 {
122 for (const auto &objs : { leaders, followers }) {
123 for (const auto &obj : objs) {
124 const auto &obj_states = obj->getPossibleStates();
125 if (obj_states.find(p_state) == obj_states.end()) {
126 return false;
127 }
128 }
129 }
130 return true;
131 }
132
133 void
134 PowerDomain::calculatePossiblePwrStates()
135 {
136 assert(possibleStates.empty());
137 for (auto p_state: leaders[0]->getPossibleStates()) {
138 if (isPossiblePwrState(p_state)) {
139 possibleStates.emplace(p_state);
140 DPRINTF(PowerDomain, "%u/%s is a p-state\n", p_state,
141 Enums::PwrStateStrings[p_state]);
142 }
143 }
144 }
145
146 Enums::PwrState
147 PowerDomain::calculatePowerDomainState(
148 const std::vector<Enums::PwrState> &f_states)
149 {
150 DPRINTF(PowerDomain, "Calculating the power state\n");
151 Enums::PwrState most_perf_state = Enums::PwrState::Num_PwrState;
152 std::string most_perf_leader;
153 for (auto leader : leaders) {
154 Enums::PwrState pw = leader->get();
155 if (pw < most_perf_state) {
156 most_perf_state = pw;
157 most_perf_leader = leader->name();
158 }
159 }
160 assert(most_perf_state != Enums::PwrState::Num_PwrState);
161 DPRINTF(PowerDomain, "Most performant leader is %s, at %u\n",
162 most_perf_leader, most_perf_state);
163
164 // If asked to check the power states of the followers (f_states contains
165 // the power states of the followers)
166 if (!f_states.empty()) {
167 for (Enums::PwrState f_pw : f_states ) {
168 // Ignore UNDEFINED state of follower, at startup the followers
169 // might be in the UNDEFINED state, PowerDomain will pull them up
170 if ((f_pw != Enums::PwrState::UNDEFINED) &&
171 (f_pw < most_perf_state)) {
172 most_perf_state = f_pw;
173 }
174 }
175 DPRINTF(PowerDomain, "Most performant state, including followers "
176 "is %u\n", most_perf_state);
177 }
178 return most_perf_state;
179 }
180
181 void
182 PowerDomain::setFollowerPowerStates()
183 {
184 // Loop over all followers and tell them to change their power state so
185 // they match that of the power domain (or a more performant power state)
186 std::vector<Enums::PwrState> matched_states;
187 for (auto follower : followers) {
188 Enums::PwrState actual_pws =
189 follower->matchPwrState(leaderTargetState);
190 matched_states.push_back(actual_pws);
191 assert(actual_pws <= leaderTargetState);
192 DPRINTF(PowerDomain, "%u matched domain power state (%u) with %u\n",
193 follower->name(), leaderTargetState,
194 actual_pws);
195 }
196 // Now the power states of the follower have been changed recalculate the
197 // power state of the domain as a whole, including followers
198 Enums::PwrState new_power_state =
199 calculatePowerDomainState(matched_states);
200 if (new_power_state != _currState) {
201 // Change in power state of the domain, so update. Updates in power
202 // state need to happen via set() so it can propagate to
203 // overarching power domains (if there are any).
204 DPRINTF(PowerDomain, "Updated power domain state to %u\n",
205 new_power_state);
206 set(new_power_state);
207 }
208 }
209
210 void
211 PowerDomain::pwrStateChangeCallback(Enums::PwrState new_pwr_state,
212 PowerState* leader)
213 {
214 DPRINTF(PowerDomain, "PwrState update to %u by %s\n", new_pwr_state,
215 leader->name());
216
217 Enums::PwrState old_target_state = leaderTargetState;
218 // Calculate the power state of the domain, based on the leaders
219 if (new_pwr_state < _currState) {
220 // The power state of the power domain always needs to match that of
221 // the most performant leader so no need to go over the other leaders
222 // The power state need to be changed via a the PwrStateCall() so any
223 // overarching power domains get informed
224 leaderTargetState = new_pwr_state;
225 } else {
226 // Need to calculate the newly required power state, based on the
227 // leaders only and change to that state.
228 leaderTargetState = calculatePowerDomainState();
229 }
230 if (old_target_state!= leaderTargetState) {
231 // The followers will try to match that power state requested by the
232 // leaders in in the update event, based upon the actual power state,
233 // we will 'officially' change the power state of the domain by calling
234 // set()
235 schedule(pwrStateUpdateEvent, curTick() + updateLatency);
236 DPRINTF(PowerDomain, "TargetState change from %u to %u, followers will"
237 "be updated in %u ticks\n", old_target_state,
238 leaderTargetState, updateLatency);
239 stats.numLeaderCallsChangingState++;
240 }
241 stats.numLeaderCalls++;
242 }
243
244 PowerDomain::PowerDomainStats::PowerDomainStats(PowerDomain &pd)
245 : Stats::Group(&pd),
246 ADD_STAT(numLeaderCalls, UNIT_COUNT,
247 "Number of calls by leaders to change power domain state"),
248 ADD_STAT(numLeaderCallsChangingState, UNIT_COUNT,
249 "Number of calls by leader to change power domain state actually "
250 "resulting in a power state change")
251 {
252 }
253
254 void
255 PowerDomain::PowerDomainStats::regStats()
256 {
257 Stats::Group::regStats();
258
259 numLeaderCalls
260 .flags(Stats::nozero)
261 ;
262 numLeaderCallsChangingState
263 .flags(Stats::nozero)
264 ;
265 }