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