1/*************************************************************************************** 2* Copyright (c) 2020-2021 Institute of Computing Technology, Chinese Academy of Sciences 3* Copyright (c) 2020-2021 Peng Cheng Laboratory 4* 5* XiangShan is licensed under Mulan PSL v2. 6* You can use this software according to the terms and conditions of the Mulan PSL v2. 7* You may obtain a copy of Mulan PSL v2 at: 8* http://license.coscl.org.cn/MulanPSL2 9* 10* THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, 11* EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, 12* MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. 13* 14* See the Mulan PSL v2 for more details. 15***************************************************************************************/ 16 17package top 18 19import chipsalliance.rocketchip.config.Parameters 20import freechips.rocketchip.diplomacy.{AdapterNode, LazyModule, LazyModuleImp} 21import freechips.rocketchip.tilelink._ 22import chisel3._ 23import chisel3.util._ 24import utils.{XSPerfAccumulate, XSPerfPrint} 25import freechips.rocketchip.tilelink.TLMessages._ 26import freechips.rocketchip.tilelink.TLPermissions._ 27import utility.{MemReqSource, ReqSourceField, ReqSourceKey, GTimer} 28 29class BusPerfMonitor(name: String, stat_latency: Boolean, add_reqkey: Boolean)(implicit p: Parameters) extends LazyModule { 30 val node = if (add_reqkey) TLAdapterNode(managerFn = { m => 31 TLSlavePortParameters.v1( 32 m.managers.map { m => 33 m.v2copy() 34 }, 35 requestKeys = Seq(ReqSourceKey), 36 beatBytes = 32, 37 endSinkId = m.endSinkId 38 ) 39 }) else { 40 TLAdapterNode() 41 } 42 lazy val module = new BusPerfMonitorImp(this, name, stat_latency) 43} 44 45class BusPerfMonitorImp(outer: BusPerfMonitor, name: String, stat_latency: Boolean) 46 extends LazyModuleImp(outer) 47{ 48 49 outer.node.in.zip(outer.node.out).foreach{ 50 case ((in, edgeIn), (out, edgeOut)) => 51 out <> in 52 } 53 54 def PERF_CHN[T <: TLChannel](clientName: String, chn: DecoupledIO[T]) = { 55 56 val channelName = chn.bits.channelName.replaceAll(" ", "_").replaceAll("'", "") 57 XSPerfAccumulate(s"${clientName}_${channelName}_fire", chn.fire) 58 XSPerfAccumulate(s"${clientName}_${channelName}_stall", chn.valid && !chn.ready) 59 60 val ops = chn.bits match { 61 case _: TLBundleA => TLMessages.a.map(_._1) 62 case _: TLBundleB => TLMessages.b.map(_._1) 63 case _: TLBundleC => TLMessages.c.map(_._1) 64 case _: TLBundleD => TLMessages.d.map(_._1) 65 case _: TLBundleE => Nil 66 } 67 68 for((op_raw, i) <- ops.zipWithIndex){ 69 val op = s"${op_raw}".replaceAll(" ", "_") 70 chn.bits match { 71 case a: TLBundleA => 72 XSPerfAccumulate(s"${clientName}_${channelName}_${op}_fire", 73 i.U === a.opcode && chn.fire 74 ) 75 XSPerfAccumulate(s"${clientName}_${channelName}_${op}_stall", 76 i.U === a.opcode && chn.valid && !chn.ready 77 ) 78 case b: TLBundleB => 79 XSPerfAccumulate(s"${clientName}_${channelName}_${op}_fire", 80 i.U === b.opcode && chn.fire 81 ) 82 XSPerfAccumulate(s"${clientName}_${channelName}_${op}_stall", 83 i.U === b.opcode && chn.valid && !chn.ready 84 ) 85 case c: TLBundleC => 86 XSPerfAccumulate(s"${clientName}_${channelName}_${op}_fire", 87 i.U === c.opcode && chn.fire 88 ) 89 XSPerfAccumulate(s"${clientName}_${channelName}_${op}_stall", 90 i.U === c.opcode && chn.valid && !chn.ready 91 ) 92 case d: TLBundleD => 93 XSPerfAccumulate(s"${clientName}_${channelName}_${op}_fire", 94 i.U === d.opcode && chn.fire 95 ) 96 XSPerfAccumulate(s"${clientName}_${channelName}_${op}_stall", 97 i.U === d.opcode && chn.valid && !chn.ready 98 ) 99 } 100 } 101 } 102 103 for (((in, edgeIn), i) <- outer.node.in.zipWithIndex) { 104 val clientName = s"${name}_${edgeIn.master.masters.head.name}_bank_$i" 105 PERF_CHN(clientName, in.a) 106 PERF_CHN(clientName, in.d) 107 if (in.params.hasBCE) { 108 PERF_CHN(clientName, in.b) 109 PERF_CHN(clientName, in.c) 110 PERF_CHN(clientName, in.e) 111 } 112 } 113 114 if (stat_latency) { 115 val nrEdge = outer.node.in.length.toInt 116 val edgeIn = outer.node.in.head._2 117 118 class RecordEntry()(implicit p: Parameters) extends Bundle { 119 val valid = Bool() 120 val timeStamp = UInt(64.W) 121 val reqType = UInt(8.W) 122 } 123 124 // For simplicity, latency statistic works between nodes with SINGLE edge 125 require(nrEdge == 1) 126 val timer = GTimer() 127 val nrSource = math.pow(2, edgeIn.bundle.sourceBits).toInt 128 val latencyRecord = RegInit(VecInit(Seq.fill(nrSource)(0.U.asTypeOf(new RecordEntry())))) 129 val latencySum = RegInit(0.U(128.W)) 130 val nrRecord = RegInit(0.U(128.W)) 131 132 outer.node.in.zip(outer.node.out).zipWithIndex.foreach { 133 case (((in, edgeIn), (out, edgeOut)), i) => 134 val channelA = in.a 135 when(channelA.fire && 136 channelA.bits.opcode =/= Hint && 137 channelA.bits.opcode =/= PutFullData && 138 channelA.bits.opcode =/= PutPartialData 139 ) { 140 // Valid channel A fire, record it 141 assert(latencyRecord(channelA.bits.source).valid === false.B) 142 latencyRecord(channelA.bits.source).valid := true.B 143 latencyRecord(channelA.bits.source).timeStamp := timer 144 latencyRecord(channelA.bits.source).reqType := channelA.bits.user.lift(ReqSourceKey).getOrElse(MemReqSource.NoWhere.id.U) 145 } 146 val channelD = in.d 147 val (first, _, _, _) = edgeIn.count(channelD) 148 // Valid channel D fire, resolve it 149 val resolveRecord = channelD.fire && first && 150 channelD.bits.opcode =/= ReleaseAck && 151 channelD.bits.opcode =/= AccessAck 152 val latency = WireInit(0.U(64.W)) 153 when(resolveRecord) { 154 assert(latencyRecord(channelD.bits.source).valid === true.B) 155 latencyRecord(channelD.bits.source).valid := false.B 156 latency := timer - latencyRecord(channelD.bits.source).timeStamp 157 latencySum := latencySum + timer 158 nrRecord := nrRecord + 1.U 159 // printf("timer: %x\n", latency) 160 } 161 XSPerfAccumulate(name + "_nrRecord_all", resolveRecord) 162 XSPerfAccumulate(name + "_latencySum_all", Mux(resolveRecord, latency, 0.U)) 163 164 for (j <- 0 until MemReqSource.ReqSourceCount.id) { 165 val typeMatch = latencyRecord(channelD.bits.source).reqType === j.U 166 XSPerfAccumulate(name + s"_nrRecord_type${j}", resolveRecord && typeMatch) 167 XSPerfAccumulate(name + s"_latencySum_type${j}", Mux(resolveRecord && typeMatch, latency, 0.U)) 168 } 169 } 170 } 171 172} 173 174object BusPerfMonitor { 175 def apply( 176 name: String, 177 enable: Boolean = false, 178 stat_latency: Boolean = false, 179 add_reqkey: Boolean = false)(implicit p: Parameters) = 180 { 181 if(enable){ 182 val busPMU = LazyModule(new BusPerfMonitor(name, stat_latency, add_reqkey)) 183 busPMU.node 184 } else { 185 TLTempNode() 186 } 187 } 188} 189