inorder: update branch predictor
- use InOrderBPred instead of Resource for DPRINTFs - account for DELAY SLOT in updating RAS and in squashing - don't let squashed instructions update the predictor - the BTB needs to use the ASID not the TID to work for multithreaded programs - add stats for BTB hits
This commit is contained in:
@@ -103,6 +103,12 @@ BPredUnit::regStats()
|
||||
.desc("Number of BTB hits")
|
||||
;
|
||||
|
||||
BTBHitPct
|
||||
.name(name() + ".BTBHitPct")
|
||||
.desc("BTB Hit Percentage")
|
||||
.precision(6);
|
||||
BTBHitPct = (BTBHits / BTBLookups) * 100;
|
||||
|
||||
usedRAS
|
||||
.name(name() + ".usedRAS")
|
||||
.desc("Number of times the RAS was used to get a target.")
|
||||
@@ -150,30 +156,35 @@ BPredUnit::predict(DynInstPtr &inst, Addr &PC, ThreadID tid)
|
||||
|
||||
using TheISA::MachInst;
|
||||
|
||||
int asid = inst->asid;
|
||||
bool pred_taken = false;
|
||||
Addr target;
|
||||
|
||||
++lookups;
|
||||
DPRINTF(InOrderBPred, "[tid:%i] [sn:%i] %s ... PC%#x doing branch prediction\n",
|
||||
tid, inst->seqNum, inst->staticInst->disassemble(inst->PC),
|
||||
inst->readPC());
|
||||
|
||||
|
||||
void *bp_history = NULL;
|
||||
|
||||
if (inst->isUncondCtrl()) {
|
||||
DPRINTF(Resource, "BranchPred: [tid:%i] Unconditional control.\n", tid);
|
||||
DPRINTF(InOrderBPred, "BranchPred: [tid:%i] Unconditional control.\n", tid);
|
||||
pred_taken = true;
|
||||
// Tell the BP there was an unconditional branch.
|
||||
BPUncond(bp_history);
|
||||
|
||||
if (inst->isReturn() && RAS[tid].empty()) {
|
||||
DPRINTF(Resource, "BranchPred: [tid:%i] RAS is empty, predicting "
|
||||
"false.\n", tid);
|
||||
pred_taken = false;
|
||||
}
|
||||
if (inst->isReturn() && RAS[tid].empty()) {
|
||||
DPRINTF(InOrderBPred, "BranchPred: [tid:%i] RAS is empty, predicting "
|
||||
"false.\n", tid);
|
||||
pred_taken = false;
|
||||
}
|
||||
} else {
|
||||
++condPredicted;
|
||||
|
||||
pred_taken = BPLookup(PC, bp_history);
|
||||
|
||||
DPRINTF(Resource, "BranchPred: [tid:%i]: Branch predictor predicted %i "
|
||||
DPRINTF(InOrderBPred, "BranchPred: [tid:%i]: Branch predictor predicted %i "
|
||||
"for PC %#x\n",
|
||||
tid, pred_taken, inst->readPC());
|
||||
}
|
||||
@@ -199,22 +210,28 @@ BPredUnit::predict(DynInstPtr &inst, Addr &PC, ThreadID tid)
|
||||
|
||||
RAS[tid].pop();
|
||||
|
||||
DPRINTF(Resource, "BranchPred: [tid:%i]: Instruction %#x is a return, "
|
||||
DPRINTF(InOrderBPred, "BranchPred: [tid:%i]: Instruction %#x is a return, "
|
||||
"RAS predicted target: %#x, RAS index: %i.\n",
|
||||
tid, inst->readPC(), target, predict_record.RASIndex);
|
||||
} else {
|
||||
++BTBLookups;
|
||||
|
||||
if (inst->isCall()) {
|
||||
RAS[tid].push(PC + sizeof(MachInst));
|
||||
#if ISA_HAS_DELAY_SLOT
|
||||
Addr ras_pc = PC + (2 * sizeof(MachInst)); // Next Next PC
|
||||
#else
|
||||
Addr ras_pc = PC + sizeof(MachInst); // Next PC
|
||||
#endif
|
||||
|
||||
RAS[tid].push(ras_pc);
|
||||
|
||||
// Record that it was a call so that the top RAS entry can
|
||||
// be popped off if the speculation is incorrect.
|
||||
predict_record.wasCall = true;
|
||||
|
||||
DPRINTF(Resource, "BranchPred: [tid:%i] Instruction %#x was a call"
|
||||
", adding %#x to the RAS.\n",
|
||||
tid, inst->readPC(), PC + sizeof(MachInst));
|
||||
DPRINTF(InOrderBPred, "BranchPred: [tid:%i]: Instruction %#x was a call"
|
||||
", adding %#x to the RAS index: %i.\n",
|
||||
tid, inst->readPC(), ras_pc, RAS[tid].topIdx());
|
||||
}
|
||||
|
||||
if (inst->isCall() &&
|
||||
@@ -222,20 +239,20 @@ BPredUnit::predict(DynInstPtr &inst, Addr &PC, ThreadID tid)
|
||||
inst->isDirectCtrl()) {
|
||||
target = inst->branchTarget();
|
||||
|
||||
DPRINTF(Fetch, "BranchPred: [tid:%i]: Setting %#x predicted"
|
||||
DPRINTF(InOrderBPred, "BranchPred: [tid:%i]: Setting %#x predicted"
|
||||
" target to %#x.\n",
|
||||
tid, inst->readPC(), target);
|
||||
} else if (BTB.valid(PC, tid)) {
|
||||
} else if (BTB.valid(PC, asid)) {
|
||||
++BTBHits;
|
||||
|
||||
// If it's not a return, use the BTB to get the target addr.
|
||||
target = BTB.lookup(PC, tid);
|
||||
target = BTB.lookup(PC, asid);
|
||||
|
||||
DPRINTF(Resource, "BranchPred: [tid:%i]: Instruction %#x predicted"
|
||||
DPRINTF(InOrderBPred, "BranchPred: [tid:%i]: [asid:%i] Instruction %#x predicted"
|
||||
" target is %#x.\n",
|
||||
tid, inst->readPC(), target);
|
||||
tid, asid, inst->readPC(), target);
|
||||
} else {
|
||||
DPRINTF(Resource, "BranchPred: [tid:%i]: BTB doesn't have a "
|
||||
DPRINTF(InOrderBPred, "BranchPred: [tid:%i]: BTB doesn't have a "
|
||||
"valid entry.\n",tid);
|
||||
pred_taken = false;
|
||||
}
|
||||
@@ -258,7 +275,8 @@ BPredUnit::predict(DynInstPtr &inst, Addr &PC, ThreadID tid)
|
||||
|
||||
predHist[tid].push_front(predict_record);
|
||||
|
||||
DPRINTF(Resource, "[tid:%i] predHist.size(): %i\n", tid, predHist[tid].size());
|
||||
DPRINTF(InOrderBPred, "[tid:%i] [sn:%i] pushed onto front of predHist ...predHist.size(): %i\n",
|
||||
tid, inst->seqNum, predHist[tid].size());
|
||||
|
||||
inst->setBranchPred(pred_taken);
|
||||
|
||||
@@ -292,7 +310,7 @@ BPredUnit::squash(const InstSeqNum &squashed_sn, ThreadID tid)
|
||||
while (!pred_hist.empty() &&
|
||||
pred_hist.front().seqNum > squashed_sn) {
|
||||
if (pred_hist.front().usedRAS) {
|
||||
DPRINTF(Resource, "BranchPred: [tid:%i]: Restoring top of RAS to: %i,"
|
||||
DPRINTF(InOrderBPred, "BranchPred: [tid:%i]: Restoring top of RAS to: %i,"
|
||||
" target: %#x.\n",
|
||||
tid,
|
||||
pred_hist.front().RASIndex,
|
||||
@@ -302,7 +320,7 @@ BPredUnit::squash(const InstSeqNum &squashed_sn, ThreadID tid)
|
||||
pred_hist.front().RASTarget);
|
||||
|
||||
} else if (pred_hist.front().wasCall) {
|
||||
DPRINTF(Resource, "BranchPred: [tid:%i]: Removing speculative entry "
|
||||
DPRINTF(InOrderBPred, "BranchPred: [tid:%i]: Removing speculative entry "
|
||||
"added to the RAS.\n",tid);
|
||||
|
||||
RAS[tid].pop();
|
||||
@@ -331,7 +349,7 @@ BPredUnit::squash(const InstSeqNum &squashed_sn,
|
||||
|
||||
++condIncorrect;
|
||||
|
||||
DPRINTF(Resource, "BranchPred: [tid:%i]: Squashing from sequence number %i, "
|
||||
DPRINTF(InOrderBPred, "BranchPred: [tid:%i]: Squashing from sequence number %i, "
|
||||
"setting target to %#x.\n",
|
||||
tid, squashed_sn, corr_target);
|
||||
|
||||
@@ -341,19 +359,38 @@ BPredUnit::squash(const InstSeqNum &squashed_sn,
|
||||
// corresponding to the squash. In that case, don't bother trying to
|
||||
// fix up the entry.
|
||||
if (!pred_hist.empty()) {
|
||||
if(pred_hist.front().seqNum==squashed_sn){
|
||||
HistoryIt hist_it = pred_hist.begin();
|
||||
//HistoryIt hist_it = find(pred_hist.begin(), pred_hist.end(),
|
||||
// squashed_sn);
|
||||
|
||||
assert(pred_hist.front().seqNum == squashed_sn);
|
||||
if (pred_hist.front().usedRAS) {
|
||||
//assert(hist_it != pred_hist.end());
|
||||
if (pred_hist.front().seqNum != squashed_sn) {
|
||||
DPRINTF(InOrderBPred, "Front sn %i != Squash sn %i\n",
|
||||
pred_hist.front().seqNum, squashed_sn);
|
||||
|
||||
assert(pred_hist.front().seqNum == squashed_sn);
|
||||
}
|
||||
|
||||
|
||||
if ((*hist_it).usedRAS) {
|
||||
++RASIncorrect;
|
||||
}
|
||||
|
||||
BPUpdate(pred_hist.front().PC, actually_taken,
|
||||
BPUpdate((*hist_it).PC, actually_taken,
|
||||
pred_hist.front().bpHistory);
|
||||
|
||||
BTB.update(pred_hist.front().PC, corr_target, tid);
|
||||
pred_hist.pop_front();
|
||||
}
|
||||
BTB.update((*hist_it).PC, corr_target, tid);
|
||||
|
||||
DPRINTF(InOrderBPred, "BranchPred: [tid:%i]: Removing history for [sn:%i] "
|
||||
"PC %#x.\n", tid, (*hist_it).seqNum, (*hist_it).PC);
|
||||
|
||||
pred_hist.erase(hist_it);
|
||||
|
||||
DPRINTF(InOrderBPred, "[tid:%i]: predHist.size(): %i\n", tid, predHist[tid].size());
|
||||
|
||||
} else {
|
||||
DPRINTF(InOrderBPred, "BranchPred: [tid:%i]: [sn:%i] pred_hist empty, can't update.\n",
|
||||
tid, squashed_sn);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -219,6 +219,7 @@ class BPredUnit
|
||||
};
|
||||
|
||||
typedef std::list<PredictorHistory> History;
|
||||
typedef History::iterator HistoryIt;
|
||||
|
||||
/**
|
||||
* The per-thread predictor history. This is used to update the predictor
|
||||
@@ -255,6 +256,7 @@ class BPredUnit
|
||||
Stats::Scalar usedRAS;
|
||||
/** Stat for number of times the RAS is incorrect. */
|
||||
Stats::Scalar RASIncorrect;
|
||||
Stats::Formula BTBHitPct;
|
||||
};
|
||||
|
||||
#endif // __CPU_INORDER_BPRED_UNIT_HH__
|
||||
|
||||
@@ -78,42 +78,48 @@ BranchPredictor::execute(int slot_num)
|
||||
{
|
||||
case PredictBranch:
|
||||
{
|
||||
Addr pred_PC = inst->readNextPC();
|
||||
if (inst->seqNum > cpu->squashSeqNum[tid] &&
|
||||
curTick == cpu->lastSquashCycle[tid]) {
|
||||
DPRINTF(InOrderStage, "[tid:%u]: [sn:%i]: squashed, skipping prediction \n",
|
||||
tid, inst->seqNum);
|
||||
} else {
|
||||
Addr pred_PC = inst->readNextPC();
|
||||
|
||||
if (inst->isControl()) {
|
||||
// If not, the pred_PC be updated to pc+8
|
||||
// If predicted, the pred_PC will be updated to new target value
|
||||
bool predict_taken = branchPred.predict(inst, pred_PC, tid);
|
||||
if (inst->isControl()) {
|
||||
// If not, the pred_PC be updated to pc+8
|
||||
// If predicted, the pred_PC will be updated to new target value
|
||||
bool predict_taken = branchPred.predict(inst, pred_PC, tid);
|
||||
|
||||
if (predict_taken) {
|
||||
DPRINTF(InOrderBPred, "[tid:%i]: [sn:%i]: Branch predicted true.\n",
|
||||
tid, seq_num);
|
||||
if (predict_taken) {
|
||||
DPRINTF(InOrderBPred, "[tid:%i]: [sn:%i]: Branch predicted true.\n",
|
||||
tid, seq_num);
|
||||
|
||||
inst->setPredTarg(pred_PC);
|
||||
|
||||
predictedTaken++;
|
||||
} else {
|
||||
DPRINTF(InOrderBPred, "[tid:%i]: [sn:%i]: Branch predicted false.\n",
|
||||
tid, seq_num);
|
||||
|
||||
if (inst->isCondDelaySlot())
|
||||
{
|
||||
inst->setPredTarg(inst->readPC() + (2 * instSize));
|
||||
} else {
|
||||
inst->setPredTarg(pred_PC);
|
||||
|
||||
predictedTaken++;
|
||||
} else {
|
||||
DPRINTF(InOrderBPred, "[tid:%i]: [sn:%i]: Branch predicted false.\n",
|
||||
tid, seq_num);
|
||||
|
||||
if (inst->isCondDelaySlot())
|
||||
{
|
||||
inst->setPredTarg(inst->readPC() + (2 * instSize));
|
||||
} else {
|
||||
inst->setPredTarg(pred_PC);
|
||||
}
|
||||
|
||||
predictedNotTaken++;
|
||||
}
|
||||
|
||||
predictedNotTaken++;
|
||||
}
|
||||
inst->setBranchPred(predict_taken);
|
||||
|
||||
inst->setBranchPred(predict_taken);
|
||||
|
||||
DPRINTF(InOrderBPred, "[tid:%i]: [sn:%i]: Predicted PC is %08p.\n",
|
||||
DPRINTF(InOrderBPred, "[tid:%i]: [sn:%i]: Predicted PC is %08p.\n",
|
||||
tid, seq_num, pred_PC);
|
||||
|
||||
} else {
|
||||
DPRINTF(InOrderBPred, "[tid:%i]: Ignoring [sn:%i] because this isn't "
|
||||
"a control instruction.\n", tid, seq_num);
|
||||
} else {
|
||||
//DPRINTF(InOrderBPred, "[tid:%i]: Ignoring [sn:%i] because this isn't "
|
||||
// "a control instruction.\n", tid, seq_num);
|
||||
}
|
||||
}
|
||||
|
||||
bpred_req->done();
|
||||
@@ -122,11 +128,17 @@ BranchPredictor::execute(int slot_num)
|
||||
|
||||
case UpdatePredictor:
|
||||
{
|
||||
DPRINTF(InOrderBPred, "[tid:%i]: [sn:%i]: Updating Branch Predictor.\n",
|
||||
tid, seq_num);
|
||||
if (inst->seqNum > cpu->squashSeqNum[tid] &&
|
||||
curTick == cpu->lastSquashCycle[tid]) {
|
||||
DPRINTF(InOrderStage, "[tid:%u]: [sn:%i]: squashed, skipping branch predictor update \n",
|
||||
tid, inst->seqNum);
|
||||
} else {
|
||||
DPRINTF(InOrderBPred, "[tid:%i]: [sn:%i]: Updating Branch Predictor.\n",
|
||||
tid, seq_num);
|
||||
|
||||
|
||||
branchPred.update(seq_num, tid);
|
||||
branchPred.update(seq_num, tid);
|
||||
}
|
||||
|
||||
bpred_req->done();
|
||||
}
|
||||
@@ -141,10 +153,21 @@ void
|
||||
BranchPredictor::squash(DynInstPtr inst, int squash_stage,
|
||||
InstSeqNum squash_seq_num, ThreadID tid)
|
||||
{
|
||||
DPRINTF(InOrderBPred, "Squashing...\n");
|
||||
Addr corr_targ=inst->readPredPC();
|
||||
bool taken=inst->predTaken();
|
||||
branchPred.squash(squash_seq_num,corr_targ,taken,tid);
|
||||
DPRINTF(InOrderBPred, "[tid:%i][sn:%i] Squashing...\n", tid, inst->seqNum);
|
||||
|
||||
#if ISA_HAS_DELAY_SLOT
|
||||
// We need to squash the actual branch , NOT the delay slot
|
||||
// in the branch predictor
|
||||
squash_seq_num = squash_seq_num - 1;
|
||||
#endif
|
||||
|
||||
if(squash_stage>=ThePipeline::BackEndStartStage) {
|
||||
Addr corr_targ=inst->readPredPC();
|
||||
bool taken=inst->predTaken();
|
||||
branchPred.squash(squash_seq_num,corr_targ,taken,tid);
|
||||
} else {
|
||||
branchPred.squash(squash_seq_num, tid);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
|
||||
@@ -170,8 +170,14 @@ ExecutionUnit::execute(int slot_num)
|
||||
|
||||
if (inst->predTaken()) {
|
||||
predictedTakenIncorrect++;
|
||||
DPRINTF(InOrderExecute, "[tid:%i] [sn:%i] %s ... PC%#x ... Mispredicts! (Taken)\n",
|
||||
tid, inst->seqNum, inst->staticInst->disassemble(inst->PC),
|
||||
inst->readPC());
|
||||
} else {
|
||||
predictedNotTakenIncorrect++;
|
||||
DPRINTF(InOrderExecute, "[tid:%i] [sn:%i] %s ... PC%#x ... Mispredicts! (Not Taken)\n",
|
||||
tid, inst->seqNum, inst->staticInst->disassemble(inst->PC),
|
||||
inst->readPC());
|
||||
}
|
||||
} else {
|
||||
DPRINTF(InOrderExecute, "[tid:%i]: [sn:%i]: Prediction Correct.\n",
|
||||
|
||||
Reference in New Issue
Block a user