energy: Small extentions and fixes for DVFS handler
authorStephan Diestelhorst <stephan.diestelhorst@arm.com>
Mon, 16 Jun 2014 13:59:44 +0000 (14:59 +0100)
committerStephan Diestelhorst <stephan.diestelhorst@arm.com>
Mon, 16 Jun 2014 13:59:44 +0000 (14:59 +0100)
These additions allow easier interoperability with and querying from an
additional controller which will be in a separate patch.  Also adding warnings
for changing the enabled state of the handler across checkpoint / resume and
deviating from the state in the configuration.

Contributed-by: Akash Bagdia <akash.bagdia@arm.com>
src/sim/clock_domain.cc
src/sim/clock_domain.hh
src/sim/dvfs_handler.cc
src/sim/dvfs_handler.hh
src/sim/voltage_domain.cc
src/sim/voltage_domain.hh

index 746ef12fd554c4ba52af40e30db2b37653bd6ff8..8f45bba0930138397a24c0b7665c56c39f16dae0 100644 (file)
@@ -136,6 +136,11 @@ SrcClockDomain::perfLevel(PerfLevel perf_level)
 {
     assert(validPerfLevel(perf_level));
 
+    if (perf_level == _perfLevel) {
+        // Silently ignore identical overwrites
+        return;
+    }
+
     DPRINTF(ClockDomain, "DVFS: Switching performance level of domain %s "\
             "(id: %d) from  %d to %d\n", name(), domainID(), _perfLevel,
             perf_level);
@@ -162,6 +167,13 @@ SrcClockDomain::unserialize(Checkpoint *cp, const std::string &section)
 {
     ClockDomain::unserialize(cp, section);
     UNSERIALIZE_SCALAR(_perfLevel);
+}
+
+void
+SrcClockDomain::startup()
+{
+    // Perform proper clock update when all related components have been
+    // created (i.e. after unserialization / object creation)
     perfLevel(_perfLevel);
 }
 
index 946e5bd27c5734b0db66235a75a8651c7fff04be..edf2340ad013df431866197d49b96fbe297ffca9 100644 (file)
@@ -237,6 +237,7 @@ class SrcClockDomain : public ClockDomain
         return freqOpPoints[perf_level];
     }
 
+    void startup();
     void serialize(std::ostream &os);
     void unserialize(Checkpoint *cp, const std::string &section);
 
index bb60b18504da21db02087787e02f6093fc838800..f4fe760a2d7944c0c21b9eee1d11632ac47f1070 100644 (file)
@@ -81,12 +81,26 @@ DVFSHandler::DVFSHandler(const Params *p)
         // Create a dedicated event slot per known domain ID
         UpdateEvent *event = &updatePerfLevelEvents[domain_id];
         event->domainIDToSet = d->domainID();
+
+        // Add domain ID to the list of domains
+        domainIDList.push_back(d->domainID());
     }
     UpdateEvent::dvfsHandler = this;
 }
 
 DVFSHandler *DVFSHandler::UpdateEvent::dvfsHandler;
 
+DVFSHandler::DomainID
+DVFSHandler::domainID(uint32_t index) const
+{
+    fatal_if(index >= numDomains(), "DVFS: Requested index out of "\
+             "bound, max value %d\n", (domainIDList.size() - 1));
+
+    assert(domains.find(domainIDList[index]) != domains.end());
+
+    return domainIDList[index];
+}
+
 bool
 DVFSHandler::validDomainID(DomainID domain_id) const
 {
@@ -186,8 +200,15 @@ DVFSHandler::serialize(std::ostream &os)
 void
 DVFSHandler::unserialize(Checkpoint *cp, const std::string &section)
 {
+    bool temp = enableHandler;
+
     UNSERIALIZE_SCALAR(enableHandler);
 
+    if(temp != enableHandler) {
+        warn("DVFS: Forcing enable handler status to unserialized value of %d",
+             enableHandler);
+    }
+
     // Reconstruct the map of domain IDs and their scheduled events
     std::vector<DomainID> domain_ids;
     std::vector<PerfLevel> perf_levels;
index c8d9621335aa0c790fd64a1b72b04a9fa8d4aa3b..3ff08115a75cf1af154505315186672366734501 100644 (file)
 
 #include <vector>
 
+#include "debug/DVFS.hh"
 #include "params/ClockDomain.hh"
 #include "params/DVFSHandler.hh"
 #include "params/VoltageDomain.hh"
 #include "sim/clock_domain.hh"
 #include "sim/eventq.hh"
 #include "sim/sim_object.hh"
-
+#include "sim/voltage_domain.hh"
 
 /**
  * DVFS Handler class, maintains a list of all the domains it can handle.
@@ -79,6 +80,18 @@ class DVFSHandler : public SimObject
     typedef SrcClockDomain::DomainID DomainID;
     typedef SrcClockDomain::PerfLevel PerfLevel;
 
+    /**
+     * Get the number of domains assigned to this DVFS handler.
+     * @return Number of domains
+     */
+    uint32_t numDomains() const { return domainIDList.size(); }
+
+    /**
+     * Get the n-th domain ID, from the domains managed by this handler.
+     * @return Domain ID
+     */
+    DomainID domainID(uint32_t index) const;
+
     /**
      * Check whether a domain ID is known to the handler or not.
      * @param domain_id Domain ID to check
@@ -127,6 +140,19 @@ class DVFSHandler : public SimObject
         return findDomain(domain_id)->clkPeriodAtPerfLevel(perf_level);
     }
 
+    /**
+     * Read the voltage of the specified domain at the specified
+     * performance level.
+     * @param domain_id Domain ID to query
+     * @param perf_level Performance level of interest
+     * @return Voltage for the requested performance level of the respective
+     * domain
+     */
+    double voltageAtPerfLevel(DomainID domain_id, PerfLevel perf_level) const
+    {
+        return findDomain(domain_id)->voltageDomain()->voltage(perf_level);
+    }
+
     /**
      * Get the total number of available performance levels.
      *
@@ -153,6 +179,11 @@ class DVFSHandler : public SimObject
     typedef std::map<DomainID, SrcClockDomain*> Domains;
     Domains domains;
 
+    /**
+      * List of IDs avaiable in the domain list
+      */
+    std::vector<DomainID> domainIDList;
+
     /**
       * Clock domain of the system the handler is instantiated.
       */
index b5673feda249d920347d7fd5c2777fe6d06b1ddd..2b16d04b9c5918f2c7565665cca83d6c34b838a8 100644 (file)
@@ -54,9 +54,9 @@ VoltageDomain::VoltageDomain(const Params *p)
 
     // Voltages must be sorted in descending order.
     fatal_if(!std::is_sorted(voltageOpPoints.begin(), voltageOpPoints.end(),
-             std::greater_equal<Voltages::value_type>()), "DVFS: Voltage "\
-             "operation points not in descending order for voltage domain "\
-             "%s\n", name());
+             std::greater<Voltages::value_type>()), "DVFS: Voltage operation "\
+             "points not in descending order for voltage domain %s\n",
+             name());
 }
 
 void
@@ -66,6 +66,11 @@ VoltageDomain::perfLevel(PerfLevel perf_level)
                   "DVFS: Requested voltage ID %d is outside the known "\
                   "range for domain %s.\n", perf_level, name());
 
+    if (perf_level == _perfLevel) {
+        // Silently ignore identical overwrites
+        return;
+    }
+
     _perfLevel = perf_level;
 
     DPRINTF(VoltageDomain, "Setting voltage to %.3fV idx: %d for domain %s\n",
index 3904c80c9907c7c17be5dccf7d98152158aa871e..9ffbe7bbc787e8c82c4a7c6975fa2fbfe55b10ad 100644 (file)
@@ -60,6 +60,8 @@ class VoltageDomain : public SimObject
     typedef VoltageDomainParams Params;
     VoltageDomain(const Params *p);
 
+    typedef SrcClockDomain::PerfLevel PerfLevel;
+
     /**
      * Get the current voltage.
      *
@@ -67,9 +69,18 @@ class VoltageDomain : public SimObject
      */
     double voltage() const { return voltageOpPoints[_perfLevel]; }
 
-    uint32_t numVoltages() const { return (uint32_t)voltageOpPoints.size(); }
+    /**
+     * Get the voltage at specified performance level.
+     *
+     * @param perf_level Performance level for which the voltage is requested
+     * @return Voltage of the domain at specified performance level
+     */
+    double voltage(PerfLevel perf_level) const
+    {
+        return voltageOpPoints[perf_level];
+    }
 
-    typedef SrcClockDomain::PerfLevel PerfLevel;
+    uint32_t numVoltages() const { return (uint32_t)voltageOpPoints.size(); }
 
     /**
      * Set the voltage point of the domain.