changeset 09deddf4e447 in /z/repo/gem5
details: http://repo.gem5.org/gem5?cmd=changeset;node=09deddf4e447
description:
mem: Add basic stats to the buses
This patch adds a basic set of stats which are hard to impossible to
implement using only communication monitors, and are needed for
insight such as bus utilization, transactions through the bus etc.
Stats added include throughput and transaction distribution, and also
a two-dimensional vector capturing how many packets and how much data
is exchanged between the masters and slaves connected to the bus.
diffstat:
src/mem/bus.cc | 69 ++++++++++++++++++++++++++++
src/mem/bus.hh | 30 ++++++++++++
src/mem/coherent_bus.cc | 110 ++++++++++++++++++++++++++++++++++++++++----
src/mem/coherent_bus.hh | 5 ++
src/mem/noncoherent_bus.cc | 65 ++++++++++++++++++++++++--
src/mem/noncoherent_bus.hh | 5 ++
6 files changed, 266 insertions(+), 18 deletions(-)
diffs (truncated from 593 to 300 lines):
diff -r d98f85e25441 -r 09deddf4e447 src/mem/bus.cc
--- a/src/mem/bus.cc Thu May 30 12:53:57 2013 -0400
+++ b/src/mem/bus.cc Thu May 30 12:53:58 2013 -0400
@@ -179,6 +179,9 @@
assert(until != 0);
bus.schedule(releaseEvent, until);
+ // account for the occupied ticks
+ occupancy += until - curTick();
+
DPRINTF(BaseBus, "The bus is now busy from tick %d to %d\n",
curTick(), until);
}
@@ -558,6 +561,52 @@
return blockSize;
}
+void
+BaseBus::regStats()
+{
+ using namespace Stats;
+
+ transDist
+ .init(MemCmd::NUM_MEM_CMDS)
+ .name(name() + ".trans_dist")
+ .desc("Transaction distribution")
+ .flags(nozero);
+
+ // get the string representation of the commands
+ for (int i = 0; i < MemCmd::NUM_MEM_CMDS; i++) {
+ MemCmd cmd(i);
+ const std::string &cstr = cmd.toString();
+ transDist.subname(i, cstr);
+ }
+
+ pktCount
+ .init(slavePorts.size(), masterPorts.size())
+ .name(name() + ".pkt_count")
+ .desc("Packet count per connected master and slave (bytes)")
+ .flags(total | nozero | nonan);
+
+ totPktSize
+ .init(slavePorts.size(), masterPorts.size())
+ .name(name() + ".tot_pkt_size")
+ .desc("Cumulative packet size per connected master and slave (bytes)")
+ .flags(total | nozero | nonan);
+
+ // both the packet count and total size are two-dimensional
+ // vectors, indexed by slave port id and master port id, thus the
+ // neighbouring master and slave, they do not differentiate what
+ // came from the master and was forwarded to the slave (requests
+ // and snoop responses) and what came from the slave and was
+ // forwarded to the master (responses and snoop requests)
+ for (int i = 0; i < slavePorts.size(); i++) {
+ pktCount.subname(i, slavePorts[i]->getMasterPort().name());
+ totPktSize.subname(i, slavePorts[i]->getMasterPort().name());
+ for (int j = 0; j < masterPorts.size(); j++) {
+ pktCount.ysubname(j, masterPorts[j]->getSlavePort().name());
+ totPktSize.ysubname(j, masterPorts[j]->getSlavePort().name());
+ }
+ }
+}
+
template <typename PortClass>
unsigned int
BaseBus::Layer<PortClass>::drain(DrainManager *dm)
@@ -573,6 +622,26 @@
return 0;
}
+template <typename PortClass>
+void
+BaseBus::Layer<PortClass>::regStats()
+{
+ using namespace Stats;
+
+ occupancy
+ .name(name() + ".occupancy")
+ .desc("Layer occupancy (ticks)")
+ .flags(nozero);
+
+ utilization
+ .name(name() + ".utilization")
+ .desc("Layer utilization (%)")
+ .precision(1)
+ .flags(nozero);
+
+ utilization = 100 * occupancy / simTicks;
+}
+
/**
* Bus layer template instantiations. Could be removed with _impl.hh
* file, but since there are only two given options (MasterPort and
diff -r d98f85e25441 -r 09deddf4e447 src/mem/bus.hh
--- a/src/mem/bus.hh Thu May 30 12:53:57 2013 -0400
+++ b/src/mem/bus.hh Thu May 30 12:53:58 2013 -0400
@@ -57,6 +57,7 @@
#include "base/types.hh"
#include "mem/mem_object.hh"
#include "params/BaseBus.hh"
+#include "sim/stats.hh"
/**
* The base bus contains the common elements of the non-coherent and
@@ -179,6 +180,11 @@
*/
void recvRetry(PortID port_id);
+ /**
+ * Register stats for the layer
+ */
+ void regStats();
+
private:
/** The bus this layer is a part of. */
@@ -246,6 +252,14 @@
/** event used to schedule a release of the layer */
EventWrapper<Layer, &Layer::releaseLayer> releaseEvent;
+ /**
+ * Stats for occupancy and utilization. These stats capture
+ * the time the bus spends in the busy state and are thus only
+ * relevant when the memory system is in timing mode.
+ */
+ Stats::Scalar occupancy;
+ Stats::Formula utilization;
+
};
/** cycles of overhead per transaction */
@@ -381,6 +395,20 @@
virtual ~BaseBus();
+ /**
+ * Stats for transaction distribution and data passing through the
+ * bus. The transaction distribution is globally counting
+ * different types of commands. The packet count and total packet
+ * size are two-dimensional vectors that are indexed by the bus
+ * slave port and master port id (thus the neighbouring master and
+ * neighbouring slave), summing up both directions (request and
+ * response).
+ */
+ Stats::Formula throughput;
+ Stats::Vector transDist;
+ Stats::Vector2d pktCount;
+ Stats::Vector2d totPktSize;
+
public:
virtual void init();
@@ -393,6 +421,8 @@
virtual unsigned int drain(DrainManager *dm) = 0;
+ virtual void regStats();
+
};
#endif //__MEM_BUS_HH__
diff -r d98f85e25441 -r 09deddf4e447 src/mem/coherent_bus.cc
--- a/src/mem/coherent_bus.cc Thu May 30 12:53:57 2013 -0400
+++ b/src/mem/coherent_bus.cc Thu May 30 12:53:58 2013 -0400
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2011-2012 ARM Limited
+ * Copyright (c) 2011-2013 ARM Limited
* All rights reserved
*
* The license below extends only to copyright in the software and shall
@@ -125,11 +125,11 @@
bool is_express_snoop = pkt->isExpressSnoop();
// determine the destination based on the address
- PortID dest_port_id = findPort(pkt->getAddr());
+ PortID master_port_id = findPort(pkt->getAddr());
// test if the bus should be considered occupied for the current
// port, and exclude express snoops from the check
- if (!is_express_snoop && !reqLayer.tryTiming(src_port, dest_port_id)) {
+ if (!is_express_snoop && !reqLayer.tryTiming(src_port, master_port_id)) {
DPRINTF(CoherentBus, "recvTimingReq: src %s %s 0x%x BUS BUSY\n",
src_port->name(), pkt->cmdString(), pkt->getAddr());
return false;
@@ -139,6 +139,11 @@
src_port->name(), pkt->cmdString(), is_express_snoop,
pkt->getAddr());
+ // store size and command as they might be modified when
+ // forwarding the packet
+ unsigned int pkt_size = pkt->hasData() ? pkt->getSize() : 0;
+ unsigned int pkt_cmd = pkt->cmdToIndex();
+
// set the source port for routing of the response
pkt->setSrc(slave_port_id);
@@ -169,11 +174,12 @@
}
// since it is a normal request, attempt to send the packet
- bool success = masterPorts[dest_port_id]->sendTimingReq(pkt);
+ bool success = masterPorts[master_port_id]->sendTimingReq(pkt);
// if this is an express snoop, we are done at this point
if (is_express_snoop) {
assert(success);
+ snoopDataThroughBus += pkt_size;
} else {
// for normal requests, check if successful
if (!success) {
@@ -192,14 +198,22 @@
src_port->name(), pkt->cmdString(), pkt->getAddr());
// update the bus state and schedule an idle event
- reqLayer.failedTiming(src_port, dest_port_id,
+ reqLayer.failedTiming(src_port, master_port_id,
clockEdge(Cycles(headerCycles)));
} else {
// update the bus state and schedule an idle event
reqLayer.succeededTiming(packetFinishTime);
+ dataThroughBus += pkt_size;
}
}
+ // stats updates only consider packets that were successfully sent
+ if (success) {
+ pktCount[slave_port_id][master_port_id]++;
+ totPktSize[slave_port_id][master_port_id] += pkt_size;
+ transDist[pkt_cmd]++;
+ }
+
return success;
}
@@ -220,6 +234,11 @@
DPRINTF(CoherentBus, "recvTimingResp: src %s %s 0x%x\n",
src_port->name(), pkt->cmdString(), pkt->getAddr());
+ // store size and command as they might be modified when
+ // forwarding the packet
+ unsigned int pkt_size = pkt->hasData() ? pkt->getSize() : 0;
+ unsigned int pkt_cmd = pkt->cmdToIndex();
+
calcPacketTiming(pkt);
Tick packetFinishTime = pkt->busLastWordDelay + curTick();
@@ -230,9 +249,11 @@
// remove it as outstanding
outstandingReq.erase(pkt->req);
- // send the packet to the destination through one of our slave
- // ports, as determined by the destination field
- bool success M5_VAR_USED = slavePorts[pkt->getDest()]->sendTimingResp(pkt);
+ // determine the destination based on what is stored in the packet
+ PortID slave_port_id = pkt->getDest();
+
+ // send the packet through the destination slave port
+ bool success M5_VAR_USED = slavePorts[slave_port_id]->sendTimingResp(pkt);
// currently it is illegal to block responses... can lead to
// deadlock
@@ -240,6 +261,12 @@
respLayer.succeededTiming(packetFinishTime);
+ // stats updates
+ dataThroughBus += pkt_size;
+ pktCount[slave_port_id][master_port_id]++;
+ totPktSize[slave_port_id][master_port_id] += pkt_size;
+ transDist[pkt_cmd]++;
+
return true;
}
@@ -250,6 +277,10 @@
masterPorts[master_port_id]->name(), pkt->cmdString(),
pkt->getAddr());
+ // update stats here as we know the forwarding will succeed
+ transDist[pkt->cmdToIndex()]++;
+ snoopDataThroughBus += pkt->hasData() ? pkt->getSize() : 0;
+
// we should only see express snoops from caches
assert(pkt->isExpressSnoop());
@@ -286,8 +317,13 @@
DPRINTF(CoherentBus, "recvTimingSnoop: src %s %s 0x%x\n",
src_port->name(), pkt->cmdString(), pkt->getAddr());
+ // store size and command as they might be modified when
+ // forwarding the packet
+ unsigned int pkt_size = pkt->hasData() ? pkt->getSize() : 0;
+ unsigned int pkt_cmd = pkt->cmdToIndex();
+
// get the destination from the packet
- PortID dest = pkt->getDest();
+ PortID dest_port_id = pkt->getDest();
// responses are never express snoops
_______________________________________________
gem5-dev mailing list
[email protected]
http://m5sim.org/mailman/listinfo/gem5-dev