From c52190a695dc1928713e5bbda85cd17867c7e465 Mon Sep 17 00:00:00 2001 From: Andreas Sandberg Date: Sun, 9 Feb 2014 20:49:28 +0100 Subject: [PATCH] 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. --- src/cpu/simple/BaseSimpleCPU.py | 3 ++ src/cpu/simple/base.cc | 57 +++++++++++++++++++++++++++++++-- src/cpu/simple/base.hh | 16 ++++++++- 3 files changed, 73 insertions(+), 3 deletions(-) diff --git a/src/cpu/simple/BaseSimpleCPU.py b/src/cpu/simple/BaseSimpleCPU.py index a4ae7e34b..243a09269 100644 --- a/src/cpu/simple/BaseSimpleCPU.py +++ b/src/cpu/simple/BaseSimpleCPU.py @@ -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") diff --git a/src/cpu/simple/base.cc b/src/cpu/simple/base.cc index 078f490e8..3adf6d27f 100644 --- a/src/cpu/simple/base.cc +++ b/src/cpu/simple/base.cc @@ -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 diff --git a/src/cpu/simple/base.hh b/src/cpu/simple/base.hh index 8134465af..ad672da6c 100644 --- a/src/cpu/simple/base.hh +++ b/src/cpu/simple/base.hh @@ -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__ -- 2.30.2