pwr: Adds logic to enter power gating for the cpu model
authorAnouk Van Laer <anouk.vanlaer@arm.com>
Fri, 17 Mar 2017 12:02:00 +0000 (12:02 +0000)
committerAndreas Sandberg <andreas.sandberg@arm.com>
Mon, 20 Nov 2017 11:03:03 +0000 (11:03 +0000)
If the CPU has been clock gated for a sufficient amount of time
(configurable via pwrGatingLatency), the CPU will go into the OFF
power state.  This does not model hardware, just behaviour.

Change-Id: Ib3681d1ffa6ad25eba60f47b4020325f63472d43
Reviewed-by: Andreas Sandberg <andreas.sandberg@arm.com>
Reviewed-on: https://gem5-review.googlesource.com/3969
Reviewed-by: Jason Lowe-Power <jason@lowepower.com>
Maintainer: Andreas Sandberg <andreas.sandberg@arm.com>

src/cpu/BaseCPU.py
src/cpu/base.cc
src/cpu/base.hh
src/cpu/minor/cpu.cc
src/cpu/o3/cpu.cc
src/cpu/simple/atomic.cc
src/cpu/simple/timing.cc

index fcae74207532918e306c3d33d009cbd7ed85c923..0e131ae0ad5fa8f834d0f0823f7460fa74d54efe 100644 (file)
@@ -1,4 +1,4 @@
-# Copyright (c) 2012-2013, 2015 ARM Limited
+# Copyright (c) 2012-2013, 2015-2017 ARM Limited
 # All rights reserved.
 #
 # The license below extends only to copyright in the software and shall
@@ -135,6 +135,8 @@ class BaseCPU(MemObject):
     cpu_id = Param.Int(-1, "CPU identifier")
     socket_id = Param.Unsigned(0, "Physical Socket identifier")
     numThreads = Param.Unsigned(1, "number of HW thread contexts")
+    pwr_gating_latency = Param.Cycles(300,
+        "Latency to enter power gating state when all contexts are suspended")
 
     function_trace = Param.Bool(False, "Enable function trace")
     function_trace_start = Param.Tick(0, "Tick to start function trace")
index 6f76b8c6f0e78522388b020a11947c8ec5d0a6a3..78cf4196cfe51bb640f43ef19acc3866c0b4ae85 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2011-2012,2016 ARM Limited
+ * Copyright (c) 2011-2012,2016-2017 ARM Limited
  * All rights reserved
  *
  * The license below extends only to copyright in the software and shall
@@ -136,7 +136,9 @@ BaseCPU::BaseCPU(Params *p, bool is_checker)
       functionTraceStream(nullptr), currentFunctionStart(0),
       currentFunctionEnd(0), functionEntryTick(0),
       addressMonitor(p->numThreads),
-      syscallRetryLatency(p->syscallRetryLatency)
+      syscallRetryLatency(p->syscallRetryLatency),
+      pwrGatingLatency(p->pwr_gating_latency),
+      enterPwrGatingEvent([this]{ enterPwrGating(); }, name())
 {
     // if Python did not provide a valid ID, do it here
     if (_cpuId == -1 ) {
@@ -361,6 +363,9 @@ BaseCPU::startup()
         new CPUProgressEvent(this, params()->progress_interval);
     }
 
+    if (_switchedOut)
+        ClockedObject::pwrState(Enums::PwrState::OFF);
+
     // Assumption CPU start to operate instantaneously without any latency
     if (ClockedObject::pwrState() == Enums::PwrState::UNDEFINED)
         ClockedObject::pwrState(Enums::PwrState::ON);
@@ -472,6 +477,29 @@ BaseCPU::registerThreadContexts()
     }
 }
 
+void
+BaseCPU::deschedulePowerGatingEvent()
+{
+    if (enterPwrGatingEvent.scheduled()){
+        deschedule(enterPwrGatingEvent);
+    }
+}
+
+void
+BaseCPU::schedulePowerGatingEvent()
+{
+    for (auto tc : threadContexts) {
+        if (tc->status() == ThreadContext::Active)
+            return;
+    }
+
+    if (ClockedObject::pwrState() == Enums::PwrState::CLK_GATED) {
+        assert(!enterPwrGatingEvent.scheduled());
+        // Schedule a power gating event when clock gated for the specified
+        // amount of time
+        schedule(enterPwrGatingEvent, clockEdge(pwrGatingLatency));
+    }
+}
 
 int
 BaseCPU::findContext(ThreadContext *tc)
@@ -487,6 +515,10 @@ BaseCPU::findContext(ThreadContext *tc)
 void
 BaseCPU::activateContext(ThreadID thread_num)
 {
+    // Squash enter power gating event while cpu gets activated
+    if (enterPwrGatingEvent.scheduled())
+        deschedule(enterPwrGatingEvent);
+
     // For any active thread running, update CPU power state to active (ON)
     ClockedObject::pwrState(Enums::PwrState::ON);
 }
@@ -503,6 +535,15 @@ BaseCPU::suspendContext(ThreadID thread_num)
 
     // All CPU threads suspended, enter lower power state for the CPU
     ClockedObject::pwrState(Enums::PwrState::CLK_GATED);
+
+    //Schedule power gating event when clock gated for a configurable cycles
+    schedule(enterPwrGatingEvent, clockEdge(pwrGatingLatency));
+}
+
+void
+BaseCPU::enterPwrGating(void)
+{
+    ClockedObject::pwrState(Enums::PwrState::OFF);
 }
 
 void
@@ -516,6 +557,9 @@ BaseCPU::switchOut()
     // Flush all TLBs in the CPU to avoid having stale translations if
     // it gets switched in later.
     flushTLBs();
+
+    // Go to the power gating state
+    ClockedObject::pwrState(Enums::PwrState::OFF);
 }
 
 void
@@ -527,6 +571,8 @@ BaseCPU::takeOverFrom(BaseCPU *oldCPU)
     assert(oldCPU != this);
     _pid = oldCPU->getPid();
     _taskId = oldCPU->taskId();
+    // Take over the power state of the switchedOut CPU
+    ClockedObject::pwrState(oldCPU->pwrState());
     _switchedOut = false;
 
     ThreadID size = threadContexts.size();
index 79a4bf1d65bdd34cfcc3467c358254641c4332a7..7039fcfbc5375ea038a6fa30661a0a87c617ee07 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2011-2013 ARM Limited
+ * Copyright (c) 2011-2013, 2017 ARM Limited
  * All rights reserved
  *
  * The license below extends only to copyright in the software and shall
@@ -307,6 +307,11 @@ class BaseCPU : public MemObject
 
     void registerThreadContexts();
 
+    // Functions to deschedule and reschedule the events to enter the
+    // power gating sleep before and after checkpoiting respectively.
+    void deschedulePowerGatingEvent();
+    void schedulePowerGatingEvent();
+
     /**
      * Prepare for another CPU to take over execution.
      *
@@ -583,6 +588,11 @@ class BaseCPU : public MemObject
     bool waitForRemoteGDB() const;
 
     Cycles syscallRetryLatency;
+  // Enables CPU to enter power gating on a configurable cycle count
+  protected:
+    const Cycles pwrGatingLatency;
+    void enterPwrGating();
+    EventFunctionWrapper enterPwrGatingEvent;
 };
 
 #endif // THE_ISA == NULL_ISA
index ae4fda6f69f4e47298ab1652280eb85760f3a009..68c07675f46fe4f07b3cb13ee919af98ad972a5f 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2012-2014 ARM Limited
+ * Copyright (c) 2012-2014, 2017 ARM Limited
  * All rights reserved
  *
  * The license below extends only to copyright in the software and shall
@@ -195,6 +195,9 @@ MinorCPU::startup()
 DrainState
 MinorCPU::drain()
 {
+    // Deschedule any power gating event (if any)
+    deschedulePowerGatingEvent();
+
     if (switchedOut()) {
         DPRINTF(Drain, "Minor CPU switched out, draining not needed.\n");
         return DrainState::Drained;
@@ -240,10 +243,14 @@ MinorCPU::drainResume()
             "'timing' mode.\n");
     }
 
-    for (ThreadID tid = 0; tid < numThreads; tid++)
+    for (ThreadID tid = 0; tid < numThreads; tid++){
         wakeup(tid);
+    }
 
     pipeline->drainResume();
+
+    // Reschedule any power gating event (if any)
+    schedulePowerGatingEvent();
 }
 
 void
index 0695711f174ae3e99a047faa48308610d11f75f5..091c3a6ad0387be5b89b6c741387b3d5f23c3639 100644 (file)
@@ -1031,6 +1031,9 @@ template <class Impl>
 DrainState
 FullO3CPU<Impl>::drain()
 {
+    // Deschedule any power gating event (if any)
+    deschedulePowerGatingEvent();
+
     // If the CPU isn't doing anything, then return immediately.
     if (switchedOut())
         return DrainState::Drained;
@@ -1186,6 +1189,9 @@ FullO3CPU<Impl>::drainResume()
     assert(!tickEvent.scheduled());
     if (_status == Running)
         schedule(tickEvent, nextCycle());
+
+    // Reschedule any power gating event (if any)
+    schedulePowerGatingEvent();
 }
 
 template <class Impl>
index c47686abc5f45517909e403643c28c2a68680631..9039e6137b1d3164e7f3b524c13a17d1fe4483e3 100644 (file)
@@ -1,6 +1,6 @@
 /*
  * Copyright 2014 Google, Inc.
- * Copyright (c) 2012-2013,2015 ARM Limited
+ * Copyright (c) 2012-2013,2015,2017 ARM Limited
  * All rights reserved.
  *
  * The license below extends only to copyright in the software and shall
@@ -101,6 +101,9 @@ AtomicSimpleCPU::~AtomicSimpleCPU()
 DrainState
 AtomicSimpleCPU::drain()
 {
+    // Deschedule any power gating event (if any)
+    deschedulePowerGatingEvent();
+
     if (switchedOut())
         return DrainState::Drained;
 
@@ -163,6 +166,9 @@ AtomicSimpleCPU::drainResume()
             threadInfo[tid]->notIdleFraction = 0;
         }
     }
+
+    // Reschedule any power gating event (if any)
+    schedulePowerGatingEvent();
 }
 
 bool
index d2cb6ee210132df2b05a7346b99fd729cfb7ca02..f57354d56d73812b9636c1f647e5c62acb119a72 100644 (file)
@@ -1,6 +1,6 @@
 /*
  * Copyright 2014 Google, Inc.
- * Copyright (c) 2010-2013,2015 ARM Limited
+ * Copyright (c) 2010-2013,2015,2017 ARM Limited
  * All rights reserved
  *
  * The license below extends only to copyright in the software and shall
@@ -94,6 +94,9 @@ TimingSimpleCPU::~TimingSimpleCPU()
 DrainState
 TimingSimpleCPU::drain()
 {
+    // Deschedule any power gating event (if any)
+    deschedulePowerGatingEvent();
+
     if (switchedOut())
         return DrainState::Drained;
 
@@ -146,6 +149,9 @@ TimingSimpleCPU::drainResume()
         }
     }
 
+    // Reschedule any power gating event (if any)
+    schedulePowerGatingEvent();
+
     system->totalNumInsts = 0;
 }