xref: /XiangShan/src/main/scala/xiangshan/mem/prefetch/PrefetcherMonitor.scala (revision 8891a219bbc84f568e1d134854d8d5ed86d6d560)
1package xiangshan.mem.prefetch
2
3import chisel3._
4import chisel3.util._
5import org.chipsalliance.cde.config.Parameters
6import xiangshan._
7import xiangshan.mem.{LdPrefetchTrainBundle, StPrefetchTrainBundle, L1PrefetchReq}
8import utils._
9import utility._
10
11trait HasPrefetcherMonitorHelper {
12  val TIMELY_CHECK_INTERVAL = 1000
13  val VALIDITY_CHECK_INTERVAL = 1000
14
15  val BAD_THRESHOLD = 400
16  val DISABLE_THRESHOLD = 900
17  val LATE_HIT_THRESHOLD = 900
18  val LATE_MISS_THRESHOLD = 200
19
20  val BACK_OFF_INTERVAL = 100000
21  val LOW_CONF_INTERVAL = 200000
22
23  // val enableDynamicPrefetcher = false
24}
25
26class PrefetchControlBundle()(implicit p: Parameters) extends XSBundle with HasStreamPrefetchHelper {
27  val dynamic_depth = UInt(DEPTH_BITS.W)
28  val flush = Bool()
29  val enable = Bool()
30  val confidence = UInt(1.W)
31}
32
33class PrefetcherMonitorBundle()(implicit p: Parameters) extends XSBundle {
34  val timely = new XSBundle {
35    val total_prefetch = Input(Bool())
36    val late_hit_prefetch = Input(Bool())
37    val late_miss_prefetch = Input(Bool())
38    val prefetch_hit = Input(UInt(2.W))
39  }
40
41  val validity = new XSBundle {
42    val good_prefetch = Input(Bool())
43    val bad_prefetch = Input(Bool())
44  }
45
46  val pf_ctrl = Output(new PrefetchControlBundle)
47}
48
49class PrefetcherMonitor()(implicit p: Parameters) extends XSModule with HasPrefetcherMonitorHelper with HasStreamPrefetchHelper {
50  val io = IO(new PrefetcherMonitorBundle)
51
52  val depth = Reg(UInt(DEPTH_BITS.W))
53  val flush = RegInit(false.B)
54  val enable = RegInit(true.B)
55  val confidence = RegInit(1.U(1.W))
56
57  // TODO: mshr number
58  // mshr full && load miss && load send mshr req && !load match,  -> decr nmax prefetch
59  // mshr free
60
61  io.pf_ctrl.dynamic_depth := depth
62  io.pf_ctrl.flush := flush
63  io.pf_ctrl.enable := enable
64  io.pf_ctrl.confidence := confidence
65
66  val depth_const = Wire(UInt(DEPTH_BITS.W))
67  depth_const := Constantin.createRecord("depth" + p(XSCoreParamsKey).HartId.toString, initValue = 32.U)
68
69  val total_prefetch_cnt = RegInit(0.U((log2Up(TIMELY_CHECK_INTERVAL) + 1).W))
70  val late_hit_prefetch_cnt = RegInit(0.U((log2Up(TIMELY_CHECK_INTERVAL) + 1).W))
71  val late_miss_prefetch_cnt = RegInit(0.U((log2Up(TIMELY_CHECK_INTERVAL) + 1).W))
72  val prefetch_hit_cnt = RegInit(0.U(32.W))
73
74  val good_prefetch_cnt = RegInit(0.U((log2Up(VALIDITY_CHECK_INTERVAL) + 1).W))
75  val bad_prefetch_cnt = RegInit(0.U((log2Up(VALIDITY_CHECK_INTERVAL) + 1).W))
76
77  val back_off_cnt = RegInit(0.U((log2Up(BACK_OFF_INTERVAL) + 1).W))
78  val low_conf_cnt = RegInit(0.U((log2Up(LOW_CONF_INTERVAL) + 1).W))
79
80  val timely_reset = total_prefetch_cnt === TIMELY_CHECK_INTERVAL.U
81  val validity_reset = (good_prefetch_cnt + bad_prefetch_cnt) === VALIDITY_CHECK_INTERVAL.U
82  val back_off_reset = back_off_cnt === BACK_OFF_INTERVAL.U
83  val conf_reset = low_conf_cnt === LOW_CONF_INTERVAL.U
84
85  total_prefetch_cnt := Mux(timely_reset, 0.U, total_prefetch_cnt + io.timely.total_prefetch)
86  late_hit_prefetch_cnt := Mux(timely_reset, 0.U, late_hit_prefetch_cnt + io.timely.late_hit_prefetch)
87  late_miss_prefetch_cnt := Mux(timely_reset, 0.U, late_miss_prefetch_cnt + io.timely.late_miss_prefetch)
88  prefetch_hit_cnt := Mux(timely_reset, 0.U, prefetch_hit_cnt + io.timely.prefetch_hit)
89
90  good_prefetch_cnt := Mux(validity_reset, 0.U, good_prefetch_cnt + io.validity.good_prefetch)
91  bad_prefetch_cnt := Mux(validity_reset, 0.U, bad_prefetch_cnt + io.validity.bad_prefetch)
92
93  back_off_cnt := Mux(back_off_reset, 0.U, back_off_cnt + !enable)
94  low_conf_cnt := Mux(conf_reset, 0.U, low_conf_cnt + !confidence.asBool)
95
96  val trigger_late_hit = timely_reset && (late_hit_prefetch_cnt >= LATE_HIT_THRESHOLD.U)
97  val trigger_late_miss = timely_reset && (late_miss_prefetch_cnt >= LATE_MISS_THRESHOLD.U)
98  val trigger_bad_prefetch = validity_reset && (bad_prefetch_cnt >= BAD_THRESHOLD.U)
99  val trigger_disable = validity_reset && (bad_prefetch_cnt >= DISABLE_THRESHOLD.U)
100
101  flush := Mux(flush, false.B, flush)
102  enable := Mux(back_off_reset, true.B, enable)
103  confidence := Mux(conf_reset, 1.U(1.W), confidence)
104
105  when(trigger_bad_prefetch) {
106    depth := Mux(depth === 1.U, depth, depth >> 1)
107  }
108  when(trigger_disable) {
109    confidence := 0.U(1.W)
110    enable := false.B
111    flush := true.B
112  }
113
114  when(trigger_late_miss) {
115    depth := Mux(depth === (1 << (DEPTH_BITS - 1)).U, depth, depth << 1)
116  }.elsewhen(trigger_late_hit) {
117    // for now, late hit will disable the prefether
118    confidence := 0.U(1.W)
119    enable := false.B
120  }
121
122  val enableDynamicPrefetcher_const = WireInit(Constantin.createRecord("enableDynamicPrefetcher" + p(XSCoreParamsKey).HartId.toString, initValue = 1.U))
123  val enableDynamicPrefetcher = enableDynamicPrefetcher_const === 1.U
124
125  when(!enableDynamicPrefetcher) {
126    depth := depth_const
127    flush := false.B
128    enable := true.B
129    confidence := 1.U
130  }.otherwise {
131    // for now, only dynamically disable prefetcher, without depth and flush
132    depth := depth_const
133    flush := false.B
134  }
135
136  when(reset.asBool) {
137    depth := depth_const
138  }
139
140  XSPerfAccumulate("total_prefetch", io.timely.total_prefetch)
141  XSPerfAccumulate("late_hit_prefetch", io.timely.late_hit_prefetch)
142  XSPerfAccumulate("late_miss_prefetch", io.timely.late_miss_prefetch)
143  XSPerfAccumulate("good_prefetch", io.validity.good_prefetch)
144  XSPerfAccumulate("bad_prefetch", io.validity.bad_prefetch)
145  for(i <- (0 until DEPTH_BITS)) {
146    val t = (1 << i)
147    XSPerfAccumulate(s"depth${t}", depth === t.U)
148  }
149  XSPerfAccumulate("trigger_disable", trigger_disable)
150  XSPerfAccumulate("prefetch_hit", io.timely.prefetch_hit)
151
152  assert(depth =/= 0.U, "depth should not be zero")
153}