xref: /XiangShan/src/main/scala/top/BusPerfMonitor.scala (revision 7a96cc7f535a08022595db7dfd263251e5db443e)
1d2b20d1aSTang Haojin/***************************************************************************************
2d2b20d1aSTang Haojin* Copyright (c) 2020-2021 Institute of Computing Technology, Chinese Academy of Sciences
3d2b20d1aSTang Haojin* Copyright (c) 2020-2021 Peng Cheng Laboratory
4d2b20d1aSTang Haojin*
5d2b20d1aSTang Haojin* XiangShan is licensed under Mulan PSL v2.
6d2b20d1aSTang Haojin* You can use this software according to the terms and conditions of the Mulan PSL v2.
7d2b20d1aSTang Haojin* You may obtain a copy of Mulan PSL v2 at:
8d2b20d1aSTang Haojin*          http://license.coscl.org.cn/MulanPSL2
9d2b20d1aSTang Haojin*
10d2b20d1aSTang Haojin* THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
11d2b20d1aSTang Haojin* EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
12d2b20d1aSTang Haojin* MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
13d2b20d1aSTang Haojin*
14d2b20d1aSTang Haojin* See the Mulan PSL v2 for more details.
15d2b20d1aSTang Haojin***************************************************************************************/
16d2b20d1aSTang Haojin
171a2cf152SYinan Xupackage top
181a2cf152SYinan Xu
198891a219SYinan Xuimport org.chipsalliance.cde.config.Parameters
201a2cf152SYinan Xuimport chisel3._
211a2cf152SYinan Xuimport chisel3.util._
226695f071SYinan Xuimport freechips.rocketchip.diplomacy.{LazyModule, LazyModuleImp}
23d2b20d1aSTang Haojinimport freechips.rocketchip.tilelink.TLMessages._
246695f071SYinan Xuimport freechips.rocketchip.tilelink._
256695f071SYinan Xuimport utility.{GTimer, MemReqSource, ReqSourceKey}
266695f071SYinan Xuimport utils.XSPerfAccumulate
271a2cf152SYinan Xu
286695f071SYinan Xuclass BusPerfMonitor(name: String, stat_latency: Boolean)(implicit p: Parameters) extends LazyModule {
296695f071SYinan Xu  val node = TLAdapterNode()
30d2b20d1aSTang Haojin  lazy val module = new BusPerfMonitorImp(this, name, stat_latency)
311a2cf152SYinan Xu}
321a2cf152SYinan Xu
33d2b20d1aSTang Haojinclass BusPerfMonitorImp(outer: BusPerfMonitor, name: String, stat_latency: Boolean)
341a2cf152SYinan Xu  extends LazyModuleImp(outer)
351a2cf152SYinan Xu{
3673be64b3SJiawei Lin
371a2cf152SYinan Xu  outer.node.in.zip(outer.node.out).foreach{
381a2cf152SYinan Xu    case ((in, edgeIn), (out, edgeOut)) =>
391a2cf152SYinan Xu      out <> in
401a2cf152SYinan Xu  }
411a2cf152SYinan Xu
421a2cf152SYinan Xu  def PERF_CHN[T <: TLChannel](clientName: String, chn: DecoupledIO[T]) = {
431a2cf152SYinan Xu
44d18dc7e6Swakafa    val channelName = chn.bits.channelName.replaceAll(" ", "_").replaceAll("'", "")
45d2b20d1aSTang Haojin    XSPerfAccumulate(s"${clientName}_${channelName}_fire", chn.fire)
46d18dc7e6Swakafa    XSPerfAccumulate(s"${clientName}_${channelName}_stall", chn.valid && !chn.ready)
471a2cf152SYinan Xu
481a2cf152SYinan Xu    val ops = chn.bits match {
491a2cf152SYinan Xu      case _: TLBundleA => TLMessages.a.map(_._1)
501a2cf152SYinan Xu      case _: TLBundleB => TLMessages.b.map(_._1)
511a2cf152SYinan Xu      case _: TLBundleC => TLMessages.c.map(_._1)
521a2cf152SYinan Xu      case _: TLBundleD => TLMessages.d.map(_._1)
531a2cf152SYinan Xu      case _: TLBundleE => Nil
541a2cf152SYinan Xu    }
55d18dc7e6Swakafa
56d18dc7e6Swakafa    for((op_raw, i) <- ops.zipWithIndex){
57d18dc7e6Swakafa      val op = s"${op_raw}".replaceAll(" ", "_")
581a2cf152SYinan Xu      chn.bits match {
591a2cf152SYinan Xu        case a: TLBundleA =>
60d18dc7e6Swakafa          XSPerfAccumulate(s"${clientName}_${channelName}_${op}_fire",
61d2b20d1aSTang Haojin            i.U === a.opcode && chn.fire
621a2cf152SYinan Xu          )
63d18dc7e6Swakafa          XSPerfAccumulate(s"${clientName}_${channelName}_${op}_stall",
641a2cf152SYinan Xu            i.U === a.opcode && chn.valid && !chn.ready
651a2cf152SYinan Xu          )
661a2cf152SYinan Xu        case b: TLBundleB =>
67d18dc7e6Swakafa          XSPerfAccumulate(s"${clientName}_${channelName}_${op}_fire",
68d2b20d1aSTang Haojin            i.U === b.opcode && chn.fire
691a2cf152SYinan Xu          )
70d18dc7e6Swakafa          XSPerfAccumulate(s"${clientName}_${channelName}_${op}_stall",
711a2cf152SYinan Xu            i.U === b.opcode && chn.valid && !chn.ready
721a2cf152SYinan Xu          )
731a2cf152SYinan Xu        case c: TLBundleC =>
74d18dc7e6Swakafa          XSPerfAccumulate(s"${clientName}_${channelName}_${op}_fire",
75d2b20d1aSTang Haojin            i.U === c.opcode && chn.fire
761a2cf152SYinan Xu          )
77d18dc7e6Swakafa          XSPerfAccumulate(s"${clientName}_${channelName}_${op}_stall",
781a2cf152SYinan Xu            i.U === c.opcode && chn.valid && !chn.ready
791a2cf152SYinan Xu          )
801a2cf152SYinan Xu        case d: TLBundleD =>
81d18dc7e6Swakafa          XSPerfAccumulate(s"${clientName}_${channelName}_${op}_fire",
82d2b20d1aSTang Haojin            i.U === d.opcode && chn.fire
831a2cf152SYinan Xu          )
84d18dc7e6Swakafa          XSPerfAccumulate(s"${clientName}_${channelName}_${op}_stall",
851a2cf152SYinan Xu            i.U === d.opcode && chn.valid && !chn.ready
861a2cf152SYinan Xu          )
87*7a96cc7fSHaojin Tang        case e: TLBundleE => throw new IllegalArgumentException("Cannot reach here")
881a2cf152SYinan Xu      }
891a2cf152SYinan Xu    }
901a2cf152SYinan Xu  }
911a2cf152SYinan Xu
921f0e2dc7SJiawei Lin  for (((in, edgeIn), i) <- outer.node.in.zipWithIndex) {
93d2b20d1aSTang Haojin    val clientName = s"${name}_${edgeIn.master.masters.head.name}_bank_$i"
941a2cf152SYinan Xu    PERF_CHN(clientName, in.a)
951a2cf152SYinan Xu    PERF_CHN(clientName, in.d)
961a2cf152SYinan Xu    if (in.params.hasBCE) {
971a2cf152SYinan Xu      PERF_CHN(clientName, in.b)
981a2cf152SYinan Xu      PERF_CHN(clientName, in.c)
991a2cf152SYinan Xu      PERF_CHN(clientName, in.e)
1001a2cf152SYinan Xu    }
1011a2cf152SYinan Xu  }
102d2b20d1aSTang Haojin
103d2b20d1aSTang Haojin  if (stat_latency) {
104d2b20d1aSTang Haojin    val nrEdge = outer.node.in.length.toInt
105d2b20d1aSTang Haojin    val edgeIn = outer.node.in.head._2
106d2b20d1aSTang Haojin
107d2b20d1aSTang Haojin    class RecordEntry()(implicit p: Parameters) extends Bundle {
108d2b20d1aSTang Haojin      val valid = Bool()
109d2b20d1aSTang Haojin      val timeStamp = UInt(64.W)
110d2b20d1aSTang Haojin      val reqType = UInt(8.W)
111d2b20d1aSTang Haojin    }
112d2b20d1aSTang Haojin
113d2b20d1aSTang Haojin    // For simplicity, latency statistic works between nodes with SINGLE edge
114d2b20d1aSTang Haojin    require(nrEdge == 1)
115d2b20d1aSTang Haojin    val timer = GTimer()
116d2b20d1aSTang Haojin    val nrSource = math.pow(2, edgeIn.bundle.sourceBits).toInt
117d2b20d1aSTang Haojin    val latencyRecord = RegInit(VecInit(Seq.fill(nrSource)(0.U.asTypeOf(new RecordEntry()))))
118d2b20d1aSTang Haojin    val latencySum = RegInit(0.U(128.W))
119d2b20d1aSTang Haojin    val nrRecord = RegInit(0.U(128.W))
120d2b20d1aSTang Haojin
121d2b20d1aSTang Haojin    outer.node.in.zip(outer.node.out).zipWithIndex.foreach {
122d2b20d1aSTang Haojin      case (((in, edgeIn), (out, edgeOut)), i) =>
123d2b20d1aSTang Haojin        val channelA = in.a
124d2b20d1aSTang Haojin        when(channelA.fire &&
125d2b20d1aSTang Haojin          channelA.bits.opcode =/= Hint &&
126d2b20d1aSTang Haojin          channelA.bits.opcode =/= PutFullData &&
127d2b20d1aSTang Haojin          channelA.bits.opcode =/= PutPartialData
128d2b20d1aSTang Haojin        ) {
129d2b20d1aSTang Haojin          // Valid channel A fire, record it
130d2b20d1aSTang Haojin          assert(latencyRecord(channelA.bits.source).valid === false.B)
131d2b20d1aSTang Haojin          latencyRecord(channelA.bits.source).valid := true.B
132d2b20d1aSTang Haojin          latencyRecord(channelA.bits.source).timeStamp := timer
133d2b20d1aSTang Haojin          latencyRecord(channelA.bits.source).reqType := channelA.bits.user.lift(ReqSourceKey).getOrElse(MemReqSource.NoWhere.id.U)
134d2b20d1aSTang Haojin        }
135d2b20d1aSTang Haojin        val channelD = in.d
136d2b20d1aSTang Haojin        val (first, _, _, _) = edgeIn.count(channelD)
137d2b20d1aSTang Haojin        // Valid channel D fire, resolve it
138d2b20d1aSTang Haojin        val resolveRecord = channelD.fire && first &&
139d2b20d1aSTang Haojin          channelD.bits.opcode =/= ReleaseAck &&
140d2b20d1aSTang Haojin          channelD.bits.opcode =/= AccessAck
141d2b20d1aSTang Haojin        val latency = WireInit(0.U(64.W))
142d2b20d1aSTang Haojin        when(resolveRecord) {
143d2b20d1aSTang Haojin          assert(latencyRecord(channelD.bits.source).valid === true.B)
144d2b20d1aSTang Haojin          latencyRecord(channelD.bits.source).valid := false.B
145d2b20d1aSTang Haojin          latency := timer - latencyRecord(channelD.bits.source).timeStamp
146d2b20d1aSTang Haojin          latencySum := latencySum + timer
147d2b20d1aSTang Haojin          nrRecord := nrRecord + 1.U
148d2b20d1aSTang Haojin          // printf("timer: %x\n", latency)
149d2b20d1aSTang Haojin        }
150d2b20d1aSTang Haojin        XSPerfAccumulate(name + "_nrRecord_all", resolveRecord)
151d2b20d1aSTang Haojin        XSPerfAccumulate(name + "_latencySum_all", Mux(resolveRecord, latency, 0.U))
152d2b20d1aSTang Haojin
153d2b20d1aSTang Haojin        for (j <- 0 until MemReqSource.ReqSourceCount.id) {
154d2b20d1aSTang Haojin          val typeMatch = latencyRecord(channelD.bits.source).reqType === j.U
155d2b20d1aSTang Haojin          XSPerfAccumulate(name + s"_nrRecord_type${j}", resolveRecord && typeMatch)
156d2b20d1aSTang Haojin          XSPerfAccumulate(name + s"_latencySum_type${j}", Mux(resolveRecord && typeMatch, latency, 0.U))
157d2b20d1aSTang Haojin        }
158d2b20d1aSTang Haojin    }
159d2b20d1aSTang Haojin  }
160d2b20d1aSTang Haojin
1611a2cf152SYinan Xu}
1621a2cf152SYinan Xu
1631a2cf152SYinan Xuobject BusPerfMonitor {
164d2b20d1aSTang Haojin  def apply(
165d2b20d1aSTang Haojin     name: String,
166d2b20d1aSTang Haojin     enable: Boolean = false,
167d2b20d1aSTang Haojin     stat_latency: Boolean = false,
168d2b20d1aSTang Haojin     add_reqkey: Boolean = false)(implicit p: Parameters) =
169d2b20d1aSTang Haojin  {
17073be64b3SJiawei Lin    if(enable){
1716695f071SYinan Xu      val busPMU = LazyModule(new BusPerfMonitor(name, stat_latency))
1721a2cf152SYinan Xu      busPMU.node
17373be64b3SJiawei Lin    } else {
17473be64b3SJiawei Lin      TLTempNode()
17573be64b3SJiawei Lin    }
1761a2cf152SYinan Xu  }
1771a2cf152SYinan Xu}
178