Allow variable data length in memory manager.
This commit is contained in:
@@ -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)
|
||||||
{}
|
{}
|
||||||
|
|
||||||
|
|||||||
@@ -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>
|
||||||
|
|||||||
@@ -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);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -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++)
|
||||||
|
|||||||
@@ -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)
|
||||||
|
|||||||
@@ -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);
|
||||||
};
|
};
|
||||||
|
|||||||
26
README.md
26
README.md
@@ -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
|
||||||
|
|||||||
Reference in New Issue
Block a user