From: Neha Agarwal Date: Sun, 23 Mar 2014 15:11:58 +0000 (-0400) Subject: cpu: DRAM Traffic Generator X-Git-Url: https://git.libre-soc.org/?a=commitdiff_plain;h=364a51181ea4fb09ee24f5a57eb293744075b326;p=gem5.git 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: 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. --- diff --git a/src/cpu/testers/traffic_gen/generators.cc b/src/cpu/testers/traffic_gen/generators.cc index 9d0c7e02c..f0c126a81 100644 --- a/src/cpu/testers/traffic_gen/generators.cc +++ b/src/cpu/testers/traffic_gen/generators.cc @@ -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(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(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 + + // 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) { + // 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 { diff --git a/src/cpu/testers/traffic_gen/generators.hh b/src/cpu/testers/traffic_gen/generators.hh index fe5c5995c..498ef8f37 100644 --- a/src/cpu/testers/traffic_gen/generators.hh +++ b/src/cpu/testers/traffic_gen/generators.hh @@ -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 diff --git a/src/cpu/testers/traffic_gen/traffic_gen.cc b/src/cpu/testers/traffic_gen/traffic_gen.cc index 4b2259bd9..d53c9b000 100644 --- a/src/cpu/testers/traffic_gen/traffic_gen.cc +++ b/src/cpu/testers/traffic_gen/traffic_gen.cc @@ -41,6 +41,7 @@ #include +#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",