blob: 5604856a912f17e63aff7e9a3bb21acf78a1a795 [file] [log] [blame]
/*
* Copyright (c) 2012-2013 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
* Neha Agarwal
*/
/**
* @file
* Declaration of a set of generator behaviours that are used by the
* stand-alone traffic generator, but can also be instantiated
* elsewhere.
*/
#ifndef __CPU_TRAFFIC_GEN_GENERATORS_HH__
#define __CPU_TRAFFIC_GEN_GENERATORS_HH__
#include "base/bitfield.hh"
#include "base/intmath.hh"
#include "mem/packet.hh"
#include "proto/protoio.hh"
/**
* Base class for all generators, with the shared functionality and
* virtual functions for entering, executing and leaving the
* generator.
*/
class BaseGen
{
protected:
/** Name to use for status and debug printing */
const std::string _name;
/** The MasterID used for generating requests */
const MasterID masterID;
/**
* Generate a new request and associated packet
*
* @param addr Physical address to use
* @param size Size of the request
* @param cmd Memory command to send
* @param flags Optional request flags
*/
PacketPtr getPacket(Addr addr, unsigned size, const MemCmd& cmd,
Request::FlagsType flags = 0);
public:
/** Time to spend in this state */
const Tick duration;
/**
* Create a base generator.
*
* @param _name Name to use for status and debug
* @param master_id MasterID set on each request
* @param _duration duration of this state before transitioning
*/
BaseGen(const std::string& _name, MasterID master_id, Tick _duration);
virtual ~BaseGen() { }
/**
* Get the name, useful for DPRINTFs.
*
* @return the given name
*/
std::string name() const { return _name; }
/**
* Enter this generator state.
*/
virtual void enter() = 0;
/**
* Get the next generated packet.
*
* @return A packet to be sent at the current tick
*/
virtual PacketPtr getNextPacket() = 0;
/**
* Exit this generator state. By default do nothing.
*/
virtual void exit() { };
/**
* Determine the tick when the next packet is available. MaxTick
* 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(bool elastic, Tick delay) const = 0;
};
/**
* The idle generator does nothing.
*/
class IdleGen : public BaseGen
{
public:
IdleGen(const std::string& _name, MasterID master_id, Tick _duration)
: BaseGen(_name, master_id, _duration)
{ }
void enter() { }
PacketPtr getNextPacket() { return NULL; }
Tick nextPacketTick(bool elastic, Tick delay) const { 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 _name Name to use for status and debug
* @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(const std::string& _name, 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(_name, master_id, _duration),
startAddr(start_addr), endAddr(end_addr),
blocksize(_blocksize), minPeriod(min_period),
maxPeriod(max_period), readPercent(read_percent),
dataLimit(data_limit), nextAddr(startAddr), dataManipulated(0)
{ }
void enter();
PacketPtr getNextPacket();
Tick nextPacketTick(bool elastic, Tick delay) const;
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 _name Name to use for status and debug
* @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(const std::string& _name, 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(_name, master_id, _duration),
startAddr(start_addr), endAddr(end_addr),
blocksize(_blocksize), minPeriod(min_period),
maxPeriod(max_period), readPercent(read_percent),
dataLimit(data_limit), dataManipulated(0)
{ }
void enter();
PacketPtr getNextPacket();
Tick nextPacketTick(bool elastic, Tick delay) const;
protected:
/** 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;
};
/**
* DRAM specific generator is for issuing request with variable page
* hit length and bank utilization. Currently assumes a single
* channel configuration.
*/
class DramGen : public RandomGen
{
public:
/**
* Create a DRAM address sequence generator.
*
* @param _name Name to use for status and debug
* @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
* @param num_seq_pkts Number of packets per stride, each of _blocksize
* @param page_size Page size (bytes) used in the DRAM
* @param nbr_of_banks_DRAM Total number of banks in DRAM
* @param nbr_of_banks_util Number of banks to utilized,
* for N banks, we will use banks: 0->(N-1)
* @param addr_mapping Address mapping to be used,
* 0: RoCoRaBaCh, 1: RoRaBaCoCh/RoRaBaChCo
* assumes single channel system
*/
DramGen(const std::string& _name, 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,
unsigned int num_seq_pkts, unsigned int page_size,
unsigned int nbr_of_banks_DRAM, unsigned int nbr_of_banks_util,
unsigned int addr_mapping,
unsigned int nbr_of_ranks)
: RandomGen(_name, master_id, _duration, start_addr, end_addr,
_blocksize, min_period, max_period, read_percent, data_limit),
numSeqPkts(num_seq_pkts), countNumSeqPkts(0), addr(0),
isRead(true), pageSize(page_size),
pageBits(floorLog2(page_size / _blocksize)),
bankBits(floorLog2(nbr_of_banks_DRAM)),
blockBits(floorLog2(_blocksize)),
nbrOfBanksDRAM(nbr_of_banks_DRAM),
nbrOfBanksUtil(nbr_of_banks_util), addrMapping(addr_mapping),
rankBits(floorLog2(nbr_of_ranks)),
nbrOfRanks(nbr_of_ranks)
{
if (addrMapping != 1 && addrMapping != 0) {
addrMapping = 1;
warn("Unknown address mapping specified, using RoRaBaCoCh\n");
}
}
PacketPtr getNextPacket();
/** Insert bank, rank, and column bits into packed
* address to create address for 1st command in a
* series
* @param new_bank Bank number of next packet series
* @param new_rank Rank value of next packet series
*/
void genStartAddr(unsigned int new_bank , unsigned int new_rank);
protected:
/** Number of sequential DRAM packets to be generated per cpu request */
const unsigned int numSeqPkts;
/** Track number of sequential packets generated for a request */
unsigned int countNumSeqPkts;
/** Address of request */
Addr addr;
/** Remember type of requests to be generated in series */
bool isRead;
/** Page size of DRAM */
const unsigned int pageSize;
/** Number of page bits in DRAM address */
const unsigned int pageBits;
/** Number of bank bits in DRAM address*/
const unsigned int bankBits;
/** Number of block bits in DRAM address */
const unsigned int blockBits;
/** Number of banks in DRAM */
const unsigned int nbrOfBanksDRAM;
/** Number of banks to be utilized for a given configuration */
const unsigned int nbrOfBanksUtil;
/** Address mapping to be used */
unsigned int addrMapping;
/** Number of rank bits in DRAM address*/
const unsigned int rankBits;
/** Number of ranks to be utilized for a given configuration */
const unsigned int nbrOfRanks;
};
class DramRotGen : public DramGen
{
public:
/**
* Create a DRAM address sequence generator.
* This sequence generator will rotate through:
* 1) Banks per rank
* 2) Command type (if applicable)
* 3) Ranks per channel
*
* @param _name Name to use for status and debug
* @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
* @param num_seq_pkts Number of packets per stride, each of _blocksize
* @param page_size Page size (bytes) used in the DRAM
* @param nbr_of_banks_DRAM Total number of banks in DRAM
* @param nbr_of_banks_util Number of banks to utilized,
* for N banks, we will use banks: 0->(N-1)
* @param nbr_of_ranks Number of ranks utilized,
* @param addr_mapping Address mapping to be used,
* 0: RoCoRaBaCh, 1: RoRaBaCoCh/RoRaBaChCo
* assumes single channel system
*/
DramRotGen(const std::string& _name, 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,
unsigned int num_seq_pkts, unsigned int page_size,
unsigned int nbr_of_banks_DRAM, unsigned int nbr_of_banks_util,
unsigned int addr_mapping,
unsigned int nbr_of_ranks,
unsigned int max_seq_count_per_rank)
: DramGen(_name, master_id, _duration, start_addr, end_addr,
_blocksize, min_period, max_period, read_percent, data_limit,
num_seq_pkts, page_size, nbr_of_banks_DRAM,
nbr_of_banks_util, addr_mapping,
nbr_of_ranks),
maxSeqCountPerRank(max_seq_count_per_rank),
nextSeqCount(0)
{
// Rotating traffic generation can only support a read
// percentage of 0, 50, or 100
if (readPercent != 50 && readPercent != 100 && readPercent != 0) {
fatal("%s: Unsupported read percentage for DramRotGen: %d",
_name, readPercent);
}
}
PacketPtr getNextPacket();
private:
/** Number of command series issued before the rank is
changed. Should rotate to the next rank after rorating
throughall the banks for each specified command type */
const unsigned int maxSeqCountPerRank;
/** Next packet series count used to set rank and bank,
and update isRead Incremented at the start of a new
packet series */
unsigned int nextSeqCount;
};
/**
* 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;
/** Potential request flags to use */
Request::FlagsType flags;
/**
* 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;
}
};
/**
* The InputStream encapsulates a trace file and the
* internal buffers and populates TraceElements based on
* the input.
*/
class InputStream
{
private:
/// Input file stream for the protobuf trace
ProtoInputStream trace;
public:
/**
* Create a trace input stream for a given file name.
*
* @param filename Path to the file to read from
*/
InputStream(const std::string& filename);
/**
* Reset the stream such that it can be played once
* again.
*/
void reset();
/**
* Check the trace header to make sure that it is of the right
* format.
*/
void init();
/**
* Attempt to read a trace element from the stream,
* and also notify the caller if the end of the file
* was reached.
*
* @param element Trace element to populate
* @return True if an element could be read successfully
*/
bool read(TraceElement& element);
};
public:
/**
* Create a trace generator.
*
* @param _name Name to use for status and debug
* @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(const std::string& _name, MasterID master_id, Tick _duration,
const std::string& trace_file, Addr addr_offset)
: BaseGen(_name, master_id, _duration),
trace(trace_file),
tickOffset(0),
addrOffset(addr_offset),
traceComplete(false)
{
}
void enter();
PacketPtr getNextPacket();
void exit();
/**
* 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(bool elastic, Tick delay) const;
private:
/** Input stream used for reading the input trace file */
InputStream trace;
/** 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. This is mutable
* to allow us to change it as part of nextPacketTick.
*/
mutable 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;
};
#endif