Change to use batch size to store each batch location due iterator invalidation of deque container when push and pop

This commit is contained in:
Thanh C. Tran
2017-07-19 18:39:00 +02:00
parent 2338dd294d
commit 6c5fb579d4
4 changed files with 87 additions and 52 deletions

View File

@@ -169,6 +169,16 @@ GenerationExtension& GenerationExtension::getExtension(const tlm::tlm_generic_pa
return *result;
}
sc_time GenerationExtension::getTimeOfGeneration(const tlm::tlm_generic_payload *payload)
{
return GenerationExtension::getExtension(payload).TimeOfGeneration();
}
sc_time GenerationExtension::getTimeOfGeneration(const tlm::tlm_generic_payload &payload)
{
return GenerationExtension::getTimeOfGeneration(&payload);
}
//THREAD
bool operator ==(const Thread& lhs, const Thread& rhs)
{

View File

@@ -212,6 +212,8 @@ public:
virtual void copy_from(const tlm_extension_base& ext);
static GenerationExtension& getExtension(const tlm::tlm_generic_payload *payload);
sc_time TimeOfGeneration() const {return timeOfGeneration;}
static sc_time getTimeOfGeneration(const tlm::tlm_generic_payload *payload);
static sc_time getTimeOfGeneration(const tlm::tlm_generic_payload &payload);
private:
sc_time timeOfGeneration;

View File

@@ -62,13 +62,10 @@ void SMS::batchScheduler()
if (existReadyBatches()) {
if (!isSystemLightlyLoaded() && (existLowIntensityThread() || distribution(generator))) {
pickSJF();
drain(memClk);
(*lastSelectedThread).second.pop_front();
} else {
pickRR();
drain(memClk);
(*lastSelectedThread).second.pop_front();
}
drainOnePayloadFromReadybatch(memClk);
} else {
wait(memClk);
}
@@ -85,7 +82,7 @@ bool SMS::pickSJF()
{
// find threads with ready batches
std::vector<Thread> threadsWithReadyBatches;
for (const auto &each : readyBatchIters)
for (const auto &each : readyBatchInclusiveEndLocs)
{
if (!each.second.empty())
{
@@ -107,7 +104,7 @@ bool SMS::pickSJF()
}
// save selected thread
lastSelectedThread = readyBatchIters.find(minThread);
lastSelectedThread = readyBatchInclusiveEndLocs.find(minThread);
debugManager.printDebugMessage(name(),
"[SJF] Select ready batch of thread " + to_string(minThread.ID()));
return true;
@@ -124,28 +121,36 @@ bool SMS::pickSJF()
* @param memClk
* @param last
*/
void SMS::drain(const sc_time &memClk)
void SMS::drainOnePayloadFromReadybatch(const sc_time &memClk)
{
if (lastSelectedThread->second.empty()) {
return;
}
const Thread &selectedThread = lastSelectedThread->first;
const std::deque<gp*>::iterator &last = lastSelectedThread->second.front();
assert(last != requestBuffers[selectedThread].end());
unsigned int batchSize = std::distance(requestBuffers[selectedThread].begin(), last) + 1;
assert(batchSize > 0 && batchSize <= requestBuffers[selectedThread].size());
for (unsigned int i = 1; i <= batchSize; i++)
const size_t &inclusiveEndLoc = lastSelectedThread->second.front();
assert(inclusiveEndLoc < requestBuffers.size());
for (size_t i = 0; i <= inclusiveEndLoc; ++i)
{
Bank bank = DramExtension::getExtension(requestBuffers[selectedThread].front()).getBank();
wait(memClk);
Bank bank = DramExtension::getExtension(requestBuffers[selectedThread].front()).getBank();
bankBuffers[bank].emplace_back(requestBuffers[selectedThread].front());
requestBuffers[selectedThread].pop_front();
// decrement inclusive end locations of ready batches
// except this ready batch
for (size_t i = 1; i < readyBatchInclusiveEndLocs.size(); ++i)
{
--readyBatchInclusiveEndLocs[selectedThread][i];
}
debugManager.printDebugMessage(name(),
"[SJF] Drain request in the ready batch of thread "
+ to_string((*lastSelectedThread).first.ID()) + " to bankbuffer "
+ to_string(bank.ID()));
}
lastSelectedThread->second.pop_front();
}
/**
@@ -155,21 +160,21 @@ void SMS::drain(const sc_time &memClk)
*/
bool SMS::pickRR()
{
if (lastSelectedThread == readyBatchIters.end())
if (lastSelectedThread == readyBatchInclusiveEndLocs.end())
{
lastSelectedThread = readyBatchIters.begin();
lastSelectedThread = readyBatchInclusiveEndLocs.begin();
if (!(*lastSelectedThread).second.empty()) {
return true;
}
}
std::map<Thread, std::deque<gp_deque_iterator>>::iterator savedOriginalNextSelectedThread = lastSelectedThread;
std::map<Thread, std::deque<size_t>>::iterator savedOriginalNextSelectedThread = lastSelectedThread;
do
{
lastSelectedThread++;
if (lastSelectedThread == readyBatchIters.end()) {
lastSelectedThread = readyBatchIters.begin();
if (lastSelectedThread == readyBatchInclusiveEndLocs.end()) {
lastSelectedThread = readyBatchInclusiveEndLocs.begin();
}
if (lastSelectedThread == savedOriginalNextSelectedThread) {
return false;
@@ -198,11 +203,12 @@ bool SMS::existLowIntensityThread() const {
return false;
}
bool SMS::isThresholdAgeExceeded(const Thread &thread, sc_time const &memClk, std::deque<gp*>::iterator const &begin, std::deque<gp*>::iterator const &end) {
bool SMS::isThresholdAgeExceeded(const Thread &thread, sc_time const &memClk, size_t const &inclusiveBeginLoc, size_t const &exclusiveEndLoc) {
assert((exclusiveEndLoc - inclusiveBeginLoc) >= 1);
// find the oldest request in the thread's batch
sc_time oldestGenerationTime = sc_time_stamp();
for (auto reqIter = begin; reqIter != end; reqIter++) {
sc_time reqGenerationTime = GenerationExtension::getExtension(*reqIter).TimeOfGeneration();
for (size_t i = inclusiveBeginLoc; i != exclusiveEndLoc; ++i) {
sc_time reqGenerationTime = GenerationExtension::getExtension(requestBuffers[thread][i]).TimeOfGeneration();
if (reqGenerationTime < oldestGenerationTime) {
oldestGenerationTime = reqGenerationTime;
}
@@ -235,8 +241,8 @@ void SMS::updateMPKCs(sc_time const &memClk) {
}
}
bool SMS::isExceededReqBufferSize(Thread const &thread) {
return requestBuffers[thread].size() == Configuration::getInstance().RequestBufferSize;
bool SMS::isExceededReqBufferSize(size_t const &exclusiveEndLoc) {
return exclusiveEndLoc <= Configuration::getInstance().RequestBufferSize;
}
bool SMS::isRequestBuffersEmpty() const {
@@ -249,7 +255,7 @@ bool SMS::isRequestBuffersEmpty() const {
}
bool SMS::existReadyBatches() const {
for (const auto &each : readyBatchIters) {
for (const auto &each : readyBatchInclusiveEndLocs) {
if (!each.second.empty()) {
return true;
}
@@ -264,14 +270,15 @@ bool SMS::existReadyBatches() const {
* @param begin
* @return true if this batch is ready, otherwise false
*/
bool SMS::batchFormation(sc_time const &memClk, Thread const &thread, std::deque<gp*> const &requestBuffer, std::deque<gp*>::iterator const &beginIter)
bool SMS::batchFormation(sc_time const &memClk, Thread const &thread, std::deque<gp*> const &requestBuffer, size_t const &inclusiveBeginLoc)
{
if (requestBuffer.empty())
{
return false;
}
if (requestBuffer.end() == beginIter)
assert(inclusiveBeginLoc <= requestBuffer.size());
if (requestBuffer.size() == inclusiveBeginLoc)
{
return false;
}
@@ -279,30 +286,46 @@ bool SMS::batchFormation(sc_time const &memClk, Thread const &thread, std::deque
if (MPKCs[thread] < LOW_MPKC || isSystemLightlyLoaded())
{
// bypass requests by forming batch with only one request (threshold age is ZERO)
readyBatchIters[thread].push_back(beginIter);
readyBatchInclusiveEndLocs[thread].push_back(inclusiveBeginLoc);
return true;
}
else
{
// forming batch with FIFO size & threshold age constraints
std::deque<gp*>::iterator firstDifferentRowAccessReqIter = beginIter;
Row firstRow = DramExtension::getRow(*beginIter);
while (firstDifferentRowAccessReqIter != requestBuffer.end()
&& DramExtension::getRow(*firstDifferentRowAccessReqIter) == firstRow)
size_t firstDifferentRowAccessReqLoc = inclusiveBeginLoc;
Row firstRow = DramExtension::getRow(requestBuffer[inclusiveBeginLoc]);
bool isBatchReady = false;
size_t bufferSize = requestBuffer.size();
while (firstDifferentRowAccessReqLoc != bufferSize
&& DramExtension::getRow(requestBuffer[firstDifferentRowAccessReqLoc]) == firstRow)
{
++firstDifferentRowAccessReqIter;
if (firstDifferentRowAccessReqIter == requestBuffer.end ()) {
break;
}
++firstDifferentRowAccessReqLoc;
if (firstDifferentRowAccessReqLoc < bufferSize)
{
if (DramExtension::getRow(requestBuffer[firstDifferentRowAccessReqLoc]) != firstRow
|| isExceededReqBufferSize(firstDifferentRowAccessReqLoc)
|| isThresholdAgeExceeded(thread, memClk, inclusiveBeginLoc, firstDifferentRowAccessReqLoc))
{
isBatchReady = true;
break;
}
}
else
{
if (isExceededReqBufferSize(firstDifferentRowAccessReqLoc)
|| isThresholdAgeExceeded(thread, memClk, inclusiveBeginLoc, firstDifferentRowAccessReqLoc))
{
isBatchReady = true;
break;
}
}
}
// deem this batch ready
if ((firstDifferentRowAccessReqIter != requestBuffer.end())
|| isExceededReqBufferSize(thread)
|| isThresholdAgeExceeded(thread, memClk, beginIter, firstDifferentRowAccessReqIter))
// store this ready batch location
if (isBatchReady)
{
--firstDifferentRowAccessReqIter;
readyBatchIters[thread].push_back(firstDifferentRowAccessReqIter);
--firstDifferentRowAccessReqLoc;
readyBatchInclusiveEndLocs[thread].push_back(firstDifferentRowAccessReqLoc);
debugManager.printDebugMessage(name(),
"Deem batch ready - thread " + to_string(thread.ID()));
return true;
@@ -318,16 +341,16 @@ void SMS::multiBatchFormation(sc_time const &memClk)
{
for (auto &requestBuffer : requestBuffers)
{
bool formed;
bool formed = false;
do
{
if (readyBatchIters[requestBuffer.first].empty())
if (readyBatchInclusiveEndLocs[requestBuffer.first].empty())
{
formed = batchFormation(memClk, requestBuffer.first, requestBuffer.second, requestBuffer.second.begin());
formed = batchFormation(memClk, requestBuffer.first, requestBuffer.second, 0);
}
else
{
formed = batchFormation(memClk, requestBuffer.first, requestBuffer.second, readyBatchIters[requestBuffer.first].back() + 1);
formed = batchFormation(memClk, requestBuffer.first, requestBuffer.second, readyBatchInclusiveEndLocs[requestBuffer.first].back() + 1);
}
} while (!requestBuffer.second.empty() && formed);
}

View File

@@ -35,7 +35,7 @@ public:
SMS(sc_module_name /*_name*/, ControllerCore &controllerCore, unsigned int SJFprobability) : IScheduler(controllerCore), SJFprobability(SJFprobability), debugManager(DebugManager::getInstance())
{
// initialize selected thread iterator
lastSelectedThread = readyBatchIters.end();
lastSelectedThread = readyBatchInclusiveEndLocs.end();
SC_THREAD(batchScheduler);
}
SC_HAS_PROCESS(SMS);
@@ -53,28 +53,28 @@ public:
private:
std::map<Thread, std::deque<gp*>> requestBuffers;
std::map<Bank, std::deque<gp*>> bankBuffers;
std::map<Thread, std::deque<gp_deque_iterator>> readyBatchIters;
std::map<Thread, std::deque<size_t>> readyBatchInclusiveEndLocs;
std::map<Thread, unsigned int> inFlightMemRequestCounter;
std::map<Thread, unsigned int> cacheMisses;
std::map<Thread, float> MPKCs;
unsigned int SJFprobability;
std::map<Thread, std::deque<gp_deque_iterator>>::iterator lastSelectedThread;
std::map<Thread, std::deque<size_t>>::iterator lastSelectedThread;
sc_event newRequest;
DebugManager& debugManager;
bool batchFormation(sc_time const &memClk, Thread const &thread, const std::deque<gp*> &requestBuffer, const std::deque<gp*>::iterator &beginIter);
bool batchFormation(sc_time const &memClk, Thread const &thread, const std::deque<gp*> &requestBuffer, const size_t &inclusiveBeginLoc);
void multiBatchFormation(const sc_time &memClk);
bool pickSJF();
bool pickRR();
void drain(const sc_time &memClk);
void drainOnePayloadFromReadybatch(const sc_time &memClk);
bool existLowIntensityThread() const;
bool isSystemLightlyLoaded() const;
bool isThresholdAgeExceeded(const Thread &thread, const sc_time &memClk, const std::deque<gp*>::iterator &begin, const std::deque<gp*>::iterator &end);
bool isExceededReqBufferSize(Thread const &thread);
bool isThresholdAgeExceeded(const Thread &thread, const sc_time &memClk, const size_t &inclusiveBeginLoc, const size_t &exclusiveEndLoc);
bool isExceededReqBufferSize(size_t const &exclusiveEndLoc);
void updateMPKCs(const sc_time &memClk);
bool isRequestBuffersEmpty() const;