diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/cpu/testers/traffic_gen/generators.cc | 79 | ||||
-rw-r--r-- | src/cpu/testers/traffic_gen/generators.hh | 15 | ||||
-rw-r--r-- | src/cpu/testers/traffic_gen/traffic_gen.cc | 128 | ||||
-rw-r--r-- | src/cpu/testers/traffic_gen/traffic_gen.hh | 54 |
4 files changed, 188 insertions, 88 deletions
diff --git a/src/cpu/testers/traffic_gen/generators.cc b/src/cpu/testers/traffic_gen/generators.cc index 4d1812cd4..f9556b2b3 100644 --- a/src/cpu/testers/traffic_gen/generators.cc +++ b/src/cpu/testers/traffic_gen/generators.cc @@ -100,20 +100,20 @@ LinearGen::getNextPacket() // 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. @@ -162,7 +162,7 @@ RandomGen::getNextPacket() } 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 @@ -217,38 +217,19 @@ TraceGen::InputStream::read(TraceElement& element) } 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; @@ -261,17 +242,24 @@ TraceGen::enter() 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", @@ -281,8 +269,19 @@ TraceGen::getNextPacket() 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 diff --git a/src/cpu/testers/traffic_gen/generators.hh b/src/cpu/testers/traffic_gen/generators.hh index 5bcfc8e80..2b86afa22 100644 --- a/src/cpu/testers/traffic_gen/generators.hh +++ b/src/cpu/testers/traffic_gen/generators.hh @@ -126,7 +126,7 @@ class BaseGen * * @return next tick when a packet is available */ - virtual Tick nextPacketTick() = 0; + virtual Tick nextPacketTick() const = 0; }; @@ -146,7 +146,7 @@ class IdleGen : public BaseGen PacketPtr getNextPacket() { return NULL; } - Tick nextPacketTick() { return MaxTick; } + Tick nextPacketTick() const { return MaxTick; } }; /** @@ -192,7 +192,7 @@ class LinearGen : public BaseGen PacketPtr getNextPacket(); - Tick nextPacketTick(); + Tick nextPacketTick() const; private: @@ -269,7 +269,7 @@ class RandomGen : public BaseGen PacketPtr getNextPacket(); - Tick nextPacketTick(); + Tick nextPacketTick() const; private: @@ -415,12 +415,11 @@ class TraceGen : public BaseGen 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: diff --git a/src/cpu/testers/traffic_gen/traffic_gen.cc b/src/cpu/testers/traffic_gen/traffic_gen.cc index ea1a74e96..8916dcb8d 100644 --- a/src/cpu/testers/traffic_gen/traffic_gen.cc +++ b/src/cpu/testers/traffic_gen/traffic_gen.cc @@ -56,8 +56,12 @@ TrafficGen::TrafficGen(const TrafficGenParams* p) 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) { } @@ -102,7 +106,9 @@ TrafficGen::initState() { // 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"); @@ -112,9 +118,16 @@ TrafficGen::initState() 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 @@ -123,18 +136,17 @@ TrafficGen::serialize(ostream &os) 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 @@ -148,28 +160,43 @@ TrafficGen::unserialize(Checkpoint* cp, const string& section) } 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); } } @@ -340,10 +367,65 @@ TrafficGen::enterState(uint32_t newState) 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) { diff --git a/src/cpu/testers/traffic_gen/traffic_gen.hh b/src/cpu/testers/traffic_gen/traffic_gen.hh index c013109b7..0adcf781e 100644 --- a/src/cpu/testers/traffic_gen/traffic_gen.hh +++ b/src/cpu/testers/traffic_gen/traffic_gen.hh @@ -42,6 +42,7 @@ #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" @@ -74,18 +75,6 @@ class TrafficGen : public MemObject 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. */ @@ -98,6 +87,12 @@ class TrafficGen : public MemObject */ 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; @@ -124,6 +119,9 @@ class TrafficGen : public MemObject /** Time of next transition */ Tick nextTransitionTick; + /** Time of the next packet. */ + Tick nextPacketTick; + /** State transition matrix */ std::vector<std::vector<double> > transitionMatrix; @@ -133,31 +131,50 @@ class TrafficGen : public MemObject /** 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: @@ -178,6 +195,9 @@ class TrafficGen : public MemObject void unserialize(Checkpoint* cp, const std::string& section); + /** Register statistics */ + void regStats(); + }; #endif //__CPU_TRAFFIC_GEN_TRAFFIC_GEN_HH__ |