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.
This commit is contained in:
2021-05-05 16:13:44 +02:00
parent 1b0e6b1d33
commit 71551db4e3
10 changed files with 284 additions and 51 deletions

View File

@@ -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
}
]
}
}

View File

@@ -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++;
}

View File

@@ -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);

View File

@@ -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<uint64_t>(
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));
}

View File

@@ -41,16 +41,39 @@
#include "TracePlayer.h"
#include "TraceSetup.h"
#include <random>
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<uint64_t> randomAddressDistribution;
std::uniform_real_distribution<float> randomRwDistribution = std::uniform_real_distribution<float>(0.0f, 1.0f);
};
#endif // TRACEGENERATOR_H

View File

@@ -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;
}

View File

@@ -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

View File

@@ -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<TracePlayer *> *players)
TraceSetup::TraceSetup(const std::string &uri,
const std::string &pathToResources,
std::vector<TracePlayer *> &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()

View File

@@ -46,9 +46,9 @@ class TracePlayer;
class TraceSetup
{
public:
TraceSetup(std::string uri,
std::string pathToResources,
std::vector<TracePlayer *> *devices);
TraceSetup(const std::string &uri,
const std::string &pathToResources,
std::vector<TracePlayer *> &devices);
void tracePlayerTerminates();
void transactionFinished();

View File

@@ -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++)