Skip to content

Commit

Permalink
cpu: Add support for throttling the traffic generator
Browse files Browse the repository at this point in the history
Add the parameter maxPendingRequests to the traffic generator. This
parameter controls the maximum number of outstanding memory
requests. Once this limit has been reached, the traffic generators
simply drops excess requests until a response has been received.

Traffic generators may check the return value of BaseGen::send() to
determine if a send request succeeded and retry the current address in
that case.
  • Loading branch information
andysan committed Mar 15, 2013
1 parent c31eb51 commit 87fa4ac
Show file tree
Hide file tree
Showing 3 changed files with 119 additions and 70 deletions.
3 changes: 3 additions & 0 deletions src/cpu/testers/traffic_gen/TrafficGen.py
Expand Up @@ -71,3 +71,6 @@ class TrafficGen(MemObject):

# System used to determine the mode of the memory system
system = Param.System(Parent.any, "System this generator is part of")

maxPendingRequests = Param.Unsigned(16, "Maximum number of pending " \
"memory accesses")
92 changes: 56 additions & 36 deletions src/cpu/testers/traffic_gen/traffic_gen.cc
Expand Up @@ -56,6 +56,7 @@ TrafficGen::TrafficGen(const TrafficGenParams* p)
system(p->system),
masterID(system->getMasterId(name())),
port(name() + ".port", *this),
pendingRequests(0), maxPendingRequests(p->maxPendingRequests),
stateGraph(*this, port, p->config_file, masterID),
updateStateGraphEvent(this)
{
Expand Down Expand Up @@ -152,6 +153,38 @@ TrafficGen::unserialize(Checkpoint* cp, const string& section)
stateGraph.nextTransitionTick = nextTransitionTick;
}

bool
TrafficGen::send(Addr addr, unsigned size, const MemCmd& cmd, uint8_t *data)
{
if (pendingRequests < maxPendingRequests) {
// Create new request
Request::Flags flags;
Request *req = new Request(addr, size, flags, masterID);

// Embed it in a packet
PacketPtr pkt = new Packet(req, cmd);
pkt->dataDynamicArray(data);

++pendingRequests;
port.schedTimingReq(pkt, curTick());
return true;
} else {
return false;
}
}

bool
TrafficGen::recvTimingResp(PacketPtr pkt)
{
assert(pendingRequests >= 1);
--pendingRequests;

delete pkt->req;
delete pkt;

return true;
}

