cpu: Update DRAM traffic gen

Add new DRAM_ROTATE mode to traffic generator.
This mode will generate DRAM traffic that rotates across
banks per rank, command types, and ranks per channel

The looping order is illustrated below:
for (ranks per channel)
   for (command types)
      for (banks per rank)
         // Generate DRAM Command Series

This patch also adds the read percentage as an input argument to the
DRAM sweep script. If the simulated read percentage is 0 or 100, the
middle for loop does not generate additional commands.  This loop is
used only when the read percentage is set to 50, in which case the
middle loop will toggle between read and write commands.

Modified sweep.py script, which generates DRAM traffic.
Added input arguments and support for new DRAM_ROTATE mode.
The script now has input arguments for:
 1) Read percentage
 2) Number of ranks
 3) Address mapping
 4) Traffic generator mode  (DRAM or DRAM_ROTATE)

The default values are:
 100% reads, 1 rank, RoRaBaCoCh address mapping, and DRAM traffic gen mode

For the DRAM traffic mode, added multi-rank support.
This commit is contained in:
Wendy Elsasser 2014-09-20 17:17:55 -04:00
parent 3f7a9348dd
commit a384525355
4 changed files with 316 additions and 62 deletions

View file

@ -58,6 +58,20 @@ parser.add_option("--mem-type", type="choice", default="ddr3_1600_x64",
choices=MemConfig.mem_names(),
help = "type of memory to use")
parser.add_option("--ranks", "-r", type="int", default=1,
help = "Number of ranks to iterate across")
parser.add_option("--rd_perc", type="int", default=100,
help = "Percentage of read commands")
parser.add_option("--mode", type="choice", default="DRAM",
choices=["DRAM", "DRAM_ROTATE"],
help = "DRAM: Random traffic; \
DRAM_ROTATE: Traffic rotating across banks and ranks")
parser.add_option("--addr_map", type="int", default=1,
help = "0: RoCoRaBaCh; 1: RoRaBaCoCh/RoRaBaChCo")
(options, args) = parser.parse_args()
if args:
@ -89,8 +103,17 @@ MemConfig.config_mem(options, system)
if not isinstance(system.mem_ctrls[0], m5.objects.DRAMCtrl):
fatal("This script assumes the memory is a DRAMCtrl subclass")
# for now the generator assumes a single rank
system.mem_ctrls[0].ranks_per_channel = 1
# Set number of ranks based on input argument; default is 1 rank
system.mem_ctrls[0].ranks_per_channel = options.ranks
# Set the address mapping based on input argument
# Default to RoRaBaCoCh
if options.addr_map == 0:
system.mem_ctrls[0].addr_mapping = "RoCoRaBaCh"
elif options.addr_map == 1:
system.mem_ctrls[0].addr_mapping = "RoRaBaCoCh"
else:
fatal("Did not specify a valid address map argument")
# stay in each state for 0.25 ms, long enough to warm things up, and
# short enough to avoid hitting a refresh
@ -134,10 +157,12 @@ max_stride = min(512, page_size)
nxt_state = 0
for bank in range(1, nbr_banks + 1):
for stride_size in range(burst_size, max_stride + 1, burst_size):
cfg_file.write("STATE %d %d DRAM 100 0 %d "
"%d %d %d %d %d %d %d %d 1\n" %
(nxt_state, period, max_addr, burst_size, itt, itt, 0,
stride_size, page_size, nbr_banks, bank))
cfg_file.write("STATE %d %d %s %d 0 %d %d "
"%d %d %d %d %d %d %d %d %d\n" %
(nxt_state, period, options.mode, options.rd_perc,
max_addr, burst_size, itt, itt, 0, stride_size,
page_size, nbr_banks, bank, options.addr_map,
options.ranks))
nxt_state = nxt_state + 1
cfg_file.write("INIT 0\n")

View file

