diff -r 29748d82d15b -r 408c15e602c0 src/cpu/testers/traffic_gen/TrafficGen.py --- a/src/cpu/testers/traffic_gen/TrafficGen.py Tue Apr 23 08:35:28 2013 +0100 +++ b/src/cpu/testers/traffic_gen/TrafficGen.py Tue Apr 23 08:38:46 2013 +0100 @@ -71,3 +71,9 @@ # System used to determine the mode of the memory system system = Param.System(Parent.any, "System this generator is part of") + + # Should requests respond to back-pressure or not, if true, the + # rate of the traffic generator will be slowed down if requests + # are not immediately accepted + elastic_req = Param.Bool(False, + "Slow down requests in case of backpressure") diff -r 29748d82d15b -r 408c15e602c0 src/cpu/testers/traffic_gen/generators.hh --- a/src/cpu/testers/traffic_gen/generators.hh Tue Apr 23 08:35:28 2013 +0100 +++ b/src/cpu/testers/traffic_gen/generators.hh Tue Apr 23 08:38:46 2013 +0100 @@ -124,9 +124,11 @@ * means that there will not be any further packets in the current * activation cycle of the generator. * + * @param elastic should the injection respond to flow control or not + * @param delay time the previous packet spent waiting * @return next tick when a packet is available */ - virtual Tick nextPacketTick() const = 0; + virtual Tick nextPacketTick(bool elastic, Tick delay) const = 0; }; @@ -146,7 +148,7 @@ PacketPtr getNextPacket() { return NULL; } - Tick nextPacketTick() const { return MaxTick; } + Tick nextPacketTick(bool elastic, Tick delay) const { return MaxTick; } }; /** @@ -192,7 +194,7 @@ PacketPtr getNextPacket(); - Tick nextPacketTick() const; + Tick nextPacketTick(bool elastic, Tick delay) const; private: @@ -269,7 +271,7 @@ PacketPtr getNextPacket(); - Tick nextPacketTick() const; + Tick nextPacketTick(bool elastic, Tick delay) const; private: @@ -403,6 +405,7 @@ const std::string& trace_file, Addr addr_offset) : BaseGen(_name, master_id, _duration), trace(trace_file), + tickOffset(0), addrOffset(addr_offset), traceComplete(false) { @@ -419,7 +422,7 @@ * the end of the file has been reached, it returns MaxTick to * indicate that there will be no more requests. */ - Tick nextPacketTick() const; + Tick nextPacketTick(bool elastic, Tick delay) const; private: @@ -432,9 +435,10 @@ /** * Stores the time when the state was entered. This is to add an - * offset to the times stored in the trace file. + * offset to the times stored in the trace file. This is mutable + * to allow us to change it as part of nextPacketTick. */ - Tick tickOffset; + mutable Tick tickOffset; /** * Offset for memory requests. Used to shift the trace diff -r 29748d82d15b -r 408c15e602c0 src/cpu/testers/traffic_gen/generators.cc --- a/src/cpu/testers/traffic_gen/generators.cc Tue Apr 23 08:35:28 2013 +0100 +++ b/src/cpu/testers/traffic_gen/generators.cc Tue Apr 23 08:38:46 2013 +0100 @@ -112,7 +112,7 @@ } Tick -LinearGen::nextPacketTick() const +LinearGen::nextPacketTick(bool elastic, Tick delay) 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 @@ -123,7 +123,19 @@ return MaxTick; } else { // return the time when the next request should take place - return curTick() + random_mt.random(minPeriod, maxPeriod); + Tick wait = random_mt.random(minPeriod, maxPeriod); + + // compensate for the delay experienced to not be elastic, by + // default the value we generate is from the time we are + // asked, so the elasticity happens automatically + if (!elastic) { + if (wait < delay) + wait = 0; + else + wait -= delay; + } + + return curTick() + wait; } } @@ -162,7 +174,7 @@ } Tick -RandomGen::nextPacketTick() const +RandomGen::nextPacketTick(bool elastic, Tick delay) 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 @@ -173,8 +185,20 @@ // No more requests. Return MaxTick. return MaxTick; } else { - // Return the time when the next request should take place. - return curTick() + random_mt.random(minPeriod, maxPeriod); + // return the time when the next request should take place + Tick wait = random_mt.random(minPeriod, maxPeriod); + + // compensate for the delay experienced to not be elastic, by + // default the value we generate is from the time we are + // asked, so the elasticity happens automatically + if (!elastic) { + if (wait < delay) + wait = 0; + else + wait -= delay; + } + + return curTick() + wait; } } @@ -217,7 +241,7 @@ } Tick -TraceGen::nextPacketTick() const +TraceGen::nextPacketTick(bool elastic, Tick delay) const { if (traceComplete) { DPRINTF(TrafficGen, "No next tick as trace is finished\n"); @@ -232,7 +256,11 @@ DPRINTF(TrafficGen, "Next packet tick is %d\n", tickOffset + nextElement.tick); - return tickOffset + nextElement.tick; + // if the playback is supposed to be elastic, add the delay + if (elastic) + tickOffset += delay; + + return std::max(tickOffset + nextElement.tick, curTick()); } void diff -r 29748d82d15b -r 408c15e602c0 src/cpu/testers/traffic_gen/traffic_gen.hh --- a/src/cpu/testers/traffic_gen/traffic_gen.hh Tue Apr 23 08:35:28 2013 +0100 +++ b/src/cpu/testers/traffic_gen/traffic_gen.hh Tue Apr 23 08:38:46 2013 +0100 @@ -116,6 +116,12 @@ */ const std::string configFile; + /** + * Determine whether to add elasticity in the request injection, + * thus responding to backpressure by slowing things down. + */ + const bool elasticReq; + /** Time of next transition */ Tick nextTransitionTick; diff -r 29748d82d15b -r 408c15e602c0 src/cpu/testers/traffic_gen/traffic_gen.cc --- a/src/cpu/testers/traffic_gen/traffic_gen.cc Tue Apr 23 08:35:28 2013 +0100 +++ b/src/cpu/testers/traffic_gen/traffic_gen.cc Tue Apr 23 08:38:46 2013 +0100 @@ -55,6 +55,7 @@ system(p->system), masterID(system->getMasterId(name())), configFile(p->config_file), + elasticReq(p->elastic_req), nextTransitionTick(0), nextPacketTick(0), port(name() + ".port", *this), @@ -107,7 +108,7 @@ // when not restoring from a checkpoint, make sure we kick things off if (system->isTimingMode()) { // call nextPacketTick on the state to advance it - nextPacketTick = states[currState]->nextPacketTick(); + nextPacketTick = states[currState]->nextPacketTick(elasticReq, 0); schedule(updateEvent, std::min(nextPacketTick, nextTransitionTick)); } else { DPRINTF(TrafficGen, @@ -165,7 +166,7 @@ // @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 + // trace playback and the tick offset UNSERIALIZE_SCALAR(currState); } @@ -193,7 +194,7 @@ 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(); + nextPacketTick = states[currState]->nextPacketTick(elasticReq, 0); Tick nextEventTick = std::min(nextPacketTick, nextTransitionTick); DPRINTF(TrafficGen, "Next event scheduled at %lld\n", nextEventTick); schedule(updateEvent, nextEventTick); @@ -386,14 +387,16 @@ if (port.sendTimingReq(retryPkt)) { retryPkt = NULL; // remember how much delay was incurred due to back-pressure - // when sending the request + // when sending the request, we also use this to derive + // the tick for the next packet 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(); + nextPacketTick = states[currState]->nextPacketTick(elasticReq, + delay); Tick nextEventTick = std::min(nextPacketTick, nextTransitionTick); schedule(updateEvent, std::max(curTick(), nextEventTick)); } else {