void
TrafficGen::updateStateGraph()
{
Expand Down Expand Up @@ -210,11 +243,11 @@ TrafficGen::StateGraph::parseConfig(const string& file_name,

is >> traceFile >> addrOffset;

states[id] = new TraceGen(port, master_id, duration,
states[id] = new TraceGen(owner, duration,
traceFile, addrOffset);
DPRINTF(TrafficGen, "State: %d TraceGen\n", id);
} else if (mode == "IDLE") {
states[id] = new IdleGen(port, master_id, duration);
states[id] = new IdleGen(owner, duration);
DPRINTF(TrafficGen, "State: %d IdleGen\n", id);
} else if (mode == "LINEAR" || mode == "RANDOM") {
uint32_t read_percent;
Expand All @@ -237,14 +270,14 @@ TrafficGen::StateGraph::parseConfig(const string& file_name,
panic("%s cannot have more than 100% reads", name());

if (mode == "LINEAR") {
states[id] = new LinearGen(port, master_id,
states[id] = new LinearGen(owner,
duration, start_addr,
end_addr, blocksize,
min_period, max_period,
read_percent, data_limit);
DPRINTF(TrafficGen, "State: %d LinearGen\n", id);
} else if (mode == "RANDOM") {
states[id] = new RandomGen(port, master_id,
states[id] = new RandomGen(owner,
duration, start_addr,
end_addr, blocksize,
min_period, max_period,
Expand Down Expand Up @@ -344,32 +377,25 @@ TrafficGen::StateGraph::enterState(uint32_t newState)
states[currState]->enter();
}

TrafficGen::StateGraph::BaseGen::BaseGen(QueuedMasterPort& _port,
MasterID master_id,
Tick _duration)
: port(_port), masterID(master_id), duration(_duration)
TrafficGen::StateGraph::BaseGen::BaseGen(TrafficGen& _owner, Tick _duration)
: owner(_owner), duration(_duration)
{
}

void
bool
TrafficGen::StateGraph::BaseGen::send(Addr addr, unsigned size,
const MemCmd& cmd)
const MemCmd& cmd)
{
// Create new request
Request::Flags flags;
Request *req = new Request(addr, size, flags, masterID);

// Embed it in a packet
PacketPtr pkt = new Packet(req, cmd);

uint8_t* pkt_data = new uint8_t[req->getSize()];
pkt->dataDynamicArray(pkt_data);
uint8_t* pkt_data = new uint8_t[size];
if (cmd.isWrite())
memset(pkt_data, 0xA, size);

if (cmd.isWrite()) {
memset(pkt_data, 0xA, req->getSize());
if (!owner.send(addr, size, cmd, pkt_data)) {
delete[] pkt_data;
return false;
} else {
return true;
}

port.schedTimingReq(pkt, curTick());
}

void
Expand All @@ -381,9 +407,10 @@ TrafficGen::StateGraph::LinearGen::enter()

// this test only needs to happen once, but cannot be performed
// before init() is called and the ports are connected
if (port.deviceBlockSize() && blocksize > port.deviceBlockSize())
if (owner.port.deviceBlockSize() &&
blocksize > owner.port.deviceBlockSize())
fatal("TrafficGen %s block size (%d) is larger than port"
" block size (%d)\n", blocksize, port.deviceBlockSize());
" block size (%d)\n", blocksize, owner.port.deviceBlockSize());

}

Expand Down Expand Up @@ -441,9 +468,11 @@ TrafficGen::StateGraph::RandomGen::enter()

// this test only needs to happen once, but cannot be performed
// before init() is called and the ports are connected
if (port.deviceBlockSize() && blocksize > port.deviceBlockSize())
if (owner.port.deviceBlockSize() &&
blocksize > owner.port.deviceBlockSize())
fatal("TrafficGen %s block size (%d) is larger than port"
" block size (%d)\n", name(), blocksize, port.deviceBlockSize());
" block size (%d)\n", name(), blocksize,
owner.port.deviceBlockSize());
}

void
Expand Down Expand Up @@ -607,12 +636,3 @@ TrafficGen::StateGraph::TraceGen::exit() {
// file
trace.reset();
}

bool
TrafficGen::TrafficGenPort::recvTimingResp(PacketPtr pkt)
{
delete pkt->req;
delete pkt;

return true;
}
94 changes: 60 additions & 34 deletions src/cpu/testers/traffic_gen/traffic_gen.hh
Expand Up @@ -164,22 +164,23 @@ class TrafficGen : public MemObject
{

protected:

/** Port used to send requests */
QueuedMasterPort& port;

/** The MasterID used for generating requests */
const MasterID masterID;

/**
* Create a new request and associated packet and schedule
* it to be sent in the current tick.
*
* @note This method may return false to indicate that a packet
* couldn't be delivered because the maximum number of outstanding
* memory requests has been reached.
*
* @param addr Physical address to use
* @param size Size of the request
* @param cmd Memory command to send
* @return True if the request was sent, false otherwise.
*/
void send(Addr addr, unsigned size, const MemCmd& cmd);
bool send(Addr addr, unsigned size, const MemCmd& cmd);

/** Pointer to owner of generator */
TrafficGen& owner;

public:

Expand All @@ -189,12 +190,10 @@ class TrafficGen : public MemObject
/**
* Create a base generator.
*
* @param _port port used to send requests
* @param master_id MasterID set on each request
* @param _owner object owning the generator instance
* @param _duration duration of this state before transitioning
*/
BaseGen(QueuedMasterPort& _port, MasterID master_id,
Tick _duration);
BaseGen(TrafficGen& _owner, Tick _duration);

virtual ~BaseGen() { }

Expand All @@ -203,7 +202,7 @@ class TrafficGen : public MemObject
*
* @return the port name
*/
std::string name() const { return port.name(); }
std::string name() const { return owner.name(); }

/**
* Enter this generator state.
Expand Down Expand Up @@ -239,9 +238,8 @@ class TrafficGen : public MemObject

public:

IdleGen(QueuedMasterPort& _port, MasterID master_id,
Tick _duration)
: BaseGen(_port, master_id, _duration)
IdleGen(TrafficGen& _owner, Tick _duration)
: BaseGen(_owner, _duration)
{ }

void enter() { }
Expand All @@ -268,8 +266,7 @@ class TrafficGen : public MemObject
* min_period == max_period for a fixed inter-transaction
* time.
*
* @param _port port used to send requests
* @param master_id MasterID set on each request
* @param _owner object owning the generator instance
* @param _duration duration of this state before transitioning
* @param start_addr Start address
* @param end_addr End address
Expand All @@ -279,11 +276,11 @@ class TrafficGen : public MemObject
* @param read_percent Percent of transactions that are reads
* @param data_limit Upper limit on how much data to read/write
*/
LinearGen(QueuedMasterPort& _port, MasterID master_id,
Tick _duration, Addr start_addr, Addr end_addr,
LinearGen(TrafficGen& _owner, Tick _duration,
Addr start_addr, Addr end_addr,
Addr _blocksize, Tick min_period, Tick max_period,
uint8_t read_percent, Addr data_limit)
: BaseGen(_port, master_id, _duration),
: BaseGen(_owner, _duration),
startAddr(start_addr), endAddr(end_addr),
blocksize(_blocksize), minPeriod(min_period),
maxPeriod(max_period), readPercent(read_percent),
Expand Down Expand Up @@ -345,8 +342,7 @@ class TrafficGen : public MemObject
* min_period == max_period for a fixed inter-transaction
* time.
*
* @param _port port used to send requests
* @param master_id MasterID set on each request
* @param _owner object owning the generator instance
* @param _duration duration of this state before transitioning
* @param start_addr Start address
* @param end_addr End address
Expand All @@ -356,11 +352,11 @@ class TrafficGen : public MemObject
* @param read_percent Percent of transactions that are reads
* @param data_limit Upper limit on how much data to read/write
*/
RandomGen(QueuedMasterPort& _port, MasterID master_id,
Tick _duration, Addr start_addr, Addr end_addr,
RandomGen(TrafficGen& _owner, Tick _duration,
Addr start_addr, Addr end_addr,
Addr _blocksize, Tick min_period, Tick max_period,
uint8_t read_percent, Addr data_limit)
: BaseGen(_port, master_id, _duration),
: BaseGen(_owner, _duration),
startAddr(start_addr), endAddr(end_addr),
blocksize(_blocksize), minPeriod(min_period),
maxPeriod(max_period), readPercent(read_percent),
Expand Down Expand Up @@ -492,16 +488,15 @@ class TrafficGen : public MemObject
/**
* Create a trace generator.
*
* @param _port port used to send requests
* @param master_id MasterID set on each request
* @param _owner object owning the generator instance
* @param _duration duration of this state before transitioning
* @param trace_file File to read the transactions from
* @param addr_offset Positive offset to add to trace address
*/
TraceGen(QueuedMasterPort& _port, MasterID master_id,
Tick _duration, const std::string& trace_file,
TraceGen(TrafficGen& _owner, Tick _duration,
const std::string& trace_file,
Addr addr_offset)
: BaseGen(_port, master_id, _duration),
: BaseGen(_owner, _duration),
trace(trace_file),
addrOffset(addr_offset),
traceComplete(false)
Expand Down Expand Up @@ -575,21 +570,52 @@ class TrafficGen : public MemObject
public:

TrafficGenPort(const std::string& name, TrafficGen& _owner)
: QueuedMasterPort(name, &_owner, queue), queue(_owner, *this)
: QueuedMasterPort(name, &_owner, queue), queue(_owner, *this),
owner(_owner)
{ }

protected:

bool recvTimingResp(PacketPtr pkt);
bool recvTimingResp(PacketPtr pkt) {
return owner.recvTimingResp(pkt);
}

private:

MasterPacketQueue queue;

TrafficGen &owner;
};

/**
* Create a new request and associated packet and schedule it to
* be sent in the current tick.
*
* @note This method may return false to indicate that a packet
* couldn't be delivered because the maximum number of outstanding
* memory requests has been reached.
*
* @param addr Request address
* @param size Request size
* @param cmd Memory command
* @param data Dynamic array of data associated with the packet.
* @return True if the request was sent, false otherwise.
*/
bool send(Addr addr, unsigned size, const MemCmd& cmd, uint8_t *data);

/**
* Handle a timing response from the memory system.
*
* @see MasterPort::recvTimingResp()
*/
bool recvTimingResp(PacketPtr pkt);

TrafficGenPort port;

/** Number of requests still pending in the memory system */
unsigned pendingRequests;
/** Maximum number of pending requests */
const unsigned maxPendingRequests;

/** Request generator state graph */
StateGraph stateGraph;

Expand Down

0 comments on commit 87fa4ac

Please sign in to comment.