From b06fe9d033bf8a194385114ec7631db6504b4c06 Mon Sep 17 00:00:00 2001 From: zoujr <18870680299@163.com> Date: Sat, 27 Feb 2021 20:54:38 +0800 Subject: [PATCH] perf: Add perf counters for predictors --- src/main/scala/xiangshan/XSCore.scala | 2 +- .../scala/xiangshan/backend/ftq/Ftq.scala | 109 +++++++++++++++--- .../scala/xiangshan/backend/fu/Jump.scala | 1 - src/main/scala/xiangshan/frontend/BPU.scala | 40 +++++++ src/main/scala/xiangshan/frontend/IFU.scala | 58 +++++++++- 5 files changed, 186 insertions(+), 24 deletions(-) diff --git a/src/main/scala/xiangshan/XSCore.scala b/src/main/scala/xiangshan/XSCore.scala index d0e92f201..0413b3d92 100644 --- a/src/main/scala/xiangshan/XSCore.scala +++ b/src/main/scala/xiangshan/XSCore.scala @@ -315,7 +315,7 @@ case class EnviromentParameters ( FPGAPlatform: Boolean = true, EnableDebug: Boolean = false, - EnablePerfDebug: Boolean = true, + EnablePerfDebug: Boolean = false, DualCore: Boolean = false ) diff --git a/src/main/scala/xiangshan/backend/ftq/Ftq.scala b/src/main/scala/xiangshan/backend/ftq/Ftq.scala index 411d115f9..2ce0175a0 100644 --- a/src/main/scala/xiangshan/backend/ftq/Ftq.scala +++ b/src/main/scala/xiangshan/backend/ftq/Ftq.scala @@ -291,27 +291,104 @@ class Ftq extends XSModule with HasCircularQueuePtrHelper { } // Branch Predictor Perf counters + val fires = io.roq_commits.map{case c => c.valid && !c.bits.pd.notCFI} + val predRights = (0 until PredictWidth).map{i => !commitEntry.mispred(i) && !commitEntry.pd(i).notCFI && commitEntry.valids(i)} + val predWrongs = (0 until PredictWidth).map{i => commitEntry.mispred(i) && !commitEntry.pd(i).notCFI && commitEntry.valids(i)} + val isBTypes = (0 until PredictWidth).map{i => commitEntry.pd(i).isBr} + val isJTypes = (0 until PredictWidth).map{i => commitEntry.pd(i).isJal} + val isITypes = (0 until PredictWidth).map{i => commitEntry.pd(i).isJalr} + val isCTypes = (0 until PredictWidth).map{i => commitEntry.pd(i).isCall} + val isRTypes = (0 until PredictWidth).map{i => commitEntry.pd(i).isRet} + + val mbpInstrs = fires + val mbpRights = predRights + val mbpWrongs = predWrongs + val mbpBRights = Cat(predRights) & Cat(isBTypes) + val mbpBWrongs = Cat(predWrongs) & Cat(isBTypes) + val mbpJRights = Cat(predRights) & Cat(isJTypes) + val mbpJWrongs = Cat(predWrongs) & Cat(isJTypes) + val mbpIRights = Cat(predRights) & Cat(isITypes) + val mbpIWrongs = Cat(predWrongs) & Cat(isITypes) + val mbpCRights = Cat(predRights) & Cat(isCTypes) + val mbpCWrongs = Cat(predWrongs) & Cat(isCTypes) + val mbpRRights = Cat(predRights) & Cat(isRTypes) + val mbpRWrongs = Cat(predWrongs) & Cat(isRTypes) + + def predCheck(commit: FtqEntry, predAns: Seq[PredictorAnswer], lastRights: Seq[Bool], isWrong: Bool, checkTarget: Boolean) = { + commit.valids.zip(commit.pd).zip(predAns).zip(commit.takens).zip(lastRights).map { + case ((((valid, pd), ans), taken), lastRight) => + Mux(valid && pd.isBr, + isWrong ^ Mux(ans.hit.asBool, + Mux(ans.taken.asBool, if(checkTarget) {ans.target === commitEntry.target} else {taken}, + !taken), + lastRight), + false.B) + } + } + + def loopCheck(commit: FtqEntry, predAns: Seq[PredictorAnswer], isWrong: Bool) = { + commit.valids.zip(commit.pd).zip(predAns).zip(commit.takens).map { + case (((valid, pd), ans), taken) => + Mux(valid && (pd.isBr) && ans.hit.asBool, + isWrong ^ (!taken), + false.B) + } + } + + def rasCheck(commit: FtqEntry, predAns: Seq[PredictorAnswer], isWrong: Bool) = { + commit.valids.zip(commit.pd).zip(predAns).zip(commit.takens).map { + case (((valid, pd), ans), taken) => + Mux(valid && pd.isRet && taken && ans.hit.asBool, + isWrong ^ (ans.target === commitEntry.target), + false.B) + } + } + + val ubtbRights = predCheck(commitEntry, commitEntry.metas.map(_.ubtbAns), commitEntry.takens.map(!_), false.B, true) + val ubtbWrongs = predCheck(commitEntry, commitEntry.metas.map(_.ubtbAns), commitEntry.takens.map(!_), true.B, true) + // btb and ubtb pred jal and jalr as well + val btbRights = predCheck(commitEntry, commitEntry.metas.map(_.btbAns), ubtbRights, false.B, true) + val btbWrongs = predCheck(commitEntry, commitEntry.metas.map(_.btbAns), ubtbRights, true.B, true) + val tageRights = predCheck(commitEntry, commitEntry.metas.map(_.tageAns), btbRights, false.B, false) + val tageWrongs = predCheck(commitEntry, commitEntry.metas.map(_.tageAns), btbRights, true.B, false) + + val loopRights = loopCheck(commitEntry, commitEntry.metas.map(_.loopAns), false.B) + val loopWrongs = loopCheck(commitEntry, commitEntry.metas.map(_.loopAns), true.B) + + val rasRights = rasCheck(commitEntry, commitEntry.metas.map(_.rasAns), false.B) + val rasWrongs = rasCheck(commitEntry, commitEntry.metas.map(_.rasAns), true.B) + val perfCountsMap = Map( - "BpInstr" -> PopCount(io.roq_commits.map{case c => c.valid && !c.bits.pd.notCFI}), + "BpInstr" -> PopCount(mbpInstrs), "BpBInstr" -> PopCount(io.roq_commits.map{case c => c.valid && c.bits.pd.isBr}), - // "BpRight" -> PopCount((0 until PredictWidth).map{i => !mispredict_vec(headPtr.value)(i) && commit_valids(i)}), - "BpRight" -> PopCount((0 until PredictWidth).map{i => !commitEntry.mispred(i) && !commitEntry.pd(i).notCFI && commitEntry.valids(i)}), - // "BpWrong" -> PopCount((0 until PredictWidth).map{i => mispredict_vec(headPtr.value)(i) && commit_valids(i)}), - "BpWrong" -> PopCount((0 until PredictWidth).map{i => commitEntry.mispred(i) && !commitEntry.pd(i).notCFI && commitEntry.valids(i)}), - "BpBRight" -> PopCount((0 until PredictWidth).map{i => !commitEntry.mispred(i) && commitEntry.pd(i).isBr && commitEntry.valids(i)}), - "BpBWrong" -> PopCount((0 until PredictWidth).map{i => commitEntry.mispred(i) && commitEntry.pd(i).isBr && commitEntry.valids(i)}), - "BpJRight" -> PopCount((0 until PredictWidth).map{i => !commitEntry.mispred(i) && commitEntry.pd(i).isJal && commitEntry.valids(i)}), - "BpJWrong" -> PopCount((0 until PredictWidth).map{i => commitEntry.mispred(i) && commitEntry.pd(i).isJal && commitEntry.valids(i)}), - "BpIRight" -> PopCount((0 until PredictWidth).map{i => !commitEntry.mispred(i) && commitEntry.pd(i).isJalr && commitEntry.valids(i)}), - "BpIWrong" -> PopCount((0 until PredictWidth).map{i => commitEntry.mispred(i) && commitEntry.pd(i).isJalr && commitEntry.valids(i)}), - "BpCRight" -> PopCount((0 until PredictWidth).map{i => !commitEntry.mispred(i) && commitEntry.pd(i).isCall && commitEntry.valids(i)}), - "BpCWrong" -> PopCount((0 until PredictWidth).map{i => commitEntry.mispred(i) && commitEntry.pd(i).isCall && commitEntry.valids(i)}), - "BpRRight" -> PopCount((0 until PredictWidth).map{i => !commitEntry.mispred(i) && commitEntry.pd(i).isRet && commitEntry.valids(i)}), - "BpRWrong" -> PopCount((0 until PredictWidth).map{i => commitEntry.mispred(i) && commitEntry.pd(i).isRet && commitEntry.valids(i)}), + "BpRight" -> PopCount(mbpRights), + "BpWrong" -> PopCount(mbpWrongs), + "BpBRight" -> PopCount(mbpBRights), + "BpBWrong" -> PopCount(mbpBWrongs), + "BpJRight" -> PopCount(mbpJRights), + "BpJWrong" -> PopCount(mbpJWrongs), + "BpIRight" -> PopCount(mbpIRights), + "BpIWrong" -> PopCount(mbpIWrongs), + "BpCRight" -> PopCount(mbpCRights), + "BpCWrong" -> PopCount(mbpCWrongs), + "BpRRight" -> PopCount(mbpRRights), + "BpRWrong" -> PopCount(mbpRWrongs), + + "ubtbRight" -> PopCount(ubtbRights), + "ubtbWrong" -> PopCount(ubtbWrongs), + "btbRight" -> PopCount(btbRights), + "btbWrong" -> PopCount(btbWrongs), + "tageRight" -> PopCount(tageRights), + "tageWrong" -> PopCount(tageWrongs), + + "rasRight" -> PopCount(rasRights), + "rasWrong" -> PopCount(rasWrongs), + "loopRight" -> PopCount(loopRights), + "loopWrong" -> PopCount(loopWrongs), ) for((key, value) <- perfCountsMap) { - XSPerf(key, value, acc = true, intervalBits = 0) + XSPerf(key, value) } XSPerf("ftq_entries", validEntries) diff --git a/src/main/scala/xiangshan/backend/fu/Jump.scala b/src/main/scala/xiangshan/backend/fu/Jump.scala index f93ce9f46..a4372391b 100644 --- a/src/main/scala/xiangshan/backend/fu/Jump.scala +++ b/src/main/scala/xiangshan/backend/fu/Jump.scala @@ -66,7 +66,6 @@ class Jump extends FunctionUnit with HasRedirectOut { redirectOutValid := valid && !jumpDataModule.io.isAuipc redirectOut := DontCare - redirectOut.cfiUpdate.target := jumpDataModule.io.target redirectOut.level := RedirectLevel.flushAfter redirectOut.roqIdx := uop.roqIdx redirectOut.ftqIdx := uop.cf.ftqPtr diff --git a/src/main/scala/xiangshan/frontend/BPU.scala b/src/main/scala/xiangshan/frontend/BPU.scala index af899f1fe..ef4a2ee5d 100644 --- a/src/main/scala/xiangshan/frontend/BPU.scala +++ b/src/main/scala/xiangshan/frontend/BPU.scala @@ -213,6 +213,16 @@ class BPUStage1 extends BPUStage { io.out.resp <> io.in.resp io.out.brInfo := io.in.brInfo + // For perf counters + if (!env.FPGAPlatform && env.EnablePerfDebug) { + io.out.brInfo.metas.zipWithIndex.foreach{case (meta, i) => + // record ubtb pred result + meta.ubtbAns.hit := ubtbResp.hits(i) + meta.ubtbAns.taken := ubtbResp.takens(i) + meta.ubtbAns.target := ubtbResp.targets(i) + } + } + if (BPUDebug) { XSDebug(io.outFire, "outPred using ubtb resp: hits:%b, takens:%b, notTakens:%b, isRVC:%b\n", ubtbResp.hits.asUInt, ubtbResp.takens.asUInt, ~ubtbResp.takens.asUInt & brMask.asUInt, ubtbResp.is_RVC.asUInt) @@ -233,6 +243,16 @@ class BPUStage2 extends BPUStage { hasHalfRVI := btbResp.hits(PredictWidth-1) && !btbResp.isRVC(PredictWidth-1) && HasCExtension.B + // For perf counters + if (!env.FPGAPlatform && env.EnablePerfDebug) { + io.out.brInfo.metas.zipWithIndex.foreach{case (meta, i) => + // record btb pred result + meta.btbAns.hit := btbResp.hits(i) + meta.btbAns.taken := bimResp.ctrs(i)(1) + meta.btbAns.target := btbResp.targets(i) + } + } + if (BPUDebug) { XSDebug(io.outFire, "outPred using btb&bim resp: hits:%b, ctrTakens:%b\n", btbResp.hits.asUInt, VecInit(bimResp.ctrs.map(_(1))).asUInt) @@ -323,6 +343,26 @@ class BPUStage3 extends BPUStage { targets(i) := ras.io.out.bits.target } } + + // For perf counters + if (!env.FPGAPlatform && env.EnablePerfDebug) { + io.out.brInfo.metas.zipWithIndex.foreach{case (meta, i) => + // record tage pred result + meta.tageAns.hit := tageResp.hits(i) + meta.tageAns.taken := tageResp.takens(i) + meta.tageAns.target := DontCare + + // record ras pred result + meta.rasAns.hit := ras.io.out.valid + meta.rasAns.taken := true.B + meta.rasAns.target := ras.io.out.bits.target + + // record loop pred result + meta.loopAns.hit := loopRes(i) + meta.loopAns.taken := false.B + meta.loopAns.target := DontCare + } + } } diff --git a/src/main/scala/xiangshan/frontend/IFU.scala b/src/main/scala/xiangshan/frontend/IFU.scala index b4e9b7cf5..e04ca3a83 100644 --- a/src/main/scala/xiangshan/frontend/IFU.scala +++ b/src/main/scala/xiangshan/frontend/IFU.scala @@ -533,12 +533,12 @@ class IFU extends XSModule with HasIFUConst with HasCircularQueuePtrHelper io.fetchPacket.valid := fetchPacketValid // if(IFUDebug) { - if (!env.FPGAPlatform) { - val predictor_s3 = RegEnable(Mux(if3_redirect, 1.U(log2Up(4).W), 0.U(log2Up(4).W)), if3_fire) - val predictor_s4 = Mux(if4_redirect, 2.U, predictor_s3) - val predictor = predictor_s4 - toFtqBuf.metas.map(_.predictor := predictor) - } + // if (!env.FPGAPlatform) { + // val predictor_s3 = RegEnable(Mux(if3_redirect, 1.U(log2Up(4).W), 0.U(log2Up(4).W)), if3_fire) + // val predictor_s4 = Mux(if4_redirect, 2.U, predictor_s3) + // val predictor = predictor_s4 + // toFtqBuf.metas.map(_.predictor := predictor) + // } // } // val predRight = cfiUpdate.valid && !cfiUpdate.bits.isMisPred && !cfiUpdate.bits.isReplay @@ -562,6 +562,52 @@ class IFU extends XSModule with HasIFUConst with HasCircularQueuePtrHelper // ExcitingUtils.addSource(loopRight, "perfCntloopRight", Perf) // ExcitingUtils.addSource(loopWrong, "perfCntloopWrong", Perf) + if (!env.FPGAPlatform && env.EnablePerfDebug) { + val predictor_s3 = RegEnable(Mux(if3_redirect, 1.U(log2Up(4).W), 0.U(log2Up(4).W)), if3_fire) + val predictor_s4 = Mux(if4_redirect, 2.U, predictor_s3) + val predictor = predictor_s4 + toFtqBuf.metas.map(_.predictor := predictor) + + // val ubtbAns = WireInit(VecInit(Seq.fill(PredictWidth) {0.U.asTypeOf(new PredictorAnswer)} )) + // val btbAns = WireInit(VecInit(Seq.fill(PredictWidth) {0.U.asTypeOf(new PredictorAnswer)} )) + // val bimResp = WireInit(VecInit(Seq.fill(PredictWidth) {false.B} )) + // val tageAns = WireInit(VecInit(Seq.fill(PredictWidth) {0.U.asTypeOf(new PredictorAnswer)} )) + // val rasAns = WireInit(0.U.asTypeOf(new PredictorAnswer)) + // val loopAns = WireInit(VecInit(Seq.fill(PredictWidth) {0.U.asTypeOf(new PredictorAnswer)} )) + + // ExcitingUtils.addSink(ubtbAns, "ubtbAns") + // ExcitingUtils.addSink(btbAns, "btbAns") + // ExcitingUtils.addSink(bimResp, "bimResp") + // ExcitingUtils.addSink(tageAns, "tageAns") + // ExcitingUtils.addSink(rasAns, "rasAns") + // // ExcitingUtils.addSink(loopAns, "loopAns") + + // val ubtbAns_s3 = RegEnable(ubtbAns, if2_fire) + // val ubtbAns_s4 = RegEnable(ubtbAns_s3, if3_fire) + + // val btbAns_s3 = RegEnable(btbAns, if2_fire) + // val btbAns_s4 = RegEnable(btbAns_s3, if3_fire) + // val bimResp_s3 = RegEnable(bimResp, if2_fire) + // val bimResp_s4 = RegEnable(bimResp_s3, if3_fire) + + toFtqBuf.metas.zipWithIndex.foreach{ case(x,i) => + x.predictor := predictor + + // x.ubtbAns := ubtbAns_s4(i) + // x.btbAns := btbAns_s4(i) + // x.btbAns.taken := bimResp_s4(i) + // x.tageAns := tageAns(i) + // x.rasAns := rasAns // Is this right? + // x.loopAns := loopAns(i) + + x.ubtbAns := bpu.io.brInfo.metas(i).ubtbAns + x.btbAns := bpu.io.brInfo.metas(i).btbAns + x.tageAns := bpu.io.brInfo.metas(i).tageAns + x.rasAns := bpu.io.brInfo.metas(i).rasAns // Is this right? + x.loopAns := bpu.io.brInfo.metas(i).loopAns + } + } + // debug info if (IFUDebug) { XSDebug(RegNext(reset.asBool) && !reset.asBool, "Reseting...\n") -- GitLab