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(s"depth${p(XSCoreParamsKey).HartId}", initValue = 32) 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 = Constantin.createRecord(s"enableDynamicPrefetcher${p(XSCoreParamsKey).HartId}", initValue = 1) 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 XSPerfAccumulate("disable_time", !enable) 152 153 assert(depth =/= 0.U, "depth should not be zero") 154}