/*
- * Copyright (c) 2012-2013, 2016-2018 ARM Limited
+ * Copyright (c) 2012-2013, 2016-2019 ARM Limited
* All rights reserved
*
* The license below extends only to copyright in the software and shall
noProgressEvent([this]{ noProgress(); }, name()),
nextTransitionTick(0),
nextPacketTick(0),
+ maxOutstandingReqs(p->max_outstanding_reqs),
port(name() + ".port", *this),
retryPkt(NULL),
- retryPktTick(0),
+ retryPktTick(0), blockedWaitingResp(false),
updateEvent([this]{ update(); }, name()),
masterID(system->getMasterId(this)),
streamGenerator(StreamGen::create(p))
// device accesses that could be part of a trace
if (pkt && system->isMemAddr(pkt->getAddr())) {
numPackets++;
- if (!port.sendTimingReq(pkt)) {
+ // Only attempts to send if not blocked by pending responses
+ blockedWaitingResp = allocateWaitingRespSlot(pkt);
+ if (blockedWaitingResp || !port.sendTimingReq(pkt)) {
retryPkt = pkt;
retryPktTick = curTick();
}
}
}
- // if we are waiting for a retry, do not schedule any further
- // events, in the case of a transition or a successful send, go
+ // if we are waiting for a retry or for a response, do not schedule any
+ // further events, in the case of a transition or a successful send, go
// ahead and determine when the next update should take place
if (retryPkt == NULL) {
nextPacketTick = activeGenerator->nextPacketTick(elasticReq, 0);
void
BaseTrafficGen::recvReqRetry()
{
- assert(retryPkt != NULL);
-
DPRINTF(TrafficGen, "Received retry\n");
numRetries++;
+ retryReq();
+}
+
+void
+BaseTrafficGen::retryReq()
+{
+ assert(retryPkt != NULL);
+ assert(retryPktTick != 0);
+ assert(!blockedWaitingResp);
+
// attempt to send the packet, and if we are successful start up
// the machinery again
if (port.sendTimingReq(retryPkt)) {
}
bool
-BaseTrafficGen::TrafficGenPort::recvTimingResp(PacketPtr pkt)
+BaseTrafficGen::recvTimingResp(PacketPtr pkt)
{
+ auto iter = waitingResp.find(pkt->req);
+
+ panic_if(iter == waitingResp.end(), "%s: "
+ "Received unexpected response [%s reqPtr=%x]\n",
+ pkt->print(), pkt->req);
+
+ assert(iter->second <= curTick());
+
+ waitingResp.erase(iter);
+
delete pkt;
+ // Sends up the request if we were blocked
+ if (blockedWaitingResp) {
+ blockedWaitingResp = false;
+ retryReq();
+ }
+
return true;
}
/*
- * Copyright (c) 2012-2013, 2016-2018 ARM Limited
+ * Copyright (c) 2012-2013, 2016-2019 ARM Limited
* All rights reserved
*
* The license below extends only to copyright in the software and shall
#include <memory>
#include <tuple>
+#include <unordered_map>
#include "base/statistics.hh"
#include "mem/qport.hh"
*/
void recvReqRetry();
+ void retryReq();
+
+ bool recvTimingResp(PacketPtr pkt);
+
/** Transition to the next generator */
void transition();
/** Time of the next packet. */
Tick nextPacketTick;
+ const int maxOutstandingReqs;
+
/** Master port specialisation for the traffic generator */
class TrafficGenPort : public MasterPort
void recvReqRetry() { trafficGen.recvReqRetry(); }
- bool recvTimingResp(PacketPtr pkt);
+ bool recvTimingResp(PacketPtr pkt)
+ { return trafficGen.recvTimingResp(pkt); }
void recvTimingSnoopReq(PacketPtr pkt) { }
/** Tick when the stalled packet was meant to be sent. */
Tick retryPktTick;
+ /** Set when we blocked waiting for outstanding reqs */
+ bool blockedWaitingResp;
+
+ /**
+ * Puts this packet in the waitingResp list and returns true if
+ * we are above the maximum number of oustanding requests.
+ */
+ bool allocateWaitingRespSlot(PacketPtr pkt)
+ {
+ assert(waitingResp.find(pkt->req) == waitingResp.end());
+ assert(pkt->needsResponse());
+
+ waitingResp[pkt->req] = curTick();
+
+ return (maxOutstandingReqs > 0) &&
+ (waitingResp.size() > maxOutstandingReqs);
+ }
+
/** Event for scheduling updates */
EventFunctionWrapper updateEvent;
/** Count the time incurred from back-pressure. */
Stats::Scalar retryTicks;
+ /** Reqs waiting for response **/
+ std::unordered_map<RequestPtr,Tick> waitingResp;
+
public:
BaseTrafficGen(const BaseTrafficGenParams* p);