diff options
-rw-r--r-- | configs/dram/sweep.py | 37 | ||||
-rw-r--r-- | src/cpu/testers/traffic_gen/generators.cc | 194 | ||||
-rw-r--r-- | src/cpu/testers/traffic_gen/generators.hh | 99 | ||||
-rw-r--r-- | src/cpu/testers/traffic_gen/traffic_gen.cc | 52 |
4 files changed, 318 insertions, 64 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<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); - } + // pick a random rank + unsigned int new_rank = + random_mt.random<unsigned int>(0, nbrOfRanks - 1); + + // 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); + } 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 { 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", |