cpu: DRAM Traffic Generator

This patch enables a new 'DRAM' mode to the existing traffic
generator, catered to generate specific requests to DRAM based on
required hit length (stride size) and bank utilization. It is an add on
to the Random mode.

The basic idea is to control how many successive packets target the
same page, and how many banks are being used in parallel. This gives a
two-dimensional space that stresses different aspects of the DRAM
timing.

The configuration file needed to use this patch has to be changed as
follow: (reference to Random Mode, LPDDR3 memory type)

'STATE 0 10000000000 RANDOM 50 0 134217728 64 3004 5002 0'
-> 'STATE 0 10000000000 DRAM 50 0 134217728 32 3004 5002 0 96 1024 8 6 1'

The last 4 parameters to be added are:
<stride size (bytes), page size(bytes), number of banks available in DRAM,
    number of banks to be utilized, address mapping scheme>

The address mapping information is used to get the stride address
stream of the specified size and to know where to find the bank
bits. The configuration file has a parameter where '0'-> RoCoRaBaCh,
'1'-> RoRaBaCoCh/RoRaBaChCo address-mapping schemes. Note that the
generator currently assumes a single channel and a single rank. This
is to avoid overwhelming the traffic generator with information about
the memory organisation.
This commit is contained in:
Neha Agarwal 2014-03-23 11:11:58 -04:00
parent 43abaf518f
commit 364a51181e
3 changed files with 238 additions and 3 deletions

View file

@ -37,6 +37,7 @@
* Authors: Thomas Grass
* Andreas Hansson
* Sascha Bischoff
* Neha Agarwal
*/
#include "base/random.hh"
@ -173,6 +174,94 @@ RandomGen::getNextPacket()
isRead ? MemCmd::ReadReq : MemCmd::WriteReq);
}
PacketPtr
DramGen::getNextPacket()
{
// if this is the first of the packets in series to be generated,
// start counting again
if (countNumSeqPkts == 0) {
countNumSeqPkts = numSeqPkts;
// choose if we generate a read or a write here
isRead = readPercent != 0 &&
(readPercent == 100 ||
random_mt.random<uint8_t>(0, 100) < readPercent);
assert((readPercent == 0 && !isRead) ||
(readPercent == 100 && isRead) ||
readPercent != 100);
// start by picking a random address in the range
addr = random_mt.random<Addr>(startAddr, endAddr - 1);
// round down to start address of a block, i.e. a DRAM burst
addr -= addr % blocksize;
// pick a random bank
unsigned int new_bank =
random_mt.random<unsigned int>(0, nbrOfBanksUtil - 1);
// next, inser the bank bits at the right spot, and align the
// address to achieve the required hit length, this involves
// finding the appropriate start address such that all
// sequential packets target successive columns in the same
// page
// for example, if we have a stride size of 192B, which means
// for LPDDR3 where burstsize = 32B we have numSeqPkts = 6,
// the address generated previously can be such that these
// 192B cross the page boundary, hence it needs to be aligned
// so that they all belong to the same page for page hit
unsigned int columns_per_page = pageSize / blocksize;
// pick a random column, but ensure that there is room for
// numSeqPkts sequential columns in the same page
unsigned int new_col =
random_mt.random<unsigned int>(0, columns_per_page - numSeqPkts);
if (addrMapping == 1) {
// assuming block bits, then page bits, then bank bits
replaceBits(addr, blockBits + pageBits + bankBits - 1,
blockBits + pageBits, new_bank);
replaceBits(addr, blockBits + pageBits - 1, blockBits, new_col);
} else if (addrMapping == 0) {
// assuming bank bits in the bottom
replaceBits(addr, blockBits + bankBits - 1, blockBits, new_bank);
replaceBits(addr, blockBits + bankBits + pageBits - 1,
blockBits + bankBits, new_col);
}
} else {
// increment the column by one
if (addrMapping == 1)
// column bits in the bottom, so just add a block
addr += blocksize;
else if (addrMapping == 0) {
// column bits are above the bank bits, so increment the column bits
unsigned int new_col = ((addr / blocksize / nbrOfBanksDRAM) %
(pageSize / blocksize)) + 1;
replaceBits(addr, blockBits + bankBits + pageBits - 1,
blockBits + bankBits, new_col);
}
}
DPRINTF(TrafficGen, "DramGen::getNextPacket: %c to addr %x, "
"size %d, countNumSeqPkts: %d, numSeqPkts: %d\n",
isRead ? 'r' : 'w', addr, blocksize, countNumSeqPkts, numSeqPkts);
// create a new request packet
PacketPtr pkt = getPacket(addr, blocksize,
isRead ? MemCmd::ReadReq : MemCmd::WriteReq);
// add the amount of data manipulated to the total
dataManipulated += blocksize;
// subtract the number of packets remained to be generated
--countNumSeqPkts;
// return the generated packet
return pkt;
}
Tick
RandomGen::nextPacketTick(bool elastic, Tick delay) const
{

View file

@ -37,6 +37,7 @@
* Authors: Thomas Grass
* Andreas Hansson
* Sascha Bischoff
* Neha Agarwal
*/
/**
@ -49,6 +50,8 @@
#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"
@ -273,7 +276,7 @@ class RandomGen : public BaseGen
Tick nextPacketTick(bool elastic, Tick delay) const;
private:
protected:
/** Start of address range */
const Addr startAddr;
@ -304,6 +307,99 @@ class RandomGen : public BaseGen
Addr dataManipulated;
};
/**
* DRAM specific generator is for issuing request with variable page
* hit length and bank utilization. Currently assumes a single
* channel, single rank 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 and single rank 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)
: RandomGen(_name, master_id, _duration, start_addr, end_addr,
_blocksize, min_period, max_period, read_percent, data_limit),
numSeqPkts(num_seq_pkts), countNumSeqPkts(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)
{
if (addrMapping != 1 && addrMapping != 0) {
addrMapping = 1;
warn("Unknown address mapping specified, using RoRaBaCoCh\n");
}
}
PacketPtr getNextPacket();
private:
/** 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;
};
/**
* The trace replay generator reads a trace file and plays
* back the transactions. The trace is offset with respect to

View file

@ -41,6 +41,7 @@
#include <sstream>
#include "base/intmath.hh"
#include "base/random.hh"
#include "cpu/testers/traffic_gen/traffic_gen.hh"
#include "debug/Checkpoint.hh"
@ -257,7 +258,8 @@ TrafficGen::parseConfig()
} else if (mode == "IDLE") {
states[id] = new IdleGen(name(), masterID, duration);
DPRINTF(TrafficGen, "State: %d IdleGen\n", id);
} else if (mode == "LINEAR" || mode == "RANDOM") {
} else if (mode == "LINEAR" || mode == "RANDOM" ||
mode == "DRAM") {
uint32_t read_percent;
Addr start_addr;
Addr end_addr;
@ -277,7 +279,7 @@ TrafficGen::parseConfig()
if (blocksize > system->cacheLineSize())
fatal("TrafficGen %s block size (%d) is larger than "
"system block size (%d)\n", name(),
"cache line size (%d)\n", name(),
blocksize, system->cacheLineSize());
if (read_percent > 100)
@ -300,6 +302,54 @@ TrafficGen::parseConfig()
min_period, max_period,
read_percent, data_limit);
DPRINTF(TrafficGen, "State: %d RandomGen\n", id);
} else if (mode == "DRAM") {
// stride size (bytes) of the request for achieving
// required hit length
unsigned int stride_size;
unsigned int page_size;
unsigned int nbr_of_banks_DRAM;
unsigned int nbr_of_banks_util;
unsigned int addr_mapping;
is >> stride_size >> page_size >> nbr_of_banks_DRAM >>
nbr_of_banks_util >> addr_mapping;
if (stride_size > page_size)
warn("DRAM generator stride size (%d) is greater "
"than page size (%d) of the memory\n",
blocksize, page_size);
if (nbr_of_banks_util > nbr_of_banks_DRAM)
fatal("Attempting to use more banks (%) than "
"what is available (%)\n",
nbr_of_banks_util, nbr_of_banks_DRAM);
if (nbr_of_banks_util > nbr_of_banks_DRAM)
fatal("Attempting to use more banks (%) than "
"what is available (%)\n",
nbr_of_banks_util, nbr_of_banks_DRAM);
// count the number of sequential packets to
// generate
unsigned int num_seq_pkts = 1;
if (stride_size > blocksize) {
num_seq_pkts = divCeil(stride_size, blocksize);
DPRINTF(TrafficGen, "stride size: %d "
"block size: %d, num_seq_pkts: %d\n",
stride_size, blocksize, num_seq_pkts);
}
states[id] = new DramGen(name(), masterID,
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);
DPRINTF(TrafficGen, "State: %d DramGen\n", id);
}
} else {
fatal("%s: Unknown traffic generator mode: %s",