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 } 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 val edgeIn = outer.node.in.head._2 105 106 class RecordEntry()(implicit p: Parameters) extends Bundle { 107 val valid = Bool() 108 val timeStamp = UInt(64.W) 109 val reqType = UInt(8.W) 110 } 111 112 // For simplicity, latency statistic works between nodes with SINGLE edge 113 require(nrEdge == 1) 114 val timer = GTimer() 115 val nrSource = math.pow(2, edgeIn.bundle.sourceBits).toInt 116 val latencyRecord = RegInit(VecInit(Seq.fill(nrSource)(0.U.asTypeOf(new RecordEntry())))) 117 val latencySum = RegInit(0.U(128.W)) 118 val nrRecord = RegInit(0.U(128.W)) 119 120 outer.node.in.zip(outer.node.out).zipWithIndex.foreach { 121 case (((in, edgeIn), (out, edgeOut)), i) => 122 val channelA = in.a 123 when(channelA.fire && 124 channelA.bits.opcode =/= Hint && 125 channelA.bits.opcode =/= PutFullData && 126 channelA.bits.opcode =/= PutPartialData 127 ) { 128 // Valid channel A fire, record it 129 assert(latencyRecord(channelA.bits.source).valid === false.B) 130 latencyRecord(channelA.bits.source).valid := true.B 131 latencyRecord(channelA.bits.source).timeStamp := timer 132 latencyRecord(channelA.bits.source).reqType := channelA.bits.user.lift(ReqSourceKey).getOrElse(MemReqSource.NoWhere.id.U) 133 } 134 val channelD = in.d 135 val (first, _, _, _) = edgeIn.count(channelD) 136 // Valid channel D fire, resolve it 137 val resolveRecord = channelD.fire && first && 138 channelD.bits.opcode =/= ReleaseAck && 139 channelD.bits.opcode =/= AccessAck 140 val latency = WireInit(0.U(64.W)) 141 when(resolveRecord) { 142 assert(latencyRecord(channelD.bits.source).valid === true.B) 143 latencyRecord(channelD.bits.source).valid := false.B 144 latency := timer - latencyRecord(channelD.bits.source).timeStamp 145 latencySum := latencySum + timer 146 nrRecord := nrRecord + 1.U 147 // printf("timer: %x\n", latency) 148 } 149 XSPerfAccumulate(name + "_nrRecord_all", resolveRecord) 150 XSPerfAccumulate(name + "_latencySum_all", Mux(resolveRecord, latency, 0.U)) 151 152 for (j <- 0 until MemReqSource.ReqSourceCount.id) { 153 val typeMatch = latencyRecord(channelD.bits.source).reqType === j.U 154 XSPerfAccumulate(name + s"_nrRecord_type${j}", resolveRecord && typeMatch) 155 XSPerfAccumulate(name + s"_latencySum_type${j}", Mux(resolveRecord && typeMatch, latency, 0.U)) 156 } 157 } 158 } 159 160} 161 162object BusPerfMonitor { 163 def apply( 164 name: String, 165 enable: Boolean = false, 166 stat_latency: Boolean = false, 167 add_reqkey: Boolean = false)(implicit p: Parameters) = 168 { 169 if(enable){ 170 val busPMU = LazyModule(new BusPerfMonitor(name, stat_latency)) 171 busPMU.node 172 } else { 173 TLTempNode() 174 } 175 } 176} 177