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:
@@ -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__
|
||||
|
||||
Reference in New Issue
Block a user