Allow variable data length in memory manager.

This commit is contained in:
Lukas Steiner
2022-02-15 17:00:23 +01:00
parent b272baa6f9
commit 7991ef5a2a
8 changed files with 54 additions and 42 deletions

View File

@@ -192,7 +192,7 @@ void LengthConverter::createChildTranses(tlm_generic_payload* parentTrans)
ParentExtension::setExtension(parentTrans, std::move(childTranses)); ParentExtension::setExtension(parentTrans, std::move(childTranses));
} }
LengthConverter::MemoryManager::MemoryManager(bool storageEnabled, size_t maxDataLength) LengthConverter::MemoryManager::MemoryManager(bool storageEnabled, unsigned maxDataLength)
: storageEnabled(storageEnabled), maxDataLength(maxDataLength) : storageEnabled(storageEnabled), maxDataLength(maxDataLength)
{} {}

View File

@@ -88,7 +88,7 @@ private:
class MemoryManager : public tlm::tlm_mm_interface class MemoryManager : public tlm::tlm_mm_interface
{ {
public: public:
MemoryManager(bool storageEnabled, std::size_t maxDataLength); MemoryManager(bool storageEnabled, unsigned maxDataLength);
~MemoryManager() override; ~MemoryManager() override;
tlm::tlm_generic_payload* allocate(); tlm::tlm_generic_payload* allocate();
void free(tlm::tlm_generic_payload* payload) override; void free(tlm::tlm_generic_payload* payload) override;
@@ -96,7 +96,7 @@ private:
private: private:
std::stack<tlm::tlm_generic_payload*> freePayloads; std::stack<tlm::tlm_generic_payload*> freePayloads;
bool storageEnabled = false; bool storageEnabled = false;
std::size_t maxDataLength; unsigned maxDataLength;
} memoryManager; } memoryManager;
class ChildExtension : public tlm::tlm_extension<ChildExtension> class ChildExtension : public tlm::tlm_extension<ChildExtension>

View File

@@ -51,17 +51,18 @@ MemoryManager::MemoryManager()
MemoryManager::~MemoryManager() MemoryManager::~MemoryManager()
{ {
for (tlm_generic_payload *payload : freePayloads) for (auto& innerBuffer : freePayloads)
{ {
if (storageEnabled) while (!innerBuffer.second.empty())
{ {
// Delete data buffer tlm_generic_payload* payload = innerBuffer.second.top();
delete[] payload->get_data_ptr(); if (storageEnabled)
delete[] payload->get_data_ptr();
payload->reset();
delete payload;
innerBuffer.second.pop();
numberOfFrees++;
} }
// Delete all extensions
payload->reset();
delete payload;
numberOfFrees++;
} }
// Comment in if you are suspecting a memory leak in the manager // Comment in if you are suspecting a memory leak in the manager
@@ -69,18 +70,17 @@ MemoryManager::~MemoryManager()
//PRINTDEBUGMESSAGE("MemoryManager","Number of freed payloads: " + to_string(numberOfFrees)); //PRINTDEBUGMESSAGE("MemoryManager","Number of freed payloads: " + to_string(numberOfFrees));
} }
tlm_generic_payload *MemoryManager::allocate() tlm_generic_payload *MemoryManager::allocate(unsigned dataLength)
{ {
if (freePayloads.empty()) if (freePayloads[dataLength].empty())
{ {
numberOfAllocations++; numberOfAllocations++;
tlm_generic_payload *payload = new tlm_generic_payload(this); auto* payload = new tlm_generic_payload(this);
if (storageEnabled) if (storageEnabled)
{ {
// Allocate a data buffer and initialize it with zeroes: // Allocate a data buffer and initialize it with zeroes:
unsigned int dataLength = Configuration::getInstance().memSpec->maxBytesPerBurst; auto* data = new unsigned char[dataLength];
unsigned char *data = new unsigned char[dataLength];
std::fill(data, data + dataLength, 0); std::fill(data, data + dataLength, 0);
payload->set_data_ptr(data); payload->set_data_ptr(data);
} }
@@ -89,13 +89,14 @@ tlm_generic_payload *MemoryManager::allocate()
} }
else else
{ {
tlm_generic_payload *result = freePayloads.back(); tlm_generic_payload *result = freePayloads[dataLength].top();
freePayloads.pop_back(); freePayloads[dataLength].pop();
return result; return result;
} }
} }
void MemoryManager::free(tlm_generic_payload *payload) void MemoryManager::free(tlm_generic_payload *payload)
{ {
freePayloads.push_back(payload); unsigned dataLength = payload->get_data_length();
freePayloads[dataLength].push(payload);
} }

View File

@@ -37,7 +37,8 @@
#ifndef MEMORYMANAGER_H #ifndef MEMORYMANAGER_H
#define MEMORYMANAGER_H #define MEMORYMANAGER_H
#include <vector> #include <unordered_map>
#include <stack>
#include <tlm> #include <tlm>
@@ -46,13 +47,13 @@ class MemoryManager : public tlm::tlm_mm_interface
public: public:
MemoryManager(); MemoryManager();
~MemoryManager() override; ~MemoryManager() override;
tlm::tlm_generic_payload *allocate(); tlm::tlm_generic_payload *allocate(unsigned dataLength);
void free(tlm::tlm_generic_payload *payload) override; void free(tlm::tlm_generic_payload *payload) override;
private: private:
uint64_t numberOfAllocations; uint64_t numberOfAllocations;
uint64_t numberOfFrees; uint64_t numberOfFrees;
std::vector<tlm::tlm_generic_payload *> freePayloads; std::unordered_map<unsigned, std::stack<tlm::tlm_generic_payload *>> freePayloads;
bool storageEnabled = false; bool storageEnabled = false;
}; };

View File

@@ -101,7 +101,7 @@ void StlPlayer::sendNextPayload()
} }
// Allocate a generic payload for this request. // Allocate a generic payload for this request.
tlm_generic_payload *payload = setup->allocatePayload(); tlm_generic_payload *payload = setup->allocatePayload(lineIterator->dataLength);
payload->acquire(); payload->acquire();
// Fill up the payload. // Fill up the payload.
@@ -169,20 +169,20 @@ void StlPlayer::parseTraceFile()
// Get the timestamp for the transaction. // Get the timestamp for the transaction.
iss >> element; iss >> element;
if (element.empty()) if (element.empty())
SC_REPORT_FATAL("StlPlayer", ("Malformed trace file line " + std::to_string(lineCnt) + ").").c_str()); SC_REPORT_FATAL("StlPlayer", ("Malformed trace file line " + std::to_string(lineCnt) + ".").c_str());
content.sendingTime = playerClk * static_cast<double>(std::stoull(element)); content.sendingTime = playerClk * static_cast<double>(std::stoull(element));
// Get the optional burst length and command // Get the optional burst length and command
iss >> element; iss >> element;
if (element.empty()) if (element.empty())
SC_REPORT_FATAL("StlPlayer", ("Malformed trace file line " + std::to_string(lineCnt) + ").").c_str()); SC_REPORT_FATAL("StlPlayer", ("Malformed trace file line " + std::to_string(lineCnt) + ".").c_str());
if (element.at(0) == '(') if (element.at(0) == '(')
{ {
element.erase(0, 1); element.erase(0, 1);
content.dataLength = std::stoul(element); content.dataLength = std::stoul(element);
iss >> element; iss >> element;
if (element.empty()) if (element.empty())
SC_REPORT_FATAL("StlPlayer", ("Malformed trace file line " + std::to_string(lineCnt) + ").").c_str()); SC_REPORT_FATAL("StlPlayer", ("Malformed trace file line " + std::to_string(lineCnt) + ".").c_str());
} }
else else
content.dataLength = defaultDataLength; content.dataLength = defaultDataLength;
@@ -192,12 +192,12 @@ void StlPlayer::parseTraceFile()
else if (element == "write") else if (element == "write")
content.command = TLM_WRITE_COMMAND; content.command = TLM_WRITE_COMMAND;
else else
SC_REPORT_FATAL("StlPlayer", ("Malformed trace file line " + std::to_string(lineCnt) + ").").c_str()); SC_REPORT_FATAL("StlPlayer", ("Malformed trace file line " + std::to_string(lineCnt) + ".").c_str());
// Get the address. // Get the address.
iss >> element; iss >> element;
if (element.empty()) if (element.empty())
SC_REPORT_FATAL("StlPlayer", ("Malformed trace file line " + std::to_string(lineCnt) + ").").c_str()); SC_REPORT_FATAL("StlPlayer", ("Malformed trace file line " + std::to_string(lineCnt) + ".").c_str());
content.address = std::stoull(element, nullptr, 16); content.address = std::stoull(element, nullptr, 16);
// Get the data if necessary. // Get the data if necessary.
@@ -209,7 +209,7 @@ void StlPlayer::parseTraceFile()
// Check if data length in the trace file is correct. // Check if data length in the trace file is correct.
// We need two characters to represent 1 byte in hexadecimal. Offset for 0x prefix. // We need two characters to represent 1 byte in hexadecimal. Offset for 0x prefix.
if (element.length() != (content.dataLength * 2 + 2)) if (element.length() != (content.dataLength * 2 + 2))
SC_REPORT_FATAL("StlPlayer", ("Malformed trace file line " + std::to_string(lineCnt) + ").").c_str()); SC_REPORT_FATAL("StlPlayer", ("Malformed trace file line " + std::to_string(lineCnt) + ".").c_str());
// Set data // Set data
for (unsigned i = 0; i < content.dataLength; i++) for (unsigned i = 0; i < content.dataLength; i++)

View File

@@ -226,6 +226,7 @@ TraceSetup::TraceSetup(const std::string &uri,
remainingTransactions = totalTransactions; remainingTransactions = totalTransactions;
numberOfTrafficInitiators = players.size(); numberOfTrafficInitiators = players.size();
defaultDataLength = Configuration::getInstance().memSpec->defaultBytesPerBurst;
} }
void TraceSetup::trafficInitiatorTerminates() void TraceSetup::trafficInitiatorTerminates()
@@ -246,9 +247,14 @@ void TraceSetup::transactionFinished()
std::cout << std::endl; std::cout << std::endl;
} }
tlm_generic_payload *TraceSetup::allocatePayload(unsigned dataLength)
{
return memoryManager.allocate(dataLength);
}
tlm_generic_payload *TraceSetup::allocatePayload() tlm_generic_payload *TraceSetup::allocatePayload()
{ {
return memoryManager.allocate(); return allocatePayload(defaultDataLength);
} }
void TraceSetup::loadBar(uint64_t x, uint64_t n, unsigned int w, unsigned int granularity) void TraceSetup::loadBar(uint64_t x, uint64_t n, unsigned int w, unsigned int granularity)

View File

@@ -55,6 +55,7 @@ public:
void trafficInitiatorTerminates(); void trafficInitiatorTerminates();
void transactionFinished(); void transactionFinished();
tlm::tlm_generic_payload *allocatePayload(unsigned dataLength);
tlm::tlm_generic_payload *allocatePayload(); tlm::tlm_generic_payload *allocatePayload();
private: private:
@@ -63,6 +64,7 @@ private:
uint64_t remainingTransactions; uint64_t remainingTransactions;
unsigned int finishedTrafficInitiators = 0; unsigned int finishedTrafficInitiators = 0;
MemoryManager memoryManager; MemoryManager memoryManager;
unsigned defaultDataLength = 64;
static void loadBar(uint64_t x, uint64_t n, unsigned int w = 50, unsigned int granularity = 1); static void loadBar(uint64_t x, uint64_t n, unsigned int w = 50, unsigned int granularity = 1);
}; };

View File

@@ -123,7 +123,8 @@ The JSON code below shows an example configuration:
"tracesetup": [ "tracesetup": [
{ {
"clkMhz": 300, "clkMhz": 300,
"name": "ddr3_example.stl" "name": "ddr3_example.stl",
"addLengthConverter": true
}, },
{ {
"clkMhz": 2000, "clkMhz": 2000,
@@ -160,6 +161,7 @@ Fields Description:
Each **trace setup** device configuration can be a **trace player** ("type": "player"), a **traffic generator** ("type": "generator") or a **row hammer generator** ("type": "hammer"). By not specifing the **type** parameter, the device will act as a **trace player**. Each **trace setup** device configuration can be a **trace player** ("type": "player"), a **traffic generator** ("type": "generator") or a **row hammer generator** ("type": "hammer"). By not specifing the **type** parameter, the device will act as a **trace player**.
All device configurations must define a **clkMhz** (operation frequency of the **traffic initiator**) and a **name** (in case of a trace player this specifies the **trace file** to play; in case of a generator this field is only for identification purposes). All device configurations must define a **clkMhz** (operation frequency of the **traffic initiator**) and a **name** (in case of a trace player this specifies the **trace file** to play; in case of a generator this field is only for identification purposes).
The optional parameter **addLengthConverter** adds a transaction length converter between initiator and DRAMSys. This unit divides a large transaction up into several smaller transactions with the maximum length of one DRAM burst access.
The **maxPendingReadRequests** and **maxPendingWriteRequests** parameters define the maximum number of outstanding read/write requests. The current implementation delays all memory accesses when one limit is reached. The default value (0) disables the limit. The **maxPendingReadRequests** and **maxPendingWriteRequests** parameters define the maximum number of outstanding read/write requests. The current implementation delays all memory accesses when one limit is reached. The default value (0) disables the limit.
A **traffic generator** can be configured to generate **numRequests** requests in total, of which the **rwRatio** field defines the probability of one request being a read request. The **seed** parameter can be used to produce identical results for all simulations. **minAddress** and **maxAddress** specify the address range, by default the whole address range is used. The parameter **addressDistribution** can either be set to **"random"** or **"sequential"**. In case of **"sequential"** the additional **addressIncrement** field must be specified, defining the address increment after each request. A **traffic generator** can be configured to generate **numRequests** requests in total, of which the **rwRatio** field defines the probability of one request being a read request. The **seed** parameter can be used to produce identical results for all simulations. **minAddress** and **maxAddress** specify the address range, by default the whole address range is used. The parameter **addressDistribution** can either be set to **"random"** or **"sequential"**. In case of **"sequential"** the additional **addressIncrement** field must be specified, defining the address increment after each request.
@@ -171,7 +173,7 @@ Most configuration fields reference other JSON files which contain more speciali
#### Trace Files #### Trace Files
A **trace file** is a prerecorded file containing memory transactions. Each memory transaction has a time stamp that tells the simulator when it shall happen, a transaction type (*read* or *write*) and a hexadecimal memory address. A **trace file** is a prerecorded file containing memory transactions. Each memory transaction has a time stamp that tells the simulator when it shall happen, a transaction type (*read* or *write*) and a hexadecimal memory address. The optional length parameter (in bytes) allows sending transactions with a custom length that does not match the length of a single DRAM burst access. In this case a length converter has to be added. Write transactions also have to specify a data field when storage is enabled in DRAMSys.
There are two different kinds of trace files. They differ in their timing behavior and are distinguished by their file extension. There are two different kinds of trace files. They differ in their timing behavior and are distinguished by their file extension.
@@ -183,11 +185,11 @@ Syntax example:
``` ```
# Comment lines begin with # # Comment lines begin with #
# [clock-cyle]: [write|read] [hex-address] [hex-data (optional)] # cycle: [(length)] command hex-address [hex-data]
31: read 0x400140 31: read 0x400140
33: read 0x400160 33: read 0x400160
56: write 0x7fff8000 0x123456789abcdef... 56: write 0x7fff8000 0x123456789abcdef...
81: read 0x400180 81: (128) read 0x400180
``` ```
##### Relative STL Traces (.rstl) ##### Relative STL Traces (.rstl)
@@ -198,11 +200,11 @@ Syntax example:
``` ```
# Comment lines begin with # # Comment lines begin with #
# [clock-cyle]: [write|read] [hex-address] [hex-data (optional)] # cycle: [(length)] command hex-address [hex-data]
31: read 0x400140 31: read 0x400140
2: read 0x400160 2: (512) read 0x400160
23: write 0x7fff8000 0x123456789abcdef... 23: write 0x7fff8000 0x123456789abcdef...
25: read 0x400180 10: read 0x400180
``` ```
##### Elastic Traces ##### Elastic Traces