cpu: simple: Add support for using branch predictors
authorAndreas Sandberg <andreas@sandberg.pp.se>
Sun, 9 Feb 2014 19:49:28 +0000 (20:49 +0100)
committerAndreas Sandberg <andreas@sandberg.pp.se>
Sun, 9 Feb 2014 19:49:28 +0000 (20:49 +0100)
This changesets adds branch predictor support to the
BaseSimpleCPU. The simple CPUs normally don't need a branch predictor,
however, there are at least two cases where it can be desirable:

  1) A simple CPU can be used to warm the branch predictor of an O3
     CPU before switching to the slower O3 model.

  2) The simple CPU can be used as a quick way of evaluating/debugging
     new branch predictors since it exposes branch predictor
     statistics.

Limitations:
  * Since the simple CPU doesn't speculate, only one instruction will
    be active in the branch predictor at a time (i.e., the branch
    predictor will never see speculative branches).

  * The outcome of a branch prediction does not affect the performance
    of the simple CPU.

src/cpu/simple/BaseSimpleCPU.py
src/cpu/simple/base.cc
src/cpu/simple/base.hh

index a4ae7e34bc72f70a10fffffb568ee275c1a7cab7..243a092696289f1e4b5e7375b79b131126d520b6 100644 (file)
@@ -30,6 +30,7 @@ from m5.defines import buildEnv
 from m5.params import *
 from BaseCPU import BaseCPU
 from DummyChecker import DummyChecker
+from BranchPredictor import BranchPredictor
 
 class BaseSimpleCPU(BaseCPU):
     type = 'BaseSimpleCPU'
@@ -46,3 +47,5 @@ class BaseSimpleCPU(BaseCPU):
         else:
             print "ERROR: Checker only supported under ARM ISA!"
             exit(1)
+
+    branchPred = Param.BranchPredictor(NULL, "Branch Predictor")
index 078f490e8d54fb31d70ac264fd7a14d0238f94a3..3adf6d27f47e33a5a14d32e6f4982d63ee6a672a 100644 (file)
@@ -60,6 +60,7 @@
 #include "cpu/checker/cpu.hh"
 #include "cpu/checker/thread_context.hh"
 #include "cpu/exetrace.hh"
+#include "cpu/pred/bpred_unit.hh"
 #include "cpu/profile.hh"
 #include "cpu/simple_thread.hh"
 #include "cpu/smt.hh"
@@ -85,7 +86,9 @@ using namespace std;
 using namespace TheISA;
 
 BaseSimpleCPU::BaseSimpleCPU(BaseSimpleCPUParams *p)
-    : BaseCPU(p), traceData(NULL), thread(NULL)
+    : BaseCPU(p),
+      branchPred(p->branchPred),
+      traceData(NULL), thread(NULL)
 {
     if (FullSystem)
         thread = new SimpleThread(this, 0, p->system, p->itb, p->dtb,
@@ -286,6 +289,21 @@ BaseSimpleCPU::regStats()
     idleFraction = constant(1.0) - notIdleFraction;
     numIdleCycles = idleFraction * numCycles;
     numBusyCycles = (notIdleFraction)*numCycles;
+
+    numBranches
+        .name(name() + ".Branches")
+        .desc("Number of branches fetched")
+        .prereq(numBranches);
+
+    numPredictedBranches
+        .name(name() + ".predictedBranches")
+        .desc("Number of branches predicted as taken")
+        .prereq(numPredictedBranches);
+
+    numBranchMispred
+        .name(name() + ".BranchMispred")
+        .desc("Number of branch mispredictions")
+        .prereq(numBranchMispred);
 }
 
 void
@@ -434,6 +452,19 @@ BaseSimpleCPU::preExecute()
                 curStaticInst->getName(), curStaticInst->machInst);
 #endif // TRACING_ON
     }
+
+    if (branchPred && curStaticInst && curStaticInst->isControl()) {
+        // Use a fake sequence number since we only have one
+        // instruction in flight at the same time.
+        const InstSeqNum cur_sn(0);
+        const ThreadID tid(0);
+        pred_pc = thread->pcState();
+        const bool predict_taken(
+            branchPred->predict(curStaticInst, cur_sn, pred_pc, tid));
+
+        if (predict_taken)
+            ++numPredictedBranches;
+    }
 }
 
 void
@@ -464,6 +495,10 @@ BaseSimpleCPU::postExecute()
         CPA::cpa()->swAutoBegin(tc, pc.nextInstAddr());
     }
 
+    if (curStaticInst->isControl()) {
+        ++numBranches;
+    }
+
     /* Power model statistics */
     //integer alu accesses
     if (curStaticInst->isInteger()){
@@ -507,10 +542,11 @@ BaseSimpleCPU::postExecute()
     }
 }
 
-
 void
 BaseSimpleCPU::advancePC(Fault fault)
 {
+    const bool branching(thread->pcState().branching());
+
     //Since we're moving to a new pc, zero out the offset
     fetchOffset = 0;
     if (fault != NoFault) {
@@ -526,6 +562,23 @@ BaseSimpleCPU::advancePC(Fault fault)
             thread->pcState(pcState);
         }
     }
+
+    if (branchPred && curStaticInst && curStaticInst->isControl()) {
+        // Use a fake sequence number since we only have one
+        // instruction in flight at the same time.
+        const InstSeqNum cur_sn(0);
+        const ThreadID tid(0);
+
+        if (pred_pc == thread->pcState()) {
+            // Correctly predicted branch
+            branchPred->update(cur_sn, tid);
+        } else {
+            // Mis-predicted branch
+            branchPred->squash(cur_sn, pcState(),
+                               branching, tid);
+            ++numBranchMispred;
+        }
+    }
 }
 
 void
index 8134465af10ff48903d2631271d8f87aedb22510..ad672da6c4d05ab7bbb59e5422875dbed7797a26 100644 (file)
@@ -77,7 +77,7 @@ namespace Trace {
 }
 
 struct BaseSimpleCPUParams;
-
+class BPredUnit;
 
 class BaseSimpleCPU : public BaseCPU
 {
@@ -87,6 +87,8 @@ class BaseSimpleCPU : public BaseCPU
     typedef TheISA::FloatRegBits FloatRegBits;
     typedef TheISA::CCReg CCReg;
 
+    BPredUnit *branchPred;
+
   protected:
     Trace::InstRecord *traceData;
 
@@ -272,6 +274,15 @@ class BaseSimpleCPU : public BaseCPU
     Stats::Scalar dcacheRetryCycles;
     Counter lastDcacheRetry;
 
+    /// @{
+    /// Total number of branches fetched
+    Stats::Scalar numBranches;
+    /// Number of branches predicted as taken
+    Stats::Scalar numPredictedBranches;
+    /// Number of misprediced branches
+    Stats::Scalar numBranchMispred;
+    /// @}
+
     void serializeThread(std::ostream &os, ThreadID tid);
     void unserializeThread(Checkpoint *cp, const std::string &section,
                            ThreadID tid);
@@ -446,6 +457,9 @@ class BaseSimpleCPU : public BaseCPU
 
     bool misspeculating() { return thread->misspeculating(); }
     ThreadContext *tcBase() { return tc; }
+
+  private:
+    TheISA::PCState pred_pc;
 };
 
 #endif // __CPU_SIMPLE_BASE_HH__