From a384525355c37f8776e03c78e12279c38c5c3097 Mon Sep 17 00:00:00 2001 From: Wendy Elsasser Date: Sat, 20 Sep 2014 17:17:55 -0400 Subject: [PATCH] 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. --- configs/dram/sweep.py | 37 +++- src/cpu/testers/traffic_gen/generators.cc | 190 ++++++++++++++++----- src/cpu/testers/traffic_gen/generators.hh | 99 ++++++++++- src/cpu/testers/traffic_gen/traffic_gen.cc | 52 ++++-- 4 files changed, 316 insertions(+), 62 deletions(-) diff --git a/configs/dram/sweep.py b/configs/dram/sweep.py index 9b7cfd35e..631d82e07 100644 --- a/configs/dram/sweep.py +++ b/configs/dram/sweep.py @@ -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") diff --git a/src/cpu/testers/traffic_gen/generators.cc b/src/cpu/testers/traffic_gen/generators.cc index 135765fce..5e19384bc 100644 --- a/src/cpu/testers/traffic_gen/generators.cc +++ b/src/cpu/testers/traffic_gen/generators.cc @@ -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(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(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(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(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(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 { diff --git a/src/cpu/testers/traffic_gen/generators.hh b/src/cpu/testers/traffic_gen/generators.hh index a3b7e005a..5604856a9 100644 --- a/src/cpu/testers/traffic_gen/generators.hh +++ b/src/cpu/testers/traffic_gen/generators.hh @@ -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; }; /** diff --git a/src/cpu/testers/traffic_gen/traffic_gen.cc b/src/cpu/testers/traffic_gen/traffic_gen.cc index f865a00b1..9eee7a119 100644 --- a/src/cpu/testers/traffic_gen/traffic_gen.cc +++ b/src/cpu/testers/traffic_gen/traffic_gen.cc @@ -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",