From 6289933298d34fcae4f1b809947b94933f6dee82 Mon Sep 17 00:00:00 2001 From: YuanDL <2524247987@qq.com> Date: Wed, 18 Dec 2024 10:57:34 +0800 Subject: [PATCH] power(tage): Add dynamic shutdown feature for TAGE tables Add a counter to each table to record the number of consecutive misses or hits that do not participate in prediction. When the counter value reaches the threshold, close the read request for the table. When a redirect is detected, reopen the closed table. --- src/main/scala/top/Configs.scala | 3 ++ src/main/scala/xiangshan/Parameters.scala | 4 ++ src/main/scala/xiangshan/frontend/Tage.scala | 46 +++++++++++++++++++- 3 files changed, 52 insertions(+), 1 deletion(-) diff --git a/src/main/scala/top/Configs.scala b/src/main/scala/top/Configs.scala index c20f9d8c997..2c5206e178b 100644 --- a/src/main/scala/top/Configs.scala +++ b/src/main/scala/top/Configs.scala @@ -144,6 +144,9 @@ class MinimalConfig(n: Int = 1) extends Config( Seq((512, 4, 6), (512, 9, 6), (1024, 19, 6)), + // Based on the statistical results of continuous unused counters + // using spec2k6 coverage 0.3, the threshold is obtained + TageTableCloseThresholds = Seq(300, 300, 300), SCNRows = 128, SCNTables = 2, SCHistLens = Seq(0, 5), diff --git a/src/main/scala/xiangshan/Parameters.scala b/src/main/scala/xiangshan/Parameters.scala index 586fe9d52b0..bfdaaadae13 100644 --- a/src/main/scala/xiangshan/Parameters.scala +++ b/src/main/scala/xiangshan/Parameters.scala @@ -109,6 +109,9 @@ case class XSCoreParameters ( 4096, 13, 8), ( 4096, 32, 8), ( 4096, 119, 8)), + // Based on the statistical results of continuous unused counters + // using spec2k6 coverage 0.3, the threshold is obtained + TageTableCloseThresholds: Seq[Int] = Seq(300, 300, 300, 300), ITTageTableInfos: Seq[Tuple3[Int,Int,Int]] = // Sets Hist Tag Seq(( 256, 4, 9), @@ -693,6 +696,7 @@ trait HasXSParameter { } def numBr = coreParams.numBr def TageTableInfos = coreParams.TageTableInfos + def TageTableCloseThresholds = coreParams.TageTableCloseThresholds def TageBanks = coreParams.numBr def SCNRows = coreParams.SCNRows def SCCtrBits = coreParams.SCCtrBits diff --git a/src/main/scala/xiangshan/frontend/Tage.scala b/src/main/scala/xiangshan/frontend/Tage.scala index bd5b0920279..9c0cb758db6 100644 --- a/src/main/scala/xiangshan/frontend/Tage.scala +++ b/src/main/scala/xiangshan/frontend/Tage.scala @@ -65,6 +65,9 @@ trait TageParams extends HasBPUConst with HasXSParameter { def get_phy_br_idx(unhashed_idx: UInt, br_lidx: Int) = get_unshuffle_bits(unhashed_idx) ^ br_lidx.U(log2Ceil(numBr).W) def get_lgc_br_idx(unhashed_idx: UInt, br_pidx: UInt) = get_unshuffle_bits(unhashed_idx) ^ br_pidx + // Based on the statistical results of continuous unused counters + // using spec2k6 coverage 0.3, the threshold is obtained + def TABLES_CLOSE_THRESHOLD = TageTableCloseThresholds } trait HasFoldedHistory { @@ -607,10 +610,14 @@ class Tage(implicit p: Parameters) extends BaseTage { val resp_meta = Wire(new TageMeta) override val meta_size = resp_meta.getWidth + + // tables read request close signal + val s0_tables_req_closed = RegInit(VecInit(Seq.fill(TABLES_CLOSE_THRESHOLD.size)(false.B))) + val tables = TageTableInfos.zipWithIndex.map { case ((nRows, histLen, tagLen), i) => { val t = Module(new TageTable(nRows, histLen, tagLen, i)) - t.io.req.valid := io.s0_fire(1) + t.io.req.valid := io.s0_fire(1) && !s0_tables_req_closed(i) t.io.req.bits.pc := s0_pc_dup(1) t.io.req.bits.folded_hist := io.in.bits.folded_hist(1) t.io.req.bits.ghist := io.in.bits.ghist @@ -641,6 +648,9 @@ class Tage(implicit p: Parameters) extends BaseTage { val debug_pc_s1 = RegEnable(s0_pc_dup(1), io.s0_fire(1)) val debug_pc_s2 = RegEnable(debug_pc_s1, io.s1_fire(1)) + // This prediction shows the usage of each table and slot + val table_unused = Wire(Vec(TageNTables, Vec(numBr, Bool()))) + val s1_provideds = Wire(Vec(numBr, Bool())) val s1_providers = Wire(Vec(numBr, UInt(log2Ceil(TageNTables).W))) val s1_providerResps = Wire(Vec(numBr, new TageResp)) @@ -931,6 +941,10 @@ class Tage(implicit p: Parameters) extends BaseTage { updateResetU(i) := true.B } } + for (t <- 0 until TageNTables) { + // If the table t is hit but not select or missed, it can be closed + table_unused(t)(i) := !(t.U === providerInfo.tableIdx && provided) || !s1_per_br_resp(t).valid + } XSPerfAccumulate(f"tage_bank_${i}_update_allocate_failure", needToAllocate && !canAllocate) XSPerfAccumulate(f"tage_bank_${i}_update_allocate_success", needToAllocate && canAllocate) XSPerfAccumulate(s"tage_bank_${i}_mispred", hasUpdate && updateMispred) @@ -941,6 +955,36 @@ class Tage(implicit p: Parameters) extends BaseTage { } } + for (t <- 0 until TageNTables) { + require(TABLES_CLOSE_THRESHOLD.size == TageNTables) + val unused_counter = RegInit(0.U(log2Ceil(TABLES_CLOSE_THRESHOLD(t)).W)) + val unused = table_unused(t).reduce(_ && _) + // Update the counters of each table + when(io.s1_fire(1)) { + unused_counter := Mux( + !unused, + 0.U, + // If the counter increases to the threshold, to prevent overflow, + // when the status is unused, the counter value remains at its original value. + Mux(unused_counter >= TABLES_CLOSE_THRESHOLD(t).asUInt, unused_counter, unused_counter + 1.U) + ) + } + // Determine whether to turn off req based on the threshold + when(unused_counter >= TABLES_CLOSE_THRESHOLD(t).asUInt) { + s0_tables_req_closed(t) := true.B + } + // When a redirect occurs, reopen the closed table + val reopen = s0_tables_req_closed(t) && io.redirect.valid + when(reopen) { + s0_tables_req_closed(t) := false.B + unused_counter := 0.U + } + + XSPerfAccumulate(f"tage_table_${t}_close_cycle", s0_tables_req_closed(t) && io.s0_fire(0)) + XSPerfAccumulate(f"tage_table_${t}_open_cycle", !s0_tables_req_closed(t) && io.s0_fire(0)) + // XSPerfHistogram(f"tage_table_${t}_continuous_miss", unused_counter, !unused && unused_counter > 100.U, 100, 1000, 100) + } + val realWens = updateMask.transpose.map(v => v.reduce(_ | _)) for (w <- 0 until TageBanks) { for (i <- 0 until TageNTables) {