From 71551db4e3491db203b3f9da395d6762c33567d5 Mon Sep 17 00:00:00 2001 From: Derek Christ Date: Wed, 5 May 2021 16:13:44 +0200 Subject: [PATCH] Implement a more advanced TraceGenerator Implementation of a more advanced TraceGenerator that can be configured using the Json config file. The new TraceGenerator is capable of specifing the number of requests to make, the ratio of read and write accesses, the distribution of the addresses, the address increment value in case of a sequential address distribution, a seed in case of a random address distribution and the maximum number of pending read or write requests. The maximum number of pending requests was also implemented for the StlPlayer. --- .../simulations/ddr5-generator-example.json | 34 +++++ DRAMSys/simulator/StlPlayer.cpp | 15 +- DRAMSys/simulator/StlPlayer.h | 6 +- DRAMSys/simulator/TraceGenerator.cpp | 70 ++++++++-- DRAMSys/simulator/TraceGenerator.h | 27 +++- DRAMSys/simulator/TracePlayer.cpp | 37 ++++- DRAMSys/simulator/TracePlayer.h | 10 +- DRAMSys/simulator/TraceSetup.cpp | 128 ++++++++++++++---- DRAMSys/simulator/TraceSetup.h | 6 +- DRAMSys/simulator/main.cpp | 2 +- 10 files changed, 284 insertions(+), 51 deletions(-) create mode 100644 DRAMSys/library/resources/simulations/ddr5-generator-example.json diff --git a/DRAMSys/library/resources/simulations/ddr5-generator-example.json b/DRAMSys/library/resources/simulations/ddr5-generator-example.json new file mode 100644 index 00000000..1835e48b --- /dev/null +++ b/DRAMSys/library/resources/simulations/ddr5-generator-example.json @@ -0,0 +1,34 @@ +{ + "simulation": { + "addressmapping": "am_ddr5_2x8x2Gbx4_dimm_p1KB_rbc.json", + "mcconfig": "fr_fcfs.json", + "memspec": "JEDEC_2x8x2Gbx4_DDR5-3200A.json", + "simconfig": "ddr5.json", + "simulationid": "ddr5-example", + "thermalconfig": "config.json", + "tracesetup": [ + { + "clkMhz": 2000, + "type": "generator", + "name": "gen0", + "numRequests": 2000, + "rwRatio": 0.85, + "addressDistribution": "sequential", + "addressIncrement": 256, + "maxPendingReadRequests": 8, + "maxPendingWriteRequests": 8 + }, + { + "clkMhz": 2000, + "type": "generator", + "name": "gen1", + "numRequests": 2000, + "rwRatio": 0.85, + "addressDistribution": "random", + "seed": 123456, + "maxPendingReadRequests": 8, + "maxPendingWriteRequests": 8 + } + ] + } +} diff --git a/DRAMSys/simulator/StlPlayer.cpp b/DRAMSys/simulator/StlPlayer.cpp index 4880b5b0..5303be41 100644 --- a/DRAMSys/simulator/StlPlayer.cpp +++ b/DRAMSys/simulator/StlPlayer.cpp @@ -41,9 +41,11 @@ using namespace tlm; -StlPlayer::StlPlayer(sc_module_name name, - std::string pathToTrace, +StlPlayer::StlPlayer(const sc_module_name &name, + const std::string &pathToTrace, sc_time playerClk, + unsigned int maxPendingReadRequests, + unsigned int maxPendingWriteRequests, TraceSetup *setup, bool relative) : TracePlayer(name, setup), file(pathToTrace), @@ -54,6 +56,9 @@ StlPlayer::StlPlayer(sc_module_name name, if (!file.is_open()) SC_REPORT_FATAL("StlPlayer", (std::string("Could not open trace ") + pathToTrace).c_str()); + this->maxPendingReadRequests = maxPendingReadRequests; + this->maxPendingWriteRequests = maxPendingWriteRequests; + this->playerClk = playerClk; burstlength = Configuration::getInstance().memSpec->burstLength; dataLength = Configuration::getInstance().memSpec->bytesPerBurst; @@ -117,6 +122,12 @@ void StlPlayer::nextPayload() sendToTarget(*payload, BEGIN_REQ, sendingTime - sc_time_stamp()); transactionsSent++; + + if (payload->get_command() == tlm::TLM_READ_COMMAND) + pendingReadRequests++; + else if (payload->get_command() == tlm::TLM_WRITE_COMMAND) + pendingWriteRequests++; + PRINTDEBUGMESSAGE(name(), "Performing request #" + std::to_string(transactionsSent)); lineIterator++; } diff --git a/DRAMSys/simulator/StlPlayer.h b/DRAMSys/simulator/StlPlayer.h index 27081d41..45a1769b 100644 --- a/DRAMSys/simulator/StlPlayer.h +++ b/DRAMSys/simulator/StlPlayer.h @@ -58,9 +58,11 @@ struct LineContent class StlPlayer : public TracePlayer { public: - StlPlayer(sc_module_name name, - std::string pathToTrace, + StlPlayer(const sc_module_name &name, + const std::string &pathToTrace, sc_time playerClk, + unsigned int maxPendingReadRequests, + unsigned int maxPendingWriteRequests, TraceSetup *setup, bool relative); diff --git a/DRAMSys/simulator/TraceGenerator.cpp b/DRAMSys/simulator/TraceGenerator.cpp index b08080ee..8620d0e5 100644 --- a/DRAMSys/simulator/TraceGenerator.cpp +++ b/DRAMSys/simulator/TraceGenerator.cpp @@ -37,40 +37,84 @@ #include "TraceGenerator.h" -TraceGenerator::TraceGenerator(sc_module_name name, - unsigned int fCKMhz, TraceSetup *setup) - : TracePlayer(name, setup), transCounter(0) +TraceGenerator::TraceGenerator(const sc_module_name &name, + const sc_time &tCK, + uint64_t numRequests, + unsigned int maxPendingReadRequests, + unsigned int maxPendingWriteRequests, + float rwRatio, + AddressDistribution addressDistribution, + unsigned int addressIncrement, + unsigned int seed, + TraceSetup *setup) : + TracePlayer(name, setup), tCK(tCK), numRequests(numRequests), + rwRatio(rwRatio), addressDistribution(addressDistribution), + addressIncrement(addressIncrement) { - if (fCKMhz == 0) - tCK = Configuration::getInstance().memSpec->tCK; - else - tCK = sc_time(1.0 / fCKMhz, SC_US); - burstlenght = Configuration::getInstance().memSpec->burstLength; + + this->maxPendingReadRequests = maxPendingReadRequests; + this->maxPendingWriteRequests = maxPendingWriteRequests; + + randomGenerator = std::default_random_engine(seed); + randomAddressDistribution = std::uniform_int_distribution( + 0, Configuration::getInstance().memSpec->getSimMemSizeInBytes()); + } void TraceGenerator::nextPayload() { - if (transCounter >= 1000) // TODO set limit! - terminate(); + if (transCounter >= numRequests) { + finished = true; + return; + } tlm::tlm_generic_payload *payload = setup->allocatePayload(); payload->acquire(); unsigned char *dataElement = new unsigned char[16]; // TODO: column / burst breite - payload->set_address(0x0); + uint64_t address; + if (addressDistribution == AddressDistribution::Sequential) { + address = currentAddress; + currentAddress += addressIncrement; + } else { + // AddressDistribution::Random + address = randomAddressDistribution(randomGenerator); + } + + tlm::tlm_command command; + if (randomRwDistribution(randomGenerator) < rwRatio) { + command = tlm::TLM_READ_COMMAND; + } else { + command = tlm::TLM_WRITE_COMMAND; + } + + payload->set_address(address); payload->set_response_status(tlm::TLM_INCOMPLETE_RESPONSE); payload->set_dmi_allowed(false); payload->set_byte_enable_length(0); payload->set_streaming_width(burstlenght); payload->set_data_ptr(dataElement); payload->set_data_length(16); - payload->set_command(tlm::TLM_READ_COMMAND); + payload->set_command(command); transCounter++; + sc_time sendingOffset; + if (lastEndReq == sc_time_stamp()) + sendingOffset = tCK; + else + sendingOffset = SC_ZERO_TIME; + // TODO: do not send two requests in the same cycle - sendToTarget(*payload, tlm::BEGIN_REQ, SC_ZERO_TIME); + sendToTarget(*payload, tlm::BEGIN_REQ, sendingOffset); + transactionsSent++; + + if (command == tlm::TLM_READ_COMMAND) + pendingReadRequests++; + else if (command == tlm::TLM_WRITE_COMMAND) + pendingWriteRequests++; + PRINTDEBUGMESSAGE(name(), "Performing request #" + std::to_string(transactionsSent)); } diff --git a/DRAMSys/simulator/TraceGenerator.h b/DRAMSys/simulator/TraceGenerator.h index 8993e8d3..58cc9006 100644 --- a/DRAMSys/simulator/TraceGenerator.h +++ b/DRAMSys/simulator/TraceGenerator.h @@ -41,16 +41,39 @@ #include "TracePlayer.h" #include "TraceSetup.h" +#include + +enum class AddressDistribution {Sequential, Random}; + class TraceGenerator : public TracePlayer { public: - TraceGenerator(sc_module_name name, unsigned int fCKMhz, TraceSetup *setup); + TraceGenerator(const sc_module_name &name, + const sc_time &tCK, + uint64_t numRequests, + unsigned int maxPendingReadRequests, + unsigned int maxPendingWriteRequests, + float rwRatio, + AddressDistribution addressDistribution, + unsigned int addressIncrement, + unsigned int seed, + TraceSetup *setup); + virtual void nextPayload() override; private: unsigned int burstlenght; sc_time tCK; - unsigned int transCounter; + unsigned int numRequests; + float rwRatio; + AddressDistribution addressDistribution; + unsigned int addressIncrement; + unsigned int transCounter = 0; + unsigned int currentAddress = 0x0; + + std::default_random_engine randomGenerator; + std::uniform_int_distribution randomAddressDistribution; + std::uniform_real_distribution randomRwDistribution = std::uniform_real_distribution(0.0f, 1.0f); }; #endif // TRACEGENERATOR_H diff --git a/DRAMSys/simulator/TracePlayer.cpp b/DRAMSys/simulator/TracePlayer.cpp index 4c588668..393673b6 100644 --- a/DRAMSys/simulator/TracePlayer.cpp +++ b/DRAMSys/simulator/TracePlayer.cpp @@ -74,7 +74,11 @@ void TracePlayer::peqCallback(tlm_generic_payload &payload, if (phase == END_REQ) { lastEndReq = sc_time_stamp(); - nextPayload(); + + if (nextPayloadSendable()) + nextPayload(); + else + payloadPostponed = true; } else if (phase == BEGIN_RESP) { @@ -85,8 +89,19 @@ void TracePlayer::peqCallback(tlm_generic_payload &payload, transactionsReceived++; + if (payload.get_command() == tlm::TLM_READ_COMMAND) + pendingReadRequests--; + else if (payload.get_command() == tlm::TLM_WRITE_COMMAND) + pendingWriteRequests--; + + // If the initiator wasn't able to send the next payload in the END_REQ phase, do it now. + if (payloadPostponed) { + nextPayload(); + payloadPostponed = false; + } + // If all answers were received: - if (finished == true && numberOfTransactions == transactionsReceived) + if (finished == true && transactionsSent == transactionsReceived) terminate(); } else @@ -128,3 +143,21 @@ uint64_t TracePlayer::getNumberOfLines(std::string pathToTrace) return 0; } } + +bool TracePlayer::nextPayloadSendable() +{ + bool sendable = true; + + // If either the maxPendingReadRequests or maxPendingWriteRequests + // limit is reached, do not send next payload. + if (pendingReadRequests >= maxPendingReadRequests && maxPendingReadRequests != 0) + { + sendable = false; + } + else if (pendingWriteRequests >= maxPendingWriteRequests && maxPendingWriteRequests != 0) + { + sendable = false; + } + + return sendable; +} diff --git a/DRAMSys/simulator/TracePlayer.h b/DRAMSys/simulator/TracePlayer.h index 7144c95a..c1e15dd5 100644 --- a/DRAMSys/simulator/TracePlayer.h +++ b/DRAMSys/simulator/TracePlayer.h @@ -66,16 +66,24 @@ protected: TraceSetup *setup; void sendToTarget(tlm::tlm_generic_payload &payload, const tlm::tlm_phase &phase, const sc_time &delay); + uint64_t numberOfTransactions = 0; + uint64_t transactionsReceived = 0; uint64_t transactionsSent = 0; + unsigned int pendingReadRequests = 0; + unsigned int pendingWriteRequests = 0; + unsigned int maxPendingReadRequests = 0; + unsigned int maxPendingWriteRequests = 0; + bool payloadPostponed = false; bool finished = false; sc_time lastEndReq = sc_max_time(); + sc_event transactionFinished; private: tlm::tlm_sync_enum nb_transport_bw(tlm::tlm_generic_payload &payload, tlm::tlm_phase &phase, sc_time &bwDelay); void peqCallback(tlm::tlm_generic_payload &payload, const tlm::tlm_phase &phase); - uint64_t transactionsReceived = 0; + bool nextPayloadSendable(); }; #endif // TRACEPLAYER_H diff --git a/DRAMSys/simulator/TraceSetup.cpp b/DRAMSys/simulator/TraceSetup.cpp index 871be829..015bd163 100644 --- a/DRAMSys/simulator/TraceSetup.cpp +++ b/DRAMSys/simulator/TraceSetup.cpp @@ -36,12 +36,13 @@ #include "TraceSetup.h" #include "StlPlayer.h" +#include "TraceGenerator.h" using namespace tlm; -TraceSetup::TraceSetup(std::string uri, - std::string pathToResources, - std::vector *players) +TraceSetup::TraceSetup(const std::string &uri, + const std::string &pathToResources, + std::vector &players) { // Load Simulation: nlohmann::json simulationdoc = parseJSON(uri); @@ -53,52 +54,129 @@ TraceSetup::TraceSetup(std::string uri, // Load TracePlayers: if (simulationdoc["simulation"]["tracesetup"].empty()) SC_REPORT_FATAL("TraceSetup", "tracesetup is empty"); - for (auto it : simulationdoc["simulation"]["tracesetup"].items()) + for (auto &it : simulationdoc["simulation"]["tracesetup"].items()) { auto value = it.value(); if (!value.empty()) { sc_time playerClk; + if (!value["clkMhz"].is_number_unsigned()) + SC_REPORT_FATAL("TraceSetup", "Frequency is not a number."); + unsigned int frequencyMHz = value["clkMhz"]; if (frequencyMHz == 0) - SC_REPORT_FATAL("TraceSetup", "No frequency defined"); + SC_REPORT_FATAL("TraceSetup", "Frequency must not be zero."); else playerClk = sc_time(1.0 / frequencyMHz, SC_US); + if (!value["name"].is_string()) + SC_REPORT_FATAL("TraceSetup", "No trace name defined."); + std::string name = value["name"]; - size_t pos = name.rfind('.'); - if (pos == std::string::npos) - throw std::runtime_error("Name of the trace file does not contain a valid extension."); + unsigned int maxPendingReadRequests = 0; + unsigned int maxPendingWriteRequests = 0; - // Get the extension and make it lower case - std::string ext = name.substr(pos + 1); - std::transform(ext.begin(), ext.end(), ext.begin(), ::tolower); + if (value["maxPendingReadRequests"].is_number_unsigned()) + maxPendingReadRequests = value["maxPendingReadRequests"]; - std::string stlFile = pathToResources + std::string("traces/") + name; - std::string moduleName = name; + if (value["maxPendingWriteRequests"].is_number_unsigned()) + maxPendingWriteRequests = value["maxPendingWriteRequests"]; - // replace all '.' to '_' - std::replace(moduleName.begin(), moduleName.end(), '.', '_'); + std::string type; - TracePlayer *player; - if (ext == "stl") - player = new StlPlayer(moduleName.c_str(), stlFile, playerClk, this, false); - else if (ext == "rstl") - player = new StlPlayer(moduleName.c_str(), stlFile, playerClk, this, true); + // Defaulting to type "player" when not specified + if (!value["type"].is_string()) + type = "player"; else - throw std::runtime_error("Unsupported file extension in " + name); + type = value["type"]; - players->push_back(player); + if (type == "player") + { + size_t pos = name.rfind('.'); + if (pos == std::string::npos) + throw std::runtime_error("Name of the trace file does not contain a valid extension."); - if (Configuration::getInstance().simulationProgressBar) - totalTransactions += player->getNumberOfLines(stlFile); + // Get the extension and make it lower case + std::string ext = name.substr(pos + 1); + std::transform(ext.begin(), ext.end(), ext.begin(), ::tolower); + + std::string stlFile = pathToResources + std::string("traces/") + name; + std::string moduleName = name; + + // replace all '.' to '_' + std::replace(moduleName.begin(), moduleName.end(), '.', '_'); + + TracePlayer *player; + if (ext == "stl") + player = new StlPlayer(moduleName.c_str(), stlFile, playerClk, + maxPendingReadRequests, maxPendingWriteRequests, this, false); + else if (ext == "rstl") + player = new StlPlayer(moduleName.c_str(), stlFile, playerClk, + maxPendingReadRequests, maxPendingWriteRequests, this, true); + else + throw std::runtime_error("Unsupported file extension in " + name); + + players.push_back(player); + + if (Configuration::getInstance().simulationProgressBar) + totalTransactions += player->getNumberOfLines(stlFile); + } + else if (type == "generator") + { + if (!value["numRequests"].is_number_unsigned()) + SC_REPORT_FATAL("TraceSetup", "Number of requests is not a number."); + + uint64_t numRequests = value["numRequests"]; + + if (!value["rwRatio"].is_number_float()) + SC_REPORT_FATAL("TraceSetup", "Read/Write ratio is not a floating point number."); + + float rwRatio = value["rwRatio"]; + + if (!value["addressDistribution"].is_string()) + SC_REPORT_FATAL("TraceSetup", "Address distribution not defined."); + + AddressDistribution addressDistribution = AddressDistribution::Sequential; + std::string addressDistributionString = value["addressDistribution"]; + if (addressDistributionString == "sequential") + addressDistribution = AddressDistribution::Sequential; + else if (addressDistributionString == "random") + addressDistribution = AddressDistribution::Random; + else + SC_REPORT_FATAL("TraceSetup", "Address distribution must either be sequential or random."); + + unsigned int addressIncrement = 0x0; + unsigned int seed = 0; + if (addressDistribution == AddressDistribution::Sequential) { + if (!value["addressIncrement"].is_number_unsigned()) + SC_REPORT_FATAL("TraceSetup", "Address increment is not a number."); + + addressIncrement = value["addressIncrement"]; + } else { + // addressDistribution == AddressDistribution::Random + if (!value["seed"].is_number_unsigned()) + SC_REPORT_FATAL("TraceSetup", "Seed is not a number."); + + seed = value["seed"]; + } + + TracePlayer *player = new TraceGenerator(name.c_str(), playerClk, numRequests, + maxPendingReadRequests, maxPendingWriteRequests, + rwRatio, addressDistribution, + addressIncrement, seed, this); + + players.push_back(player); + + if (Configuration::getInstance().simulationProgressBar) + totalTransactions += numRequests; + } } } remainingTransactions = totalTransactions; - numberOfTracePlayers = players->size(); + numberOfTracePlayers = players.size(); } void TraceSetup::tracePlayerTerminates() diff --git a/DRAMSys/simulator/TraceSetup.h b/DRAMSys/simulator/TraceSetup.h index 5194c29a..52df9157 100644 --- a/DRAMSys/simulator/TraceSetup.h +++ b/DRAMSys/simulator/TraceSetup.h @@ -46,9 +46,9 @@ class TracePlayer; class TraceSetup { public: - TraceSetup(std::string uri, - std::string pathToResources, - std::vector *devices); + TraceSetup(const std::string &uri, + const std::string &pathToResources, + std::vector &devices); void tracePlayerTerminates(); void transactionFinished(); diff --git a/DRAMSys/simulator/main.cpp b/DRAMSys/simulator/main.cpp index c742527a..40f7fe83 100644 --- a/DRAMSys/simulator/main.cpp +++ b/DRAMSys/simulator/main.cpp @@ -109,7 +109,7 @@ int sc_main(int argc, char **argv) dramSys = new DRAMSys("DRAMSys", simulationJson, resources); // Instantiate STL Players: - TraceSetup *setup = new TraceSetup(simulationJson, resources, &players); + TraceSetup *setup = new TraceSetup(simulationJson, resources, players); // Bind STL Players with DRAMSys: for (size_t i = 0; i < players.size(); i++)