# 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")
}
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
return MaxTick;
} else {
// return the time when the next request should take place
- return curTick() + random_mt.random<Tick>(minPeriod, maxPeriod);
+ Tick wait = random_mt.random<Tick>(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;
}
}
}
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
// No more requests. Return MaxTick.
return MaxTick;
} else {
- // Return the time when the next request should take place.
- return curTick() + random_mt.random<Tick>(minPeriod, maxPeriod);
+ // return the time when the next request should take place
+ Tick wait = random_mt.random<Tick>(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;
}
}
}
Tick
-TraceGen::nextPacketTick() const
+TraceGen::nextPacketTick(bool elastic, Tick delay) const
{
if (traceComplete) {
DPRINTF(TrafficGen, "No next tick as trace is finished\n");
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
* 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;
};
PacketPtr getNextPacket() { return NULL; }
- Tick nextPacketTick() const { return MaxTick; }
+ Tick nextPacketTick(bool elastic, Tick delay) const { return MaxTick; }
};
/**
PacketPtr getNextPacket();
- Tick nextPacketTick() const;
+ Tick nextPacketTick(bool elastic, Tick delay) const;
private:
PacketPtr getNextPacket();
- Tick nextPacketTick() const;
+ Tick nextPacketTick(bool elastic, Tick delay) const;
private:
const std::string& trace_file, Addr addr_offset)
: BaseGen(_name, master_id, _duration),
trace(trace_file),
+ tickOffset(0),
addrOffset(addr_offset),
traceComplete(false)
{
* 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:
/**
* 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
system(p->system),
masterID(system->getMasterId(name())),
configFile(p->config_file),
+ elasticReq(p->elastic_req),
nextTransitionTick(0),
nextPacketTick(0),
port(name() + ".port", *this),
// 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,
// @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);
}
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);
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 {
*/
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;