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);
}
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)
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
#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
*/
void recvRetry(PortID port_id);
+ /**
+ * Register stats for the layer
+ */
+ void regStats();
+
private:
/** The bus this layer is a part of. */
/** 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 */
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();
virtual unsigned int drain(DrainManager *dm) = 0;
+ virtual void regStats();
+
};
#endif //__MEM_BUS_HH__
/*
- * 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
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;
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);
}
// 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) {
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;
}
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();
// 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
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;
}
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());
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
assert(!pkt->isExpressSnoop());
// this is a snoop response to a snoop request we
// forwarded, e.g. coming from the L1 and going to the L2
// this should be forwarded as a snoop response
- bool success M5_VAR_USED = masterPorts[dest]->sendTimingSnoopResp(pkt);
+ bool success M5_VAR_USED =
+ masterPorts[dest_port_id]->sendTimingSnoopResp(pkt);
+ pktCount[slave_port_id][dest_port_id]++;
+ totPktSize[slave_port_id][dest_port_id] += pkt_size;
assert(success);
} else {
// we got a snoop response on one of our slave ports,
// request, hence it should never go back to where the
// snoop response came from, but instead to where the
// original request came from
- assert(slave_port_id != dest);
+ assert(slave_port_id != dest_port_id);
// as a normal response, it should go back to a master
// through one of our slave ports
- bool success M5_VAR_USED = slavePorts[dest]->sendTimingResp(pkt);
+ bool success M5_VAR_USED =
+ slavePorts[dest_port_id]->sendTimingResp(pkt);
// currently it is illegal to block responses... can lead
// to deadlock
snoopRespLayer.succeededTiming(packetFinishTime);
+ // stats updates
+ transDist[pkt_cmd]++;
+ snoopDataThroughBus += pkt_size;
+
return true;
}
slavePorts[slave_port_id]->name(), pkt->getAddr(),
pkt->cmdString());
+ // add the request data
+ dataThroughBus += pkt->hasData() ? pkt->getSize() : 0;
+
MemCmd snoop_response_cmd = MemCmd::InvalidCmd;
Tick snoop_response_latency = 0;
response_latency = snoop_response_latency;
}
+ // add the response data
+ if (pkt->isResponse())
+ dataThroughBus += pkt->hasData() ? pkt->getSize() : 0;
+
// @todo: Not setting first-word time
pkt->busLastWordDelay = response_latency;
return response_latency;
masterPorts[master_port_id]->name(), pkt->getAddr(),
pkt->cmdString());
+ // add the request snoop data
+ snoopDataThroughBus += pkt->hasData() ? pkt->getSize() : 0;
+
// forward to all snoopers
std::pair<MemCmd, Tick> snoop_result =
forwardAtomic(pkt, InvalidPortID);
if (snoop_response_cmd != MemCmd::InvalidCmd)
pkt->cmd = snoop_response_cmd;
+ // add the response snoop data
+ if (pkt->isResponse())
+ snoopDataThroughBus += pkt->hasData() ? pkt->getSize() : 0;
+
// @todo: Not setting first-word time
pkt->busLastWordDelay = snoop_response_latency;
return snoop_response_latency;
return reqLayer.drain(dm) + respLayer.drain(dm) + snoopRespLayer.drain(dm);
}
+void
+CoherentBus::regStats()
+{
+ // register the stats of the base class and our three bus layers
+ BaseBus::regStats();
+ reqLayer.regStats();
+ respLayer.regStats();
+ snoopRespLayer.regStats();
+
+ dataThroughBus
+ .name(name() + ".data_through_bus")
+ .desc("Total data (bytes)")
+ ;
+
+ snoopDataThroughBus
+ .name(name() + ".snoop_data_through_bus")
+ .desc("Total snoop data (bytes)")
+ ;
+
+ throughput
+ .name(name() + ".throughput")
+ .desc("Throughput (bytes/s)")
+ .precision(0)
+ ;
+
+ throughput = (dataThroughBus + snoopDataThroughBus) / simSeconds;
+}
+
CoherentBus *
CoherentBusParams::create()
{
*/
void forwardFunctional(PacketPtr pkt, PortID exclude_slave_port_id);
+ Stats::Scalar dataThroughBus;
+ Stats::Scalar snoopDataThroughBus;
+
public:
virtual void init();
CoherentBus(const CoherentBusParams *p);
unsigned int drain(DrainManager *dm);
+
+ virtual void regStats();
};
#endif //__MEM_COHERENT_BUS_HH__
assert(!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
- if (!reqLayer.tryTiming(src_port, dest_port_id)) {
+ if (!reqLayer.tryTiming(src_port, master_port_id)) {
DPRINTF(NoncoherentBus, "recvTimingReq: src %s %s 0x%x BUSY\n",
src_port->name(), pkt->cmdString(), pkt->getAddr());
return false;
DPRINTF(NoncoherentBus, "recvTimingReq: 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();
+
// set the source port for routing of the response
pkt->setSrc(slave_port_id);
Tick packetFinishTime = pkt->busLastWordDelay + curTick();
// 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 (!success) {
// inhibited packets should never be forced to retry
pkt->busFirstWordDelay = pkt->busLastWordDelay = 0;
// occupy until the header is sent
- reqLayer.failedTiming(src_port, dest_port_id,
+ reqLayer.failedTiming(src_port, master_port_id,
clockEdge(Cycles(headerCycles)));
return false;
reqLayer.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;
}
DPRINTF(NoncoherentBus, "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();
- // send the packet to the destination through one of our slave
- // ports, as determined by the destination field
+ // 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[pkt->getDest()]->sendTimingResp(pkt);
// currently it is illegal to block responses... can lead to
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;
}
slavePorts[slave_port_id]->name(), pkt->getAddr(),
pkt->cmdString());
+ // add the request data
+ dataThroughBus += pkt->hasData() ? pkt->getSize() : 0;
+
// determine the destination port
PortID dest_id = findPort(pkt->getAddr());
// forward the request to the appropriate destination
Tick response_latency = masterPorts[dest_id]->sendAtomic(pkt);
+ // add the response data
+ if (pkt->isResponse())
+ dataThroughBus += pkt->hasData() ? pkt->getSize() : 0;
+
// @todo: Not setting first-word time
pkt->busLastWordDelay = response_latency;
return response_latency;
{
return new NoncoherentBus(this);
}
+
+void
+NoncoherentBus::regStats()
+{
+ // register the stats of the base class and our two bus layers
+ BaseBus::regStats();
+ reqLayer.regStats();
+ respLayer.regStats();
+
+ dataThroughBus
+ .name(name() + ".data_through_bus")
+ .desc("Total data (bytes)")
+ ;
+
+ throughput
+ .name(name() + ".throughput")
+ .desc("Throughput (bytes/s)")
+ .precision(0)
+ ;
+
+ throughput = dataThroughBus / simSeconds;
+}
unsigned int drain(DrainManager *dm);
+ /**
+ * stats
+ */
+ virtual void regStats();
+ Stats::Scalar dataThroughBus;
};
#endif //__MEM_NONCOHERENT_BUS_HH__