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:
parent
eb73a14fe2
commit
c52190a695
3 changed files with 73 additions and 3 deletions
|
@ -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")
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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 §ion,
|
||||
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__
|
||||
|
|
Loading…
Reference in a new issue