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 org.chipsalliance.cde.config.Parameters 20import chisel3._ 21import chisel3.util._ 22import freechips.rocketchip.diplomacy.{LazyModule, LazyModuleImp} 23import freechips.rocketchip.tilelink.TLMessages._ 24import freechips.rocketchip.tilelink._ 25import utility.{GTimer, MemReqSource, ReqSourceKey, XSPerfAccumulate} 26 27class BusPerfMonitor(name: String, stat_latency: Boolean)(implicit p: Parameters) extends LazyModule { 28 val node = TLAdapterNode() 29 lazy val module = new BusPerfMonitorImp(this, name, stat_latency) 30} 31 32class BusPerfMonitorImp(outer: BusPerfMonitor, name: String, stat_latency: Boolean) 33 extends LazyModuleImp(outer) 34{ 35 36 outer.node.in.zip(outer.node.out).foreach{ 37 case ((in, edgeIn), (out, edgeOut)) => 38 out <> in 39 } 40 41 def PERF_CHN[T <: TLChannel](clientName: String, chn: DecoupledIO[T]) = { 42 43 val channelName = chn.bits.channelName.replaceAll(" ", "_").replaceAll("'", "") 44 XSPerfAccumulate(s"${clientName}_${channelName}_fire", chn.fire) 45 XSPerfAccumulate(s"${clientName}_${channelName}_stall", chn.valid && !chn.ready) 46 47 val ops = chn.bits match { 48 case _: TLBundleA => TLMessages.a.map(_._1) 49 case _: TLBundleB => TLMessages.b.map(_._1) 50 case _: TLBundleC => TLMessages.c.map(_._1) 51 case _: TLBundleD => TLMessages.d.map(_._1) 52 case _: TLBundleE => Nil 53 } 54 55 for((op_raw, i) <- ops.zipWithIndex){ 56 val op = s"${op_raw}".replaceAll(" ", "_") 57 chn.bits match { 58 case a: TLBundleA => 59 XSPerfAccumulate(s"${clientName}_${channelName}_${op}_fire", 60 i.U === a.opcode && chn.fire 61 ) 62 XSPerfAccumulate(s"${clientName}_${channelName}_${op}_stall", 63 i.U === a.opcode && chn.valid && !chn.ready 64 ) 65 case b: TLBundleB => 66 XSPerfAccumulate(s"${clientName}_${channelName}_${op}_fire", 67 i.U === b.opcode && chn.fire 68 ) 69 XSPerfAccumulate(s"${clientName}_${channelName}_${op}_stall", 70 i.U === b.opcode && chn.valid && !chn.ready 71 ) 72 case c: TLBundleC => 73 XSPerfAccumulate(s"${clientName}_${channelName}_${op}_fire", 74 i.U === c.opcode && chn.fire 75 ) 76 XSPerfAccumulate(s"${clientName}_${channelName}_${op}_stall", 77 i.U === c.opcode && chn.valid && !chn.ready 78 ) 79 case d: TLBundleD => 80 XSPerfAccumulate(s"${clientName}_${channelName}_${op}_fire", 81 i.U === d.opcode && chn.fire 82 ) 83 XSPerfAccumulate(s"${clientName}_${channelName}_${op}_stall", 84 i.U === d.opcode && chn.valid && !chn.ready 85 ) 86 case e: TLBundleE => throw new IllegalArgumentException("Cannot reach here") 87 } 88 } 89 } 90 91 for (((in, edgeIn), i) <- outer.node.in.zipWithIndex) { 92 val clientName = s"${name}_${edgeIn.master.masters.head.name}_bank_$i" 93 PERF_CHN(clientName, in.a) 94 PERF_CHN(clientName, in.d) 95 if (in.params.hasBCE) { 96 PERF_CHN(clientName, in.b) 97 PERF_CHN(clientName, in.c) 98 PERF_CHN(clientName, in.e) 99 } 100 } 101 102 if (stat_latency) { 103 val nrEdge = outer.node.in.length.toInt 104 if (outer.node.in.isEmpty) { 105 println(s"name = $name") 106 } 107 val edgeIn = outer.node.in.head._2 108 109 class RecordEntry()(implicit p: Parameters) extends Bundle { 110 val valid = Bool() 111 val timeStamp = UInt(64.W) 112 val reqType = UInt(8.W) 113 } 114 115 // For simplicity, latency statistic works between nodes with SINGLE edge 116 require(nrEdge == 1) 117 val timer = GTimer() 118 val nrSource = math.pow(2, edgeIn.bundle.sourceBits).toInt 119 val latencyRecord = RegInit(VecInit(Seq.fill(nrSource)(0.U.asTypeOf(new RecordEntry())))) 120 val latencySum = RegInit(0.U(128.W)) 121 val nrRecord = RegInit(0.U(128.W)) 122 123 outer.node.in.zip(outer.node.out).zipWithIndex.foreach { 124 case (((in, edgeIn), (out, edgeOut)), i) => 125 val channelA = in.a 126 when(channelA.fire && 127 channelA.bits.opcode =/= Hint && 128 channelA.bits.opcode =/= PutFullData && 129 channelA.bits.opcode =/= PutPartialData 130 ) { 131 // Valid channel A fire, record it 132 assert(latencyRecord(channelA.bits.source).valid === false.B) 133 latencyRecord(channelA.bits.source).valid := true.B 134 latencyRecord(channelA.bits.source).timeStamp := timer 135 latencyRecord(channelA.bits.source).reqType := channelA.bits.user.lift(ReqSourceKey).getOrElse(MemReqSource.NoWhere.id.U) 136 } 137 val channelD = in.d 138 val (first, _, _, _) = edgeIn.count(channelD) 139 // Valid channel D fire, resolve it 140 val resolveRecord = channelD.fire && first && 141 channelD.bits.opcode =/= ReleaseAck && 142 channelD.bits.opcode =/= AccessAck 143 val latency = WireInit(0.U(64.W)) 144 when(resolveRecord) { 145 assert(latencyRecord(channelD.bits.source).valid === true.B) 146 latencyRecord(channelD.bits.source).valid := false.B 147 latency := timer - latencyRecord(channelD.bits.source).timeStamp 148 latencySum := latencySum + timer 149 nrRecord := nrRecord + 1.U 150 // printf("timer: %x\n", latency) 151 } 152 XSPerfAccumulate(name + "_nrRecord_all", resolveRecord) 153 XSPerfAccumulate(name + "_latencySum_all", Mux(resolveRecord, latency, 0.U)) 154 155 for (j <- 0 until MemReqSource.ReqSourceCount.id) { 156 val typeMatch = latencyRecord(channelD.bits.source).reqType === j.U 157 XSPerfAccumulate(name + s"_nrRecord_type${j}", resolveRecord && typeMatch) 158 XSPerfAccumulate(name + s"_latencySum_type${j}", Mux(resolveRecord && typeMatch, latency, 0.U)) 159 } 160 } 161 } 162 163} 164 165object BusPerfMonitor { 166 def apply( 167 name: String, 168 enable: Boolean = false, 169 stat_latency: Boolean = false, 170 add_reqkey: Boolean = false)(implicit p: Parameters) = 171 { 172 if(enable){ 173 val busPMU = LazyModule(new BusPerfMonitor(name, stat_latency)) 174 busPMU.node 175 } else { 176 TLTempNode() 177 } 178 } 179} 180