gem5/src/cpu/testers/traffic_gen/traffic_gen.hh
Andreas Hansson 2a740aa096 Port: Add protocol-agnostic ports in the port hierarchy
This patch adds an additional level of ports in the inheritance
hierarchy, separating out the protocol-specific and protocl-agnostic
parts. All the functionality related to the binding of ports is now
confined to use BaseMaster/BaseSlavePorts, and all the
protocol-specific parts stay in the Master/SlavePort. In the future it
will be possible to add other protocol-specific implementations.

The functions used in the binding of ports, i.e. getMaster/SlavePort
now use the base classes, and the index parameter is updated to use
the PortID typedef with the symbolic InvalidPortID as the default.
2012-10-15 08:12:35 -04:00

616 lines
19 KiB
C++

/*
* Copyright (c) 2012 ARM Limited
* All rights reserved
*
* The license below extends only to copyright in the software and shall
* not be construed as granting a license to any other intellectual
* property including but not limited to intellectual property relating
* to a hardware implementation of the functionality of the software
* licensed hereunder. You may use the software subject to the license
* terms below provided that you ensure that this notice is replicated
* unmodified and in its entirety in all distributions of the software,
* modified or unmodified, in source code or in binary form.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met: redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer;
* redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution;
* neither the name of the copyright holders nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* Authors: Thomas Grass
* Andreas Hansson
* Sascha Bischoff
*/
#ifndef __MEM_TRAFFIC_GEN_HH__
#define __MEM_TRAFFIC_GEN_HH__
#include <fstream>
#include "base/hashmap.hh"
#include "mem/mem_object.hh"
#include "mem/qport.hh"
#include "params/TrafficGen.hh"
/**
* The traffic generator is a master module that generates stimuli for
* the memory system, based on a collection of simple behaviours that
* are either probabilistic or based on traces. It can be used stand
* alone for creating test cases for interconnect and memory
* controllers, or function as a black box replacement for system
* components that are not yet modelled in detail, e.g. a video engine
* or baseband subsystem.
*/
class TrafficGen : public MemObject
{
private:
/**
* The system used to determine which mode we are currently operating
* in.
*/
System* system;
/**
* MasterID used in generated requests.
*/
MasterID masterID;
protected:
/**
* The state graph is responsible for instantiating and keeping
* track of the various generator states and also perform the
* transitions and call the appropriate functions when entering,
* executing and exiting a state.
*/
class StateGraph
{
public:
/**
* Create a state graph from an input file.
*
* @param _owner used solely for the name
* @param _port port used to send requests
* @param file_name configuration description to read in
* @param master_id the unique id used for all requests
*/
StateGraph(TrafficGen& _owner, QueuedMasterPort& _port,
const std::string& file_name, MasterID master_id)
: nextTransitionTick(0), owner(_owner), port(_port)
{
parseConfig(file_name, master_id);
}
/**
* Get the name, used for DPRINTFs.
*
* @return the owner's name
*/
std::string name() const { return owner.name(); }
/**
* Either perform a state transition or execute the current
* state, depending on the current time.
*/
void update();
/**
* Determine next state and perform the transition.
*/
void transition();
/**
* Enter a new state.
*
* @param newState identifier of state to enter
*/
void enterState(uint32_t newState);
/**
* Get the tick of the next event, either an execution or a
* transition.
*
* @return tick of the next state graph event
*/
Tick nextEventTick()
{
return std::min(states[currState]->nextExecuteTick(),
nextTransitionTick);
}
/** Time of next transition */
Tick nextTransitionTick;
private:
/**
* Parse the config file and build the state map and
* transition matrix.
*
* @param file_name Config file name to parse
* @param master_id MasterID to use for generated requests
*/
void parseConfig(const std::string& file_name, MasterID master_id);
/** Struct to represent a probabilistic transition during parsing. */
struct Transition {
uint32_t from;
uint32_t to;
double p;
};
/** Base class for all generator states */
class BaseGen
{
protected:
/** Port used to send requests */
QueuedMasterPort& port;
/** The MasterID used for generating requests */
const MasterID masterID;
public:
/** Time to spend in this state */
const Tick duration;
/**
* Create a base generator.
*
* @param _port port used to send requests
* @param master_id MasterID set on each request
* @param _duration duration of this state before transitioning
*/
BaseGen(QueuedMasterPort& _port, MasterID master_id,
Tick _duration);
virtual ~BaseGen() { }
/**
* Get the name, useful for DPRINTFs.
*
* @return the port name
*/
std::string name() const { return port.name(); }
/**
* Enter this generator state.
*/
virtual void enter() = 0;
/**
* Execute this generator state.
*/
virtual void execute() = 0;
/**
* Exit this generator state. By default do nothing.
*/
virtual void exit() { };
/**
* Determine the next execute tick. MaxTick means that
* there will not be any further event in the current
* activation cycle of the state.
*
* @return next tick when the state should be executed
*/
virtual Tick nextExecuteTick() = 0;
};
/**
* The idle generator does nothing.
*/
class IdleGen : public BaseGen
{
public:
IdleGen(QueuedMasterPort& _port, MasterID master_id,
Tick _duration)
: BaseGen(_port, master_id, _duration)
{ }
void enter() { }
void execute() { }
Tick nextExecuteTick() { return MaxTick; }
};
/**
* The linear generator generates sequential requests from a
* start to an end address, with a fixed block size. A
* fraction of the requests are reads, as determined by the
* read percent. There is an optional data limit for when to
* stop generating new requests.
*/
class LinearGen : public BaseGen
{
public:
/**
* Create a linear address sequence generator. Set
* 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 _duration duration of this state before transitioning
* @param start_addr Start address
* @param end_addr End address
* @param _blocksize Size used for transactions injected
* @param min_period Lower limit of random inter-transaction time
* @param max_period Upper limit of random inter-transaction time
* @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,
Addr _blocksize, Tick min_period, Tick max_period,
uint8_t read_percent, Addr data_limit)
: BaseGen(_port, master_id, _duration),
startAddr(start_addr), endAddr(end_addr),
blocksize(_blocksize), minPeriod(min_period),
maxPeriod(max_period), readPercent(read_percent),
dataLimit(data_limit)
{ }
void enter();
void execute();
Tick nextExecuteTick();
private:
/** Start of address range */
const Addr startAddr;
/** End of address range */
const Addr endAddr;
/** Blocksize and address increment */
const Addr blocksize;
/** Request generation period */
const Tick minPeriod;
const Tick maxPeriod;
/**
* Percent of generated transactions that should be reads
*/
const uint8_t readPercent;
/** Maximum amount of data to manipulate */
const Addr dataLimit;
/** Address of next request */
Addr nextAddr;
/**
* Counter to determine the amount of data
* manipulated. Used to determine if we should continue
* generating requests.
*/
Addr dataManipulated;
};
/**
* The random generator is similar to the linear one, but does
* not generate sequential addresses. Instead it randomly
* picks an address in the range, aligned to the block size.
*/
class RandomGen : public BaseGen
{
public:
/**
* Create a random address sequence generator. Set
* 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 _duration duration of this state before transitioning
* @param start_addr Start address
* @param end_addr End address
* @param _blocksize Size used for transactions injected
* @param min_period Lower limit of random inter-transaction time
* @param max_period Upper limit of random inter-transaction time
* @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,
Addr _blocksize, Tick min_period, Tick max_period,
uint8_t read_percent, Addr data_limit)
: BaseGen(_port, master_id, _duration),
startAddr(start_addr), endAddr(end_addr),
blocksize(_blocksize), minPeriod(min_period),
maxPeriod(max_period), readPercent(read_percent),
dataLimit(data_limit)
{ }
void enter();
void execute();
Tick nextExecuteTick();
private:
/** Start of address range */
const Addr startAddr;
/** End of address range */
const Addr endAddr;
/** Block size */
const Addr blocksize;
/** Request generation period */
const Tick minPeriod;
const Tick maxPeriod;
/**
* Percent of generated transactions that should be reads
*/
const uint8_t readPercent;
/** Maximum amount of data to manipulate */
const Addr dataLimit;
/**
* Counter to determine the amount of data
* manipulated. Used to determine if we should continue
* generating requests.
*/
Addr dataManipulated;
};
/**
* The trace replay generator reads a trace file and plays
* back the transactions. The trace is offset with respect to
* the time when the state was entered.
*/
class TraceGen : public BaseGen
{
private:
/**
* This struct stores a line in the trace file.
*/
struct TraceElement {
/** Specifies if the request is to be a read or a write */
MemCmd cmd;
/** The address for the request */
Addr addr;
/** The size of the access for the request */
Addr blocksize;
/** The time at which the request should be sent */
Tick tick;
/**
* Check validity of this element.
*
* @return if this element is valid
*/
bool isValid() const {
return cmd != MemCmd::InvalidCmd;
}
/**
* Make this element invalid.
*/
void clear() {
cmd = MemCmd::InvalidCmd;
}
};
public:
/**
* Create a trace generator.
*
* @param _port port used to send requests
* @param master_id MasterID set on each request
* @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,
Addr addr_offset)
: BaseGen(_port, master_id, _duration),
traceFile(trace_file),
addrOffset(addr_offset),
traceComplete(false)
{
/**
* Create a 4MB read buffer for the input trace
* file. This is to reduce the number of disk accesses
* and thereby speed up the execution of the code.
*/
readBuffer = new char[4 * 1024 * 1024];
trace.rdbuf()->pubsetbuf(readBuffer, 4 * 1024 * 1024);
trace.open(traceFile.c_str(), std::ifstream::in);
if (!trace.is_open()) {
fatal("Traffic generator %s trace file could not be"
" opened: %s\n", name(), traceFile);
}
}
~TraceGen() {
// free the memory used by the readBuffer
delete[] readBuffer;
}
void enter();
void execute();
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
* indicate that there will be no more requests.
*/
Tick nextExecuteTick();
private:
/** Path to the trace file */
std::string traceFile;
/** Input stream used for reading the input trace file */
std::ifstream trace;
/** Larger buffer used for reading from the stream */
char* readBuffer;
/** Store the current and next element in the trace */
TraceElement currElement;
TraceElement nextElement;
/**
* Stores the time when the state was entered. This is to add an
* offset to the times stored in the trace file.
*/
Tick tickOffset;
/**
* Offset for memory requests. Used to shift the trace
* away from the CPU address space.
*/
Addr addrOffset;
/**
* Set to true when the trace replay for one instance of
* state is complete.
*/
bool traceComplete;
/**
* Used to store the Tick when the next generate should
* occur. It is to remove a transaction as soon as we
* enter the state.
*/
Tick oldEmitTime;
};
/** Pointer to owner of request handler */
TrafficGen& owner;
/** Pointer to request handler */
QueuedMasterPort& port;
/** State transition matrix */
std::vector<std::vector<double> > transitionMatrix;
public:
/** Index of the current state */
uint32_t currState;
/** Map of states */
m5::hash_map<uint32_t, BaseGen*> states;
};
/** Queued handler */
class TrafficGenPort : public QueuedMasterPort
{
public:
TrafficGenPort(const std::string& name, TrafficGen& _owner)
: QueuedMasterPort(name, &_owner, queue), queue(_owner, *this),
owner(_owner)
{ }
protected:
bool recvTimingResp(PacketPtr pkt);
private:
MasterPacketQueue queue;
// Owner of the port
TrafficGen& owner;
};
TrafficGenPort port;
/** Request generator state graph */
StateGraph stateGraph;
/**
* Schedules event for next update and executes an update on the
* state graph.
*/
void updateStateGraph();
/** Event for updating the state graph */
EventWrapper<TrafficGen,
&TrafficGen::updateStateGraph> updateStateGraphEvent;
public:
TrafficGen(const TrafficGenParams* p);
~TrafficGen() {}
virtual BaseMasterPort& getMasterPort(const std::string &if_name,
PortID idx = InvalidPortID);
void init();
void initState();
unsigned int drain(Event *drain_event);
void serialize(std::ostream &os);
void unserialize(Checkpoint* cp, const std::string& section);
};
#endif //__MEM_TRAFFIC_GEN_HH__