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