Most create() methods are no longer necessary. This change deletes them, and occasionally moves some code from them into the constructors they call. Change-Id: Icbab29ba280144b892f9b12fac9e29a0839477e5 Reviewed-on: https://gem5-review.googlesource.com/c/public/gem5/+/36536 Reviewed-by: Gabe Black <gabe.black@gmail.com> Maintainer: Gabe Black <gabe.black@gmail.com> Tested-by: kokoro <noreply+kokoro@google.com>
266 lines
10 KiB
C++
266 lines
10 KiB
C++
/*
|
|
* Copyright (c) 2017, 2019-2020 ARM Limited
|
|
* All rights reserved
|
|
*
|
|
* The license below extends only to copyright in the software and shall
|
|
* not be construed as granting a license to any other intellectual
|
|
* property including but not limited to intellectual property relating
|
|
* to a hardware implementation of the functionality of the software
|
|
* licensed hereunder. You may use the software subject to the license
|
|
* terms below provided that you ensure that this notice is replicated
|
|
* unmodified and in its entirety in all distributions of the software,
|
|
* modified or unmodified, in source code or in binary form.
|
|
*
|
|
* Redistribution and use in source and binary forms, with or without
|
|
* modification, are permitted provided that the following conditions are
|
|
* met: redistributions of source code must retain the above copyright
|
|
* notice, this list of conditions and the following disclaimer;
|
|
* redistributions in binary form must reproduce the above copyright
|
|
* notice, this list of conditions and the following disclaimer in the
|
|
* documentation and/or other materials provided with the distribution;
|
|
* neither the name of the copyright holders nor the names of its
|
|
* contributors may be used to endorse or promote products derived from
|
|
* this software without specific prior written permission.
|
|
*
|
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
|
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
|
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
|
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
|
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
|
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
|
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
|
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
|
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
|
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
|
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
*/
|
|
|
|
#include "sim/power_domain.hh"
|
|
|
|
#include <unordered_map>
|
|
|
|
#include "base/trace.hh"
|
|
#include "debug/PowerDomain.hh"
|
|
|
|
PowerDomain::PowerDomain(const PowerDomainParams &p) :
|
|
PowerState(p),
|
|
leaders(p.leaders),
|
|
pwrStateUpdateEvent(*this),
|
|
stats(*this)
|
|
{
|
|
// Check if there is at least one leader
|
|
fatal_if(leaders.empty(), "No leaders registered in %s!)", name());
|
|
|
|
// Go over the leaders and register this power domain with them
|
|
for (auto leader : leaders) {
|
|
leader->setControlledDomain(this);
|
|
}
|
|
|
|
// We will assume a power domain to start in the most performant p-state
|
|
// This will be corrected during startup()
|
|
leaderTargetState = Enums::PwrState::ON;
|
|
_currState = Enums::PwrState::ON;
|
|
}
|
|
|
|
void
|
|
PowerDomain::addFollower(PowerState* pwr_obj)
|
|
{
|
|
DPRINTF(PowerDomain, "%s is a follower in %s\n", pwr_obj->name(), name());
|
|
followers.push_back(pwr_obj);
|
|
}
|
|
|
|
void
|
|
PowerDomain::startup()
|
|
{
|
|
DPRINTF(PowerDomain, "Checks at startup\n");
|
|
// Check if the leaders and followers have the correct power states.
|
|
DPRINTF(PowerDomain, "Checking power state of leaders & followers\n");
|
|
for (const auto &objs : { leaders, followers }) {
|
|
for (const auto &obj : objs) {
|
|
const auto & states = obj->getPossibleStates();
|
|
auto it = states.find(Enums::PwrState::ON);
|
|
fatal_if(it == states.end(),
|
|
"%s in %s does not have the required power states to be "
|
|
"part of a PowerDomain i.e. the ON state!", obj->name(),
|
|
name());
|
|
}
|
|
}
|
|
|
|
// Now all objects have been checked for the minimally required power
|
|
// states, calculate the possible power states for the domain. This is the
|
|
// intersection between the possible power states of the followers and
|
|
// leaders.
|
|
calculatePossiblePwrStates();
|
|
|
|
// Check that there is no objects which is both a leader and a
|
|
// follower.
|
|
DPRINTF(PowerDomain, "Checking for double entries\n");
|
|
for (auto follower : followers) {
|
|
for (auto leader : leaders) {
|
|
fatal_if(leader == follower, "%s is both a leader and follower"
|
|
" in %s\n!", leader->name(), name());
|
|
}
|
|
}
|
|
// Record the power states of the leaders and followers
|
|
DPRINTF(PowerDomain, "Recording the current power states in domain\n");
|
|
for (auto leader : leaders) {
|
|
Enums::PwrState pws = leader->get();
|
|
fatal_if(pws == Enums::PwrState::UNDEFINED,
|
|
"%s is in the UNDEFINED power state, not acceptable as "
|
|
"leader!", leader->name());
|
|
}
|
|
|
|
// Calculate the power state of the domain, only looking at leader
|
|
leaderTargetState = calculatePowerDomainState();
|
|
// Set the power states of the followers, based upon leaderTargetState.
|
|
setFollowerPowerStates();
|
|
}
|
|
|
|
bool
|
|
PowerDomain::isPossiblePwrState(Enums::PwrState p_state)
|
|
{
|
|
for (const auto &objs : { leaders, followers }) {
|
|
for (const auto &obj : objs) {
|
|
const auto &obj_states = obj->getPossibleStates();
|
|
if (obj_states.find(p_state) == obj_states.end()) {
|
|
return false;
|
|
}
|
|
}
|
|
}
|
|
return true;
|
|
}
|
|
|
|
void
|
|
PowerDomain::calculatePossiblePwrStates()
|
|
{
|
|
assert(possibleStates.empty());
|
|
for (auto p_state: leaders[0]->getPossibleStates()) {
|
|
if (isPossiblePwrState(p_state)) {
|
|
possibleStates.emplace(p_state);
|
|
DPRINTF(PowerDomain, "%u/%s is a p-state\n", p_state,
|
|
Enums::PwrStateStrings[p_state]);
|
|
}
|
|
}
|
|
}
|
|
|
|
Enums::PwrState
|
|
PowerDomain::calculatePowerDomainState(
|
|
const std::vector<Enums::PwrState> &f_states)
|
|
{
|
|
DPRINTF(PowerDomain, "Calculating the power state\n");
|
|
Enums::PwrState most_perf_state = Enums::PwrState::Num_PwrState;
|
|
std::string most_perf_leader;
|
|
for (auto leader : leaders) {
|
|
Enums::PwrState pw = leader->get();
|
|
if (pw < most_perf_state) {
|
|
most_perf_state = pw;
|
|
most_perf_leader = leader->name();
|
|
}
|
|
}
|
|
assert(most_perf_state != Enums::PwrState::Num_PwrState);
|
|
DPRINTF(PowerDomain, "Most performant leader is %s, at %u\n",
|
|
most_perf_leader, most_perf_state);
|
|
|
|
// If asked to check the power states of the followers (f_states contains
|
|
// the power states of the followers)
|
|
if (!f_states.empty()) {
|
|
for (Enums::PwrState f_pw : f_states ) {
|
|
// Ignore UNDEFINED state of follower, at startup the followers
|
|
// might be in the UNDEFINED state, PowerDomain will pull them up
|
|
if ((f_pw != Enums::PwrState::UNDEFINED) &&
|
|
(f_pw < most_perf_state)) {
|
|
most_perf_state = f_pw;
|
|
}
|
|
}
|
|
DPRINTF(PowerDomain, "Most performant state, including followers "
|
|
"is %u\n", most_perf_state);
|
|
}
|
|
return most_perf_state;
|
|
}
|
|
|
|
void
|
|
PowerDomain::setFollowerPowerStates()
|
|
{
|
|
// Loop over all followers and tell them to change their power state so
|
|
// they match that of the power domain (or a more performant power state)
|
|
std::vector<Enums::PwrState> matched_states;
|
|
for (auto follower : followers) {
|
|
Enums::PwrState actual_pws =
|
|
follower->matchPwrState(leaderTargetState);
|
|
matched_states.push_back(actual_pws);
|
|
assert(actual_pws <= leaderTargetState);
|
|
DPRINTF(PowerDomain, "%u matched domain power state (%u) with %u\n",
|
|
follower->name(), leaderTargetState,
|
|
actual_pws);
|
|
}
|
|
// Now the power states of the follower have been changed recalculate the
|
|
// power state of the domain as a whole, including followers
|
|
Enums::PwrState new_power_state =
|
|
calculatePowerDomainState(matched_states);
|
|
if (new_power_state != _currState) {
|
|
// Change in power state of the domain, so update. Updates in power
|
|
// state need to happen via set() so it can propagate to
|
|
// overarching power domains (if there are any).
|
|
DPRINTF(PowerDomain, "Updated power domain state to %u\n",
|
|
new_power_state);
|
|
set(new_power_state);
|
|
}
|
|
}
|
|
|
|
void
|
|
PowerDomain::pwrStateChangeCallback(Enums::PwrState new_pwr_state,
|
|
PowerState* leader)
|
|
{
|
|
DPRINTF(PowerDomain, "PwrState update to %u by %s\n", new_pwr_state,
|
|
leader->name());
|
|
|
|
Enums::PwrState old_target_state = leaderTargetState;
|
|
// Calculate the power state of the domain, based on the leaders
|
|
if (new_pwr_state < _currState) {
|
|
// The power state of the power domain always needs to match that of
|
|
// the most performant leader so no need to go over the other leaders
|
|
// The power state need to be changed via a the PwrStateCall() so any
|
|
// overarching power domains get informed
|
|
leaderTargetState = new_pwr_state;
|
|
} else {
|
|
// Need to calculate the newly required power state, based on the
|
|
// leaders only and change to that state.
|
|
leaderTargetState = calculatePowerDomainState();
|
|
}
|
|
if (old_target_state!= leaderTargetState) {
|
|
// The followers will try to match that power state requested by the
|
|
// leaders in in the update event, based upon the actual power state,
|
|
// we will 'officially' change the power state of the domain by calling
|
|
// set()
|
|
schedule(pwrStateUpdateEvent, curTick() + updateLatency);
|
|
DPRINTF(PowerDomain, "TargetState change from %u to %u, followers will"
|
|
"be updated in %u ticks\n", old_target_state,
|
|
leaderTargetState, updateLatency);
|
|
stats.numLeaderCallsChangingState++;
|
|
}
|
|
stats.numLeaderCalls++;
|
|
}
|
|
|
|
PowerDomain::PowerDomainStats::PowerDomainStats(PowerDomain &pd)
|
|
: Stats::Group(&pd),
|
|
ADD_STAT(numLeaderCalls,
|
|
"Number of calls by leaders to change power domain state"),
|
|
ADD_STAT(numLeaderCallsChangingState,
|
|
"Number of calls by leader to change power domain state "
|
|
"actually resulting in a power state change")
|
|
{
|
|
}
|
|
|
|
void
|
|
PowerDomain::PowerDomainStats::regStats()
|
|
{
|
|
Stats::Group::regStats();
|
|
|
|
numLeaderCalls
|
|
.flags(Stats::nozero)
|
|
;
|
|
numLeaderCallsChangingState
|
|
.flags(Stats::nozero)
|
|
;
|
|
}
|