@ -190,56 +190,33 @@ DramGen::getNextPacket()
(readPercent == 100 && isRead) ||
readPercent != 100);
// start by picking a random address in the range
addr = random_mt.random(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
// pick a random rank
unsigned int new_rank =
random_mt.random<unsigned int>(0, nbrOfRanks - 1);
// 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;
// Generate the start address of the command series
// routine will update addr variable with bank, rank, and col
// bits updated for random traffic mode
genStartAddr(new_bank, new_rank);
// 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
// addrMapping=1: RoRaBaCoCh/RoRaBaChCo
// Simply increment addr by blocksize to increment the column by one
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) %
// addrMapping=0: RoCoRaBaCh
// Explicity increment the column bits
unsigned int new_col = ((addr / blocksize / nbrOfBanksDRAM / nbrOfRanks) %
(pageSize / blocksize)) + 1;
replaceBits(addr, blockBits + bankBits + pageBits - 1,
blockBits + bankBits, new_col);
replaceBits(addr, blockBits + bankBits + rankBits + pageBits - 1,
blockBits + bankBits + rankBits, new_col);
}
}
@ -261,6 +238,143 @@ DramGen::getNextPacket()
return pkt;
}
PacketPtr
DramRotGen::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
if (readPercent == 50) {
if ((nextSeqCount % nbrOfBanksUtil) == 0) {
// Change type after all banks have been rotated
// Otherwise, keep current value
isRead = !isRead;
}
} else {
// Set randomly based on percentage
isRead = readPercent != 0;
}
assert((readPercent == 0 && !isRead) ||
(readPercent == 100 && isRead) ||
readPercent != 100);
// Overwrite random bank value
// Rotate across banks
unsigned int new_bank = nextSeqCount % nbrOfBanksUtil;
// Overwrite random rank value
// Will rotate to the next rank after rotating through all banks,
// for each specified command type.
// Use modular function to ensure that calculated rank is within
// system limits after state transition
unsigned int new_rank = (nextSeqCount / maxSeqCountPerRank) %
nbrOfRanks;
// Increment nextSeqCount
// Roll back to 0 after completing a full rotation across
// banks, command type, and ranks
nextSeqCount = (nextSeqCount + 1) %
(nbrOfRanks * maxSeqCountPerRank);
DPRINTF(TrafficGen, "DramRotGen::getNextPacket nextSeqCount: %d "
"new_rank: %d new_bank: %d\n",
nextSeqCount, new_rank, new_bank);
// Generate the start address of the command series
// routine will update addr variable with bank, rank, and col
// bits updated for rotation scheme
genStartAddr(new_bank, new_rank);
} else {
// increment the column by one
if (addrMapping == 1)
// addrMapping=1: RoRaBaCoCh/RoRaBaChCo
// Simply increment addr by blocksize to increment the column by one
addr += blocksize;
else if (addrMapping == 0) {
// addrMapping=0: RoCoRaBaCh
// Explicity increment the column bits
unsigned int new_col = ((addr / blocksize / nbrOfBanksDRAM / nbrOfRanks) %
(pageSize / blocksize)) + 1;
replaceBits(addr, blockBits + bankBits + rankBits + pageBits - 1,
blockBits + bankBits + rankBits, new_col);
}
}
DPRINTF(TrafficGen, "DramRotGen::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;
}
void
DramGen::genStartAddr(unsigned int new_bank, unsigned int new_rank)
{
// 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;
// insert 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) {
// addrMapping=1: RoRaBaCoCh/RoRaBaChCo
// Block bits, then page bits, then bank bits, then rank bits
replaceBits(addr, blockBits + pageBits + bankBits - 1,
blockBits + pageBits, new_bank);
replaceBits(addr, blockBits + pageBits - 1, blockBits, new_col);
if (rankBits != 0) {
replaceBits(addr, blockBits + pageBits + bankBits +rankBits - 1,
blockBits + pageBits + bankBits, new_rank);
}
} else if (addrMapping == 0) {
// addrMapping=0: RoCoRaBaCh
// Block bits, then bank bits, then rank bits, then page bits
replaceBits(addr, blockBits + bankBits - 1, blockBits, new_bank);
replaceBits(addr, blockBits + bankBits + rankBits + pageBits - 1,
blockBits + bankBits + rankBits, new_col);
if (rankBits != 0) {
replaceBits(addr, blockBits + bankBits + rankBits - 1,
blockBits + bankBits, new_rank);
}
}
}
Tick
RandomGen::nextPacketTick(bool elastic, Tick delay) const
{

View file

@ -310,7 +310,7 @@ class RandomGen : public BaseGen
/**
* DRAM specific generator is for issuing request with variable page
* hit length and bank utilization. Currently assumes a single
* channel, single rank configuration.
* channel configuration.
*/
class DramGen : public RandomGen
{
@ -337,7 +337,7 @@ class DramGen : public RandomGen
* 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
* assumes single channel system
*/
DramGen(const std::string& _name, MasterID master_id, Tick _duration,
Addr start_addr, Addr end_addr, Addr _blocksize,
@ -345,7 +345,8 @@ class DramGen : public RandomGen
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 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),
@ -354,7 +355,9 @@ class DramGen : public RandomGen
bankBits(floorLog2(nbr_of_banks_DRAM)),
blockBits(floorLog2(_blocksize)),
nbrOfBanksDRAM(nbr_of_banks_DRAM),
nbrOfBanksUtil(nbr_of_banks_util), addrMapping(addr_mapping)
nbrOfBanksUtil(nbr_of_banks_util), addrMapping(addr_mapping),
rankBits(floorLog2(nbr_of_ranks)),
nbrOfRanks(nbr_of_ranks)
{
if (addrMapping != 1 && addrMapping != 0) {
addrMapping = 1;
@ -364,7 +367,15 @@ class DramGen : public RandomGen
PacketPtr getNextPacket();
private:
/** 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;
@ -398,6 +409,84 @@ class DramGen : public RandomGen
/** 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;
};
/**

View file

@ -268,7 +268,7 @@ TrafficGen::parseConfig()
states[id] = new IdleGen(name(), masterID, duration);
DPRINTF(TrafficGen, "State: %d IdleGen\n", id);
} else if (mode == "LINEAR" || mode == "RANDOM" ||
mode == "DRAM") {
mode == "DRAM" || mode == "DRAM_ROTATE") {
uint32_t read_percent;
Addr start_addr;
Addr end_addr;
@ -311,7 +311,7 @@ TrafficGen::parseConfig()
min_period, max_period,
read_percent, data_limit);
DPRINTF(TrafficGen, "State: %d RandomGen\n", id);
} else if (mode == "DRAM") {
} else if (mode == "DRAM" || mode == "DRAM_ROTATE") {
// stride size (bytes) of the request for achieving
// required hit length
unsigned int stride_size;
@ -319,9 +319,11 @@ TrafficGen::parseConfig()
unsigned int nbr_of_banks_DRAM;
unsigned int nbr_of_banks_util;
unsigned int addr_mapping;
unsigned int nbr_of_ranks;
is >> stride_size >> page_size >> nbr_of_banks_DRAM >>
nbr_of_banks_util >> addr_mapping;
nbr_of_banks_util >> addr_mapping >>
nbr_of_ranks;
if (stride_size > page_size)
warn("DRAM generator stride size (%d) is greater "
@ -349,16 +351,40 @@ TrafficGen::parseConfig()
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);
if (mode == "DRAM") {
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,
nbr_of_ranks);
DPRINTF(TrafficGen, "State: %d DramGen\n", id);
} else {
// Will rotate to the next rank after rotating
// through all banks, for each command type.
// In the 50% read case, series will be issued
// for both RD & WR before the rank in incremented
unsigned int max_seq_count_per_rank =
(read_percent == 50) ? nbr_of_banks_util * 2
: nbr_of_banks_util;
states[id] = new DramRotGen(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,
nbr_of_ranks,
max_seq_count_per_rank);
DPRINTF(TrafficGen, "State: %d DramRotGen\n", id);
}
}
} else {
fatal("%s: Unknown traffic generator mode: %s",