// increment the address
nextAddr += blocksize;
- return pkt;
-}
-
-Tick
-LinearGen::nextPacketTick()
-{
// If we have reached the end of the address space, reset the
// address to the start of the range
- if (nextAddr + blocksize > endAddr) {
+ if (nextAddr > endAddr) {
DPRINTF(TrafficGen, "Wrapping address to the start of "
"the range\n");
nextAddr = startAddr;
}
+ return pkt;
+}
+
+Tick
+LinearGen::nextPacketTick() const
+{
// Check to see if we have reached the data limit. If dataLimit is
// zero we do not have a data limit and therefore we will keep
// generating requests for the entire residency in this state.
}
Tick
-RandomGen::nextPacketTick()
+RandomGen::nextPacketTick() const
{
// Check to see if we have reached the data limit. If dataLimit is
// zero we do not have a data limit and therefore we will keep
}
Tick
-TraceGen::nextPacketTick() {
- if (traceComplete)
+TraceGen::nextPacketTick() const
+{
+ if (traceComplete) {
+ DPRINTF(TrafficGen, "No next tick as trace is finished\n");
// We are at the end of the file, thus we have no more data in
// the trace Return MaxTick to signal that there will be no
// more transactions in this active period for the state.
return MaxTick;
-
-
- //Reset the nextElement to the default values
- currElement = nextElement;
- nextElement.clear();
-
- // We need to look at the next line to calculate the next time an
- // event occurs, or potentially return MaxTick to signal that
- // nothing has to be done.
- if (!trace.read(nextElement)) {
- traceComplete = true;
- return MaxTick;
}
- DPRINTF(TrafficGen, "currElement: %c addr %d size %d tick %d (%d)\n",
- currElement.cmd.isRead() ? 'r' : 'w',
- currElement.addr,
- currElement.blocksize,
- currElement.tick + tickOffset,
- currElement.tick);
-
- DPRINTF(TrafficGen, "nextElement: %c addr %d size %d tick %d (%d)\n",
- nextElement.cmd.isRead() ? 'r' : 'w',
- nextElement.addr,
- nextElement.blocksize,
- nextElement.tick + tickOffset,
+ assert(nextElement.isValid());
+
+ DPRINTF(TrafficGen, "Next packet tick is %d\n", tickOffset +
nextElement.tick);
return tickOffset + nextElement.tick;
tickOffset = curTick();
// clear everything
- nextElement.clear();
currElement.clear();
- traceComplete = false;
+ // read the first element in the file and set the complete flag
+ traceComplete = !trace.read(nextElement);
}
PacketPtr
TraceGen::getNextPacket()
{
- // it is the responsibility of nextPacketTick to prevent the
- // state graph from executing the state if it should not
+ // shift things one step forward
+ currElement = nextElement;
+ nextElement.clear();
+
+ // read the next element and set the complete flag
+ traceComplete = !trace.read(nextElement);
+
+ // it is the responsibility of the traceComplete flag to ensure we
+ // always have a valid element here
assert(currElement.isValid());
DPRINTF(TrafficGen, "TraceGen::getNextPacket: %c %d %d %d 0x%x\n",
currElement.tick,
currElement.flags);
- return getPacket(currElement.addr + addrOffset, currElement.blocksize,
- currElement.cmd, currElement.flags);
+ PacketPtr pkt = getPacket(currElement.addr + addrOffset,
+ currElement.blocksize,
+ currElement.cmd, currElement.flags);
+
+ if (!traceComplete)
+ DPRINTF(TrafficGen, "nextElement: %c addr %d size %d tick %d (%d)\n",
+ nextElement.cmd.isRead() ? 'r' : 'w',
+ nextElement.addr,
+ nextElement.blocksize,
+ nextElement.tick + tickOffset,
+ nextElement.tick);
+
+ return pkt;
}
void
*
* @return next tick when a packet is available
*/
- virtual Tick nextPacketTick() = 0;
+ virtual Tick nextPacketTick() const = 0;
};
PacketPtr getNextPacket() { return NULL; }
- Tick nextPacketTick() { return MaxTick; }
+ Tick nextPacketTick() const { return MaxTick; }
};
/**
PacketPtr getNextPacket();
- Tick nextPacketTick();
+ Tick nextPacketTick() const;
private:
PacketPtr getNextPacket();
- Tick nextPacketTick();
+ Tick nextPacketTick() const;
private:
void exit();
/**
- * Read a line of the trace file. Returns the raw tick
- * when the next request should be generated. If the end
- * of the file has been reached, it returns MaxTick to
+ * Returns the tick when the next request should be generated. If
+ * the end of the file has been reached, it returns MaxTick to
* indicate that there will be no more requests.
*/
- Tick nextPacketTick();
+ Tick nextPacketTick() const;
private:
masterID(system->getMasterId(name())),
configFile(p->config_file),
nextTransitionTick(0),
+ nextPacketTick(0),
port(name() + ".port", *this),
- updateEvent(this)
+ retryPkt(NULL),
+ retryPktTick(0),
+ updateEvent(this),
+ drainManager(NULL)
{
}
{
// when not restoring from a checkpoint, make sure we kick things off
if (system->isTimingMode()) {
- schedule(updateEvent, nextEventTick());
+ // call nextPacketTick on the state to advance it
+ nextPacketTick = states[currState]->nextPacketTick();
+ schedule(updateEvent, std::min(nextPacketTick, nextTransitionTick));
} else {
DPRINTF(TrafficGen,
"Traffic generator is only active in timing mode\n");
unsigned int
TrafficGen::drain(DrainManager *dm)
{
- // @todo we should also stop putting new requests in the queue and
- // either interrupt the current state or wait for a transition
- return port.drain(dm);
+ if (retryPkt == NULL) {
+ // shut things down
+ nextPacketTick = MaxTick;
+ nextTransitionTick = MaxTick;
+ deschedule(updateEvent);
+ return 0;
+ } else {
+ drainManager = dm;
+ return 1;
+ }
}
void
DPRINTF(Checkpoint, "Serializing TrafficGen\n");
// save ticks of the graph event if it is scheduled
- Tick nextEvent = updateEvent.scheduled() ?
- updateEvent.when() : 0;
+ Tick nextEvent = updateEvent.scheduled() ? updateEvent.when() : 0;
- DPRINTF(TrafficGen, "Saving nextEvent=%llu\n",
- nextEvent);
+ DPRINTF(TrafficGen, "Saving nextEvent=%llu\n", nextEvent);
SERIALIZE_SCALAR(nextEvent);
SERIALIZE_SCALAR(nextTransitionTick);
- // @todo: also serialise the current state, figure out the best
- // way to drain and restore
+ SERIALIZE_SCALAR(nextPacketTick);
+
+ SERIALIZE_SCALAR(currState);
}
void
}
UNSERIALIZE_SCALAR(nextTransitionTick);
+
+ UNSERIALIZE_SCALAR(nextPacketTick);
+
+ // @todo In the case of a stateful generator state such as the
+ // trace player we would also have to restore the position in the
+ // trace playback
+ UNSERIALIZE_SCALAR(currState);
}
void
TrafficGen::update()
{
- // schedule next update event based on either the next execute
- // tick or the next transition, which ever comes first
- Tick nextEvent = nextEventTick();
- DPRINTF(TrafficGen, "Updating state graph, next event at %lld\n",
- nextEvent);
- schedule(updateEvent, nextEvent);
-
- // perform the update associated with the current update event
-
// if we have reached the time for the next state transition, then
// perform the transition
if (curTick() >= nextTransitionTick) {
transition();
} else {
- // we are still in the current state and should execute it
+ assert(curTick() >= nextPacketTick);
+ // get the next packet and try to send it
PacketPtr pkt = states[currState]->getNextPacket();
- port.schedTimingReq(pkt, curTick());
+ numPackets++;
+ if (!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
+ // ahead and determine when the next update should take place
+ if (retryPkt == NULL) {
+ // schedule next update event based on either the next execute
+ // tick or the next transition, which ever comes first
+ nextPacketTick = states[currState]->nextPacketTick();
+ Tick nextEventTick = std::min(nextPacketTick, nextTransitionTick);
+ DPRINTF(TrafficGen, "Next event scheduled at %lld\n", nextEventTick);
+ schedule(updateEvent, nextEventTick);
}
}
DPRINTF(TrafficGen, "Transition to state %d\n", newState);
currState = newState;
- nextTransitionTick += states[currState]->duration;
+ // we could have been delayed and not transitioned on the exact
+ // tick when we were supposed to (due to back pressure when
+ // sending a packet)
+ nextTransitionTick = curTick() + states[currState]->duration;
states[currState]->enter();
}
+void
+TrafficGen::recvRetry()
+{
+ assert(retryPkt != NULL);
+
+ DPRINTF(TrafficGen, "Received retry\n");
+ numRetries++;
+ // attempt to send the packet, and if we are successful start up
+ // the machinery again
+ if (port.sendTimingReq(retryPkt)) {
+ retryPkt = NULL;
+ // remember how much delay was incurred due to back-pressure
+ // when sending the request
+ Tick delay = curTick() - retryPktTick;
+ retryPktTick = 0;
+ retryTicks += delay;
+
+ if (drainManager == NULL) {
+ // packet is sent, so find out when the next one is due
+ nextPacketTick = states[currState]->nextPacketTick();
+ Tick nextEventTick = std::min(nextPacketTick, nextTransitionTick);
+ schedule(updateEvent, std::max(curTick(), nextEventTick));
+ } else {
+ // shut things down
+ nextPacketTick = MaxTick;
+ nextTransitionTick = MaxTick;
+ drainManager->signalDrainDone();
+ // Clear the drain event once we're done with it.
+ drainManager = NULL;
+ }
+ }
+}
+
+void
+TrafficGen::regStats()
+{
+ // Initialise all the stats
+ using namespace Stats;
+
+ numPackets
+ .name(name() + ".numPackets")
+ .desc("Number of packets generated");
+
+ numRetries
+ .name(name() + ".numRetries")
+ .desc("Number of retries");
+
+ retryTicks
+ .name(name() + ".retryTicks")
+ .desc("Time spent waiting due to back-pressure (ticks)");
+}
+
bool
TrafficGen::TrafficGenPort::recvTimingResp(PacketPtr pkt)
{
#define __CPU_TRAFFIC_GEN_TRAFFIC_GEN_HH__
#include "base/hashmap.hh"
+#include "base/statistics.hh"
#include "cpu/testers/traffic_gen/generators.hh"
#include "mem/mem_object.hh"
#include "mem/qport.hh"
*/
void enterState(uint32_t newState);
- /**
- * Get the tick of the next event, either a new packet or a
- * transition.
- *
- * @return tick of the next update event
- */
- Tick nextEventTick()
- {
- return std::min(states[currState]->nextPacketTick(),
- nextTransitionTick);
- }
-
/**
* Parse the config file and build the state map and
* transition matrix.
*/
void update();
+ /**
+ * Receive a retry from the neighbouring port and attempt to
+ * resend the waiting packet.
+ */
+ void recvRetry();
+
/** Struct to represent a probabilistic transition during parsing. */
struct Transition {
uint32_t from;
/** Time of next transition */
Tick nextTransitionTick;
+ /** Time of the next packet. */
+ Tick nextPacketTick;
+
/** State transition matrix */
std::vector<std::vector<double> > transitionMatrix;
/** Map of generator states */
m5::hash_map<uint32_t, BaseGen*> states;
- /** Queued master port */
- class TrafficGenPort : public QueuedMasterPort
+ /** Master port specialisation for the traffic generator */
+ class TrafficGenPort : public MasterPort
{
public:
- TrafficGenPort(const std::string& name, TrafficGen& _owner)
- : QueuedMasterPort(name, &_owner, queue), queue(_owner, *this)
+ TrafficGenPort(const std::string& name, TrafficGen& traffic_gen)
+ : MasterPort(name, &traffic_gen), trafficGen(traffic_gen)
{ }
protected:
+ void recvRetry() { trafficGen.recvRetry(); }
+
bool recvTimingResp(PacketPtr pkt);
private:
- MasterPacketQueue queue;
+ TrafficGen& trafficGen;
};
/** The instance of master port used by the traffic generator. */
TrafficGenPort port;
+ /** Packet waiting to be sent. */
+ PacketPtr retryPkt;
+
+ /** Tick when the stalled packet was meant to be sent. */
+ Tick retryPktTick;
+
/** Event for scheduling updates */
EventWrapper<TrafficGen, &TrafficGen::update> updateEvent;
+ /** Manager to signal when drained */
+ DrainManager* drainManager;
+
+ /** Count the number of generated packets. */
+ Stats::Scalar numPackets;
+
+ /** Count the number of retries. */
+ Stats::Scalar numRetries;
+
+ /** Count the time incurred from back-pressure. */
+ Stats::Scalar retryTicks;
public:
void unserialize(Checkpoint* cp, const std::string& section);
+ /** Register statistics */
+ void regStats();
+
};
#endif //__CPU_TRAFFIC_GEN_TRAFFIC_GEN_HH__