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));
}
LengthConverter::MemoryManager::MemoryManager(bool storageEnabled, size_t maxDataLength)
LengthConverter::MemoryManager::MemoryManager(bool storageEnabled, unsigned maxDataLength)
: storageEnabled(storageEnabled), maxDataLength(maxDataLength)
{}

View File

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

View File

@@ -51,17 +51,18 @@ MemoryManager::MemoryManager()
MemoryManager::~MemoryManager()
{
for (tlm_generic_payload *payload : freePayloads)
for (auto& innerBuffer : freePayloads)
{
if (storageEnabled)
while (!innerBuffer.second.empty())
{
// Delete data buffer
delete[] payload->get_data_ptr();
tlm_generic_payload* payload = innerBuffer.second.top();
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
@@ -69,18 +70,17 @@ MemoryManager::~MemoryManager()
//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++;
tlm_generic_payload *payload = new tlm_generic_payload(this);
auto* payload = new tlm_generic_payload(this);
if (storageEnabled)
{
// Allocate a data buffer and initialize it with zeroes:
unsigned int dataLength = Configuration::getInstance().memSpec->maxBytesPerBurst;
unsigned char *data = new unsigned char[dataLength];
auto* data = new unsigned char[dataLength];
std::fill(data, data + dataLength, 0);
payload->set_data_ptr(data);
}
@@ -89,13 +89,14 @@ tlm_generic_payload *MemoryManager::allocate()
}
else
{
tlm_generic_payload *result = freePayloads.back();
freePayloads.pop_back();
tlm_generic_payload *result = freePayloads[dataLength].top();
freePayloads[dataLength].pop();
return result;
}
}
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
#define MEMORYMANAGER_H
#include <vector>
#include <unordered_map>
#include <stack>
#include <tlm>
@@ -46,13 +47,13 @@ class MemoryManager : public tlm::tlm_mm_interface
public:
MemoryManager();
~MemoryManager() override;
tlm::tlm_generic_payload *allocate();
tlm::tlm_generic_payload *allocate(unsigned dataLength);
void free(tlm::tlm_generic_payload *payload) override;
private:
uint64_t numberOfAllocations;
uint64_t numberOfFrees;
std::vector<tlm::tlm_generic_payload *> freePayloads;
std::unordered_map<unsigned, std::stack<tlm::tlm_generic_payload *>> freePayloads;
bool storageEnabled = false;
};

View File

@@ -101,7 +101,7 @@ void StlPlayer::sendNextPayload()
}
// Allocate a generic payload for this request.
tlm_generic_payload *payload = setup->allocatePayload();
tlm_generic_payload *payload = setup->allocatePayload(lineIterator->dataLength);
payload->acquire();
// Fill up the payload.
@@ -169,20 +169,20 @@ void StlPlayer::parseTraceFile()
// Get the timestamp for the transaction.
iss >> element;
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));
// Get the optional burst length and command
iss >> element;
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) == '(')
{
element.erase(0, 1);
content.dataLength = std::stoul(element);
iss >> element;
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
content.dataLength = defaultDataLength;
@@ -192,12 +192,12 @@ void StlPlayer::parseTraceFile()
else if (element == "write")
content.command = TLM_WRITE_COMMAND;
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.
iss >> element;
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);
// Get the data if necessary.
@@ -209,7 +209,7 @@ void StlPlayer::parseTraceFile()
// Check if data length in the trace file is correct.
// We need two characters to represent 1 byte in hexadecimal. Offset for 0x prefix.
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
for (unsigned i = 0; i < content.dataLength; i++)

View File

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

View File

@@ -55,6 +55,7 @@ public:
void trafficInitiatorTerminates();
void transactionFinished();
tlm::tlm_generic_payload *allocatePayload(unsigned dataLength);
tlm::tlm_generic_payload *allocatePayload();
private:
@@ -63,6 +64,7 @@ private:
uint64_t remainingTransactions;
unsigned int finishedTrafficInitiators = 0;
MemoryManager memoryManager;
unsigned defaultDataLength = 64;
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": [
{
"clkMhz": 300,
"name": "ddr3_example.stl"
"name": "ddr3_example.stl",
"addLengthConverter": true
},
{
"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**.
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.
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
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.
@@ -183,11 +185,11 @@ Syntax example:
```
# Comment lines begin with #
# [clock-cyle]: [write|read] [hex-address] [hex-data (optional)]
31: read 0x400140
33: read 0x400160
56: write 0x7fff8000 0x123456789abcdef...
81: read 0x400180
# cycle: [(length)] command hex-address [hex-data]
31: read 0x400140
33: read 0x400160
56: write 0x7fff8000 0x123456789abcdef...
81: (128) read 0x400180
```
##### Relative STL Traces (.rstl)
@@ -198,11 +200,11 @@ Syntax example:
```
# Comment lines begin with #
# [clock-cyle]: [write|read] [hex-address] [hex-data (optional)]
31: read 0x400140
2: read 0x400160
23: write 0x7fff8000 0x123456789abcdef...
25: read 0x400180
# cycle: [(length)] command hex-address [hex-data]
31: read 0x400140
2: (512) read 0x400160
23: write 0x7fff8000 0x123456789abcdef...
10: read 0x400180
```
##### Elastic Traces