sim-power: Addition of PowerDomains
authorAnouk Van Laer <anouk.vanlaer@arm.com>
Wed, 20 Sep 2017 17:04:25 +0000 (18:04 +0100)
committerNikos Nikoleris <nikos.nikoleris@arm.com>
Wed, 29 Apr 2020 21:03:31 +0000 (21:03 +0000)
PowerDomains group multiple objects together to regulate their power
state. There are 2 types of objects in a PowerDomain: leaders and
followers. The power state of a PowerDomain is the most performant
power state of any of the leaders. The power state of the followers is
determined by the power state of the PowerDomain they belong to: they
need to be in a power state which is more or equally performant to the
power state of the PowerDomain.

Leaders can be ClockedObjects or other PowerDomains. Followers can
only be ClockedObjects. PowerDomains can be be nested but a
PowerDomain can only be a leader of another PowerDomain, NOT a
follower. PowerDomains are not present in the hierarchy by default,
the user needs to create and configure them in the configuration file.

The user can add an hierachy by setting the led_by parameter. gem5
will then create leaders and followers for each domain and calculate
the allowed power states for the domain.

Objects in a PowerDomain need to have at least the ON state in the
possible_states.

An example of a powerDomain config is:

pd = PowerDomain()
cpu0 = BaseCPU()
cpu1 = BaseCPU()
shared_cache = BaseCache()
cache.power_state.led_by = pd
pd.led_by = [cpu0, cpu1]

This will create a PowerDomain, where the CPUs determine their own
power states and the shared cache (via the PowerDomain) follows those
power states (when possible).

Change-Id: I4c4cd01f06d45476c6e0fb2afeb778613733e2ff
Reviewed-by: Andreas Sandberg <andreas.sandberg@arm.com>
Reviewed-by: Sascha Bischoff <sascha.bischoff@arm.com>
Signed-off-by: Nikos Nikoleris <nikos.nikoleris@arm.com>
Reviewed-on: https://gem5-review.googlesource.com/c/public/gem5/+/28051
Reviewed-by: Bobby R. Bruce <bbruce@ucdavis.edu>
Maintainer: Jason Lowe-Power <power.jg@gmail.com>
Tested-by: kokoro <noreply+kokoro@google.com>
src/sim/PowerDomain.py [new file with mode: 0644]
src/sim/PowerState.py
src/sim/SConscript
src/sim/power_domain.cc [new file with mode: 0644]
src/sim/power_domain.hh [new file with mode: 0644]
src/sim/power_state.cc
src/sim/power_state.hh

diff --git a/src/sim/PowerDomain.py b/src/sim/PowerDomain.py
new file mode 100644 (file)
index 0000000..9d45252
--- /dev/null
@@ -0,0 +1,49 @@
+# 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.
+#
+
+import sys
+
+from m5.params import *
+from m5.objects.PowerState import PowerState
+
+# A power domain groups multiple ClockedObjects and creates a
+# hierarchy in which follower ClockedObjects (caches for example) can
+# change power state depeding on what the leader objects (CPUs for
+# example) do. The power domain is the link between these.
+class PowerDomain(PowerState):
+    type = 'PowerDomain'
+    cxx_header = 'sim/power_domain.hh'
+
index bfa53e2689393cc24001342edafa1e60d33d5325..30f62e074d08a2c3b4d655efbd7075a5cf91944f 100644 (file)
@@ -70,3 +70,8 @@ class PowerState(SimObject):
     clk_gate_min = Param.Latency('1ns',"Min value of the distribution")
     clk_gate_max = Param.Latency('1s',"Max value of the distribution")
     clk_gate_bins = Param.Unsigned('20', "# bins in clk gated distribution")
+
+    # The objects which drive the power state of this object. If the list is
+    # empty, the object determines its power state independently.
+    leaders = VectorParam.PowerState(
+        [], "Objects which drive the power state of this object")
index 274faf9c141a43f28f48db448a662c9d778b1756..bf8cbf5d14562d8415acff87a742a0fbe4f7d451 100644 (file)
@@ -39,6 +39,7 @@ SimObject('DVFSHandler.py')
 SimObject('SubSystem.py')
 SimObject('RedirectPath.py')
 SimObject('PowerState.py')
+SimObject('PowerDomain.py')
 
 Source('async.cc')
 Source('backtrace_%s.cc' % env['BACKTRACE_IMPL'])
@@ -77,6 +78,7 @@ Source('dvfs_handler.cc')
 Source('clocked_object.cc')
 Source('mathexpr.cc')
 Source('power_state.cc')
+Source('power_domain.cc')
 
 GTest('byteswap.test', 'byteswap.test.cc', '../base/types.cc')
 GTest('guest_abi.test', 'guest_abi.test.cc')
@@ -121,5 +123,6 @@ DebugFlag('ClockDomain')
 DebugFlag('VoltageDomain')
 DebugFlag('DVFS')
 DebugFlag('Vma')
+DebugFlag('PowerDomain')
 
 CompoundFlag('SyscallAll', [ 'SyscallBase', 'SyscallVerbose'])
diff --git a/src/sim/power_domain.cc b/src/sim/power_domain.cc
new file mode 100644 (file)
index 0000000..fdb9b99
--- /dev/null
@@ -0,0 +1,270 @@
+/*
+ * 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 "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)
+        ;
+}
+
+PowerDomain*
+PowerDomainParams::create()
+{
+    return new PowerDomain(this);
+}
diff --git a/src/sim/power_domain.hh b/src/sim/power_domain.hh
new file mode 100644 (file)
index 0000000..c5294a6
--- /dev/null
@@ -0,0 +1,166 @@
+/*
+ * 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.
+ *
+ */
+
+#ifndef __SIM_POWER_DOMAIN_HH__
+#define __SIM_POWER_DOMAIN_HH__
+
+#include <string>
+#include <vector>
+
+#include "base/statistics.hh"
+#include "params/PowerDomain.hh"
+#include "sim/clocked_object.hh"
+#include "sim/power_state.hh"
+
+/**
+ * The PowerDomain groups PowerState objects together to regulate their
+ * power states. As the PowerDomain itself is a PowerState object, you can
+ * create hierarchies of PowerDomains. All objects in a power domain will be in
+ * the power state of the domain OR a more performant one.
+ */
+class PowerDomain : public PowerState
+{
+  public:
+    PowerDomain(const PowerDomainParams* p);
+    typedef PowerDomainParams Params;
+    ~PowerDomain() override {};
+
+    /**
+     * During startup, the list of possible power states the
+     * PowerDomain can be in is populated, the power state of the
+     * PowerDomain is set and some assertions about the PowerState objects
+     * in the Domain are checked.
+     */
+    void startup() override;
+
+    /**
+     * Register the change in power state in one of the leader. The power
+     * domain will change its own power state if required and if there is a
+     * power state, it will schedule an event to update its followers
+     */
+    void pwrStateChangeCallback(Enums::PwrState new_pwr_state,
+                                PowerState* leader);
+
+    /**
+     * Function called by a follower to register itself as
+     * a dependant of this power domain
+     */
+    void addFollower(PowerState* pwr_obj) override;
+
+  private:
+    /**
+     * Calculate the power state of the power domain, based upon the power
+     * states of the leaders. This will be called if one the leaders
+     * changes its power states.
+     * If no inputs are given, only the leaders will be polled on their
+     * power state. You can also pass a vector containing the power states
+     * which the followers returned when asked to match a certain power
+     * state (called from setFollowerPowerStates)
+     */
+    Enums::PwrState calculatePowerDomainState(
+          const std::vector<Enums::PwrState> &f_states={});
+
+    /**
+     * Check if a given p_state is available across all leaders and
+     * followers in this domain.
+     */
+    bool isPossiblePwrState(Enums::PwrState p_state);
+
+    /**
+     * Calculate the possible power states of the domain based upon the
+     * intersection of the power states of the individual objects within
+     * the domain. Done at startup.
+     */
+    void calculatePossiblePwrStates();
+
+    /**
+     * Update the followers of the newly updated power state. They are
+     * required to match the power state of the power domain i.e. go to the
+     * same power state or a more performant one
+     */
+    void setFollowerPowerStates();
+
+  private: /* Power domain attributes */
+     /**
+     * List of all leaders in the PowerDomain. A leader can
+     * independently change its power state and does not depend on the
+     * PowerDomain to change its power state. A leader needs to be a
+     * PowerState object and can also be another PowerDomain. Each
+     * PowerDomain needs to have at least one leader.
+     */
+    std::vector<PowerState*> leaders;
+
+    /**
+     * Power state requested by the leader. This is not necessarily the
+     * power state of the domain as whole (as that one depends on the
+     * matched power states of the followers
+     */
+    Enums::PwrState leaderTargetState;
+
+    /**
+     * List of all followers in the PowerDomain. The power state of the
+     * domain will determine the power state of the followers. A follower
+     * cannot change its power state independently.
+     */
+    std::vector<PowerState*> followers;
+
+    /**
+     * Latency with which power state changes of the leaders will ripple
+     * through to the followers.
+     */
+    const Tick updateLatency = 1;
+
+    /**
+     * Event to update the power states of the followers
+     */
+    EventWrapper<PowerDomain, &PowerDomain::setFollowerPowerStates>
+                pwrStateUpdateEvent;
+
+  protected:
+    struct PowerDomainStats : public Stats::Group
+    {
+        PowerDomainStats(PowerDomain &pd);
+
+        void regStats() override;
+
+        Stats::Scalar numLeaderCalls;
+        Stats::Scalar numLeaderCallsChangingState;
+    } stats;
+};
+
+#endif // __SIM_POWER_DOMAIN_HH__
index a2ed7fe282a6cadf8a2e598a340886bba9cc33bd..e116f7ea8e387ccb0e8c58ce1c37f88cbba3fff7 100644 (file)
 #include "sim/power_state.hh"
 
 #include "base/logging.hh"
+#include "debug/PowerDomain.hh"
+#include "sim/power_domain.hh"
 
 PowerState::PowerState(const PowerStateParams *p) :
     SimObject(p), _currState(p->default_state),
     possibleStates(p->possible_states.begin(),
                    p->possible_states.end()),
-    prvEvalTick(0), stats(*this)
+    stats(*this)
 {
+    for (auto &pm: p->leaders) {
+        // Register this object as a follower. This object is
+        // dependent on pm for power state transitions
+        pm->addFollower(this);
+    }
+}
+
+void
+PowerState::setControlledDomain(PowerDomain* pwr_dom)
+{
+    // Only a power domain can register as dependant of a power stated
+    // object
+    controlledDomain = pwr_dom;
+    DPRINTF(PowerDomain, "%s is registered as controlled by %s \n",
+                         pwr_dom->name(), name());
 }
 
 void
@@ -102,6 +119,60 @@ PowerState::set(Enums::PwrState p)
     _currState = p;
 
     stats.numTransitions++;
+
+    // Update the domain this object controls, if there is one
+    if (controlledDomain) {
+        controlledDomain->pwrStateChangeCallback(p, this);
+    }
+
+}
+
+Enums::PwrState
+PowerState::matchPwrState(Enums::PwrState p)
+{
+    // If the object is asked to match a power state, it has to be a follower
+    // and hence should not have a pointer to a powerDomain
+    assert(controlledDomain == nullptr);
+
+    // If we are already in this power state, ignore request
+    if (_currState == p) {
+        DPRINTF(PowerDomain, "Already in p-state %s requested to match \n",
+                Enums::PwrStateStrings[p]);
+        return _currState;
+    }
+
+    Enums::PwrState old_state = _currState;
+    if (possibleStates.find(p) != possibleStates.end()) {
+        // If this power state is allowed in this object, just go there
+        set(p);
+    } else {
+        // Loop over all power states in this object and find a power state
+        // which is more performant than the requested one (considering we
+        // cannot match it exactly)
+        for (auto rev_it = possibleStates.crbegin();
+             rev_it != possibleStates.crend(); rev_it++) {
+            if (*(rev_it) <= p) {
+                // This power state is the least performant power state that is
+                // still more performant than the requested one
+                DPRINTF(PowerDomain, "Best match for %s is %s \n",
+                        Enums::PwrStateStrings[p],
+                        Enums::PwrStateStrings[*(rev_it)]);
+                set(*(rev_it));
+                break;
+            }
+        }
+    }
+    // Check if the transition happened
+    // The only case in which the power state cannot change is if the
+    // object is already at in its most performant state.
+    warn_if((_currState == old_state) &&
+            possibleStates.find(_currState) != possibleStates.begin(),
+            "Transition to power state %s was not possible, SimObject already"
+            " in the most performance state %s",
+            Enums::PwrStateStrings[p], Enums::PwrStateStrings[_currState]);
+
+    stats.numPwrMatchStateTransitions++;
+    return _currState;
 }
 
 void
@@ -147,6 +218,8 @@ PowerState::PowerStateStats::PowerStateStats(PowerState &co)
     powerState(co),
     ADD_STAT(numTransitions,
              "Number of power state transitions"),
+    ADD_STAT(numPwrMatchStateTransitions,
+             "Number of power state transitions due match request"),
     ADD_STAT(ticksClkGated,
              "Distribution of time spent in the clock gated state"),
     ADD_STAT(pwrStateResidencyTicks,
@@ -164,6 +237,7 @@ PowerState::PowerStateStats::regStats()
     const PowerStateParams *p = powerState.params();
 
     numTransitions.flags(nozero);
+    numPwrMatchStateTransitions.flags(nozero);
 
     // Each sample is time in ticks
     unsigned num_bins = std::max(p->clk_gate_bins, 10U);
index 4565c2b1f66a91bdc9e9fa85b8110fb13327ed45..fededf8f820e116080d8c89009f8ed0b472b7584 100644 (file)
@@ -52,6 +52,8 @@
 #include "sim/core.hh"
 #include "sim/sim_object.hh"
 
+class PowerDomain;
+
 /**
  * Helper class for objects that have power states. This class provides the
  * basic functionality to change between power states.
@@ -68,6 +70,9 @@ class PowerState : public SimObject
         return reinterpret_cast<const Params*>(_params);
     }
 
+    virtual void addFollower(PowerState* pwr_obj) {};
+    void setControlledDomain(PowerDomain* pwr_dom);
+
     void serialize(CheckpointOut &cp) const override;
     void unserialize(CheckpointIn &cp) override;
 
@@ -98,6 +103,12 @@ class PowerState : public SimObject
      */
     void computeStats();
 
+    /**
+     * Change the power state of this object to a power state equal to OR more
+     * performant than p. Returns the power state the object actually went to.
+     */
+    Enums::PwrState matchPwrState(Enums::PwrState p);
+
     /**
      * Return the power states this object can be in
      */
@@ -112,11 +123,17 @@ class PowerState : public SimObject
     Enums::PwrState _currState;
 
     /** The possible power states this object can be in */
-    const std::set<Enums::PwrState> possibleStates;
+    std::set<Enums::PwrState> possibleStates;
 
     /** Last tick the power stats were calculated */
     Tick prvEvalTick = 0;
 
+    /**
+     * The power domain that this power state leads, nullptr if it
+     * doesn't lead any.
+     */
+    PowerDomain* controlledDomain = nullptr;
+
     struct PowerStateStats : public Stats::Group
     {
         PowerStateStats(PowerState &ps);
@@ -127,6 +144,7 @@ class PowerState : public SimObject
         PowerState &powerState;
 
         Stats::Scalar numTransitions;
+        Stats::Scalar numPwrMatchStateTransitions;
         Stats::Distribution ticksClkGated;
         /** Tracks the time spent in each of the power states */
         Stats::Vector pwrStateResidencyTicks;