cpu: simple: Add support for using branch predictors

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.
This commit is contained in:
Andreas Sandberg 2014-02-09 20:49:28 +01:00
parent eb73a14fe2
commit c52190a695
3 changed files with 73 additions and 3 deletions

View 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")

View 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

View 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__