|
|
|
|
@@ -61,15 +61,13 @@ void SMS::batchScheduler()
|
|
|
|
|
multiBatchFormation(memClk);
|
|
|
|
|
if (existReadyBatches()) {
|
|
|
|
|
if (!isSystemLightlyLoaded() && (existLowIntensityThread() || distribution(generator))) {
|
|
|
|
|
if (pickSJF()) {
|
|
|
|
|
drain(memClk, (*lastSelectedThread).second.front());
|
|
|
|
|
(*lastSelectedThread).second.pop_front();
|
|
|
|
|
}
|
|
|
|
|
pickSJF();
|
|
|
|
|
drain(memClk);
|
|
|
|
|
(*lastSelectedThread).second.pop_front();
|
|
|
|
|
} else {
|
|
|
|
|
if (pickRR()) {
|
|
|
|
|
drain(memClk, (*lastSelectedThread).second.front());
|
|
|
|
|
(*lastSelectedThread).second.pop_front();
|
|
|
|
|
}
|
|
|
|
|
pickRR();
|
|
|
|
|
drain(memClk);
|
|
|
|
|
(*lastSelectedThread).second.pop_front();
|
|
|
|
|
}
|
|
|
|
|
} else {
|
|
|
|
|
wait(memClk);
|
|
|
|
|
@@ -87,7 +85,7 @@ bool SMS::pickSJF()
|
|
|
|
|
{
|
|
|
|
|
// find threads with ready batches
|
|
|
|
|
std::vector<Thread> threadsWithReadyBatches;
|
|
|
|
|
for (auto& each : readyBatchIters)
|
|
|
|
|
for (const auto &each : readyBatchIters)
|
|
|
|
|
{
|
|
|
|
|
if (!each.second.empty())
|
|
|
|
|
{
|
|
|
|
|
@@ -99,8 +97,8 @@ bool SMS::pickSJF()
|
|
|
|
|
if (!threadsWithReadyBatches.empty())
|
|
|
|
|
{
|
|
|
|
|
// pick shortest-job thread among threads with non-empty request buffer
|
|
|
|
|
Thread minThread = threadsWithReadyBatches.front();
|
|
|
|
|
for (auto& thread : threadsWithReadyBatches)
|
|
|
|
|
Thread &minThread = threadsWithReadyBatches.front();
|
|
|
|
|
for (const auto &thread : threadsWithReadyBatches)
|
|
|
|
|
{
|
|
|
|
|
if (inFlightMemRequestCounter[thread] < inFlightMemRequestCounter[minThread])
|
|
|
|
|
{
|
|
|
|
|
@@ -126,17 +124,19 @@ bool SMS::pickSJF()
|
|
|
|
|
* @param memClk
|
|
|
|
|
* @param last
|
|
|
|
|
*/
|
|
|
|
|
void SMS::drain(sc_time memClk, std::deque<gp*>::iterator last)
|
|
|
|
|
void SMS::drain(const sc_time &memClk)
|
|
|
|
|
{
|
|
|
|
|
Thread selectedThread = (*lastSelectedThread).first;
|
|
|
|
|
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++)
|
|
|
|
|
{
|
|
|
|
|
Bank bank = DramExtension::getExtension(requestBuffers[selectedThread].front()).getBank();
|
|
|
|
|
// if(bankBuffers[bank].size() == Configuration::getInstance().BankBufferSize)
|
|
|
|
|
// {
|
|
|
|
|
// wait(bankBufferIsNotFull);
|
|
|
|
|
// }
|
|
|
|
|
wait(memClk);
|
|
|
|
|
bankBuffers[bank].emplace_back(requestBuffers[selectedThread].front());
|
|
|
|
|
requestBuffers[selectedThread].pop_front();
|
|
|
|
|
@@ -155,54 +155,42 @@ void SMS::drain(sc_time memClk, std::deque<gp*>::iterator last)
|
|
|
|
|
*/
|
|
|
|
|
bool SMS::pickRR()
|
|
|
|
|
{
|
|
|
|
|
std::map<Thread, std::deque<gp_deque_iterator>>::iterator nextSelectedThread;
|
|
|
|
|
if (lastSelectedThread == readyBatchIters.end())
|
|
|
|
|
{
|
|
|
|
|
lastSelectedThread = readyBatchIters.begin();
|
|
|
|
|
nextSelectedThread = lastSelectedThread;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
nextSelectedThread = lastSelectedThread;
|
|
|
|
|
nextSelectedThread++;
|
|
|
|
|
if (nextSelectedThread == readyBatchIters.end())
|
|
|
|
|
nextSelectedThread = readyBatchIters.begin();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
std::map<Thread, std::deque<gp_deque_iterator>>::iterator savedOriginalNextSelectedThread = nextSelectedThread;
|
|
|
|
|
|
|
|
|
|
while ((*nextSelectedThread).second.empty())
|
|
|
|
|
{
|
|
|
|
|
nextSelectedThread++;
|
|
|
|
|
if (nextSelectedThread == readyBatchIters.end())
|
|
|
|
|
if (lastSelectedThread == readyBatchIters.end())
|
|
|
|
|
{
|
|
|
|
|
nextSelectedThread = readyBatchIters.begin();
|
|
|
|
|
lastSelectedThread = readyBatchIters.begin();
|
|
|
|
|
if (!(*lastSelectedThread).second.empty()) {
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (nextSelectedThread == savedOriginalNextSelectedThread)
|
|
|
|
|
std::map<Thread, std::deque<gp_deque_iterator>>::iterator savedOriginalNextSelectedThread = lastSelectedThread;
|
|
|
|
|
|
|
|
|
|
do
|
|
|
|
|
{
|
|
|
|
|
// the next thread is the original thread, that mean req buffer are totally empty
|
|
|
|
|
// non-existed ready batch to be picked up & drained
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
// save last selected thread
|
|
|
|
|
lastSelectedThread = nextSelectedThread;
|
|
|
|
|
debugManager.printDebugMessage(name(),
|
|
|
|
|
"[RR] Select ready batch of thread " + to_string((*nextSelectedThread).first.ID()));
|
|
|
|
|
return true;
|
|
|
|
|
lastSelectedThread++;
|
|
|
|
|
if (lastSelectedThread == readyBatchIters.end()) {
|
|
|
|
|
lastSelectedThread = readyBatchIters.begin();
|
|
|
|
|
}
|
|
|
|
|
if (lastSelectedThread == savedOriginalNextSelectedThread) {
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
} while ((*lastSelectedThread).second.empty());
|
|
|
|
|
|
|
|
|
|
debugManager.printDebugMessage(name(),
|
|
|
|
|
"[RR] Select ready batch of thread " + to_string((*lastSelectedThread).first.ID()));
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool SMS::isSystemLightlyLoaded() {
|
|
|
|
|
bool SMS::isSystemLightlyLoaded() const {
|
|
|
|
|
unsigned int totalRequest = 0;
|
|
|
|
|
for (auto& bankBuffer : bankBuffers) {
|
|
|
|
|
for (const auto &bankBuffer : bankBuffers) {
|
|
|
|
|
totalRequest += bankBuffer.second.size();
|
|
|
|
|
}
|
|
|
|
|
return (totalRequest <= LOW_SYSTEM_LOAD);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool SMS::existLowIntensityThread() {
|
|
|
|
|
for (auto& mpkcPerThread : MPKCs) {
|
|
|
|
|
bool SMS::existLowIntensityThread() const {
|
|
|
|
|
for (const auto &mpkcPerThread : MPKCs) {
|
|
|
|
|
if (mpkcPerThread.second < LOW_MPKC) {
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
@@ -210,7 +198,7 @@ bool SMS::existLowIntensityThread() {
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool SMS::isThresholdAgeExceeded(Thread thread, sc_time memClk, std::deque<gp*>::iterator begin, std::deque<gp*>::iterator end) {
|
|
|
|
|
bool SMS::isThresholdAgeExceeded(const Thread &thread, sc_time const &memClk, std::deque<gp*>::iterator const &begin, std::deque<gp*>::iterator const &end) {
|
|
|
|
|
// find the oldest request in the thread's batch
|
|
|
|
|
sc_time oldestGenerationTime = sc_time_stamp();
|
|
|
|
|
for (auto reqIter = begin; reqIter != end; reqIter++) {
|
|
|
|
|
@@ -231,28 +219,28 @@ bool SMS::isThresholdAgeExceeded(Thread thread, sc_time memClk, std::deque<gp*>:
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void SMS::updateMPKCs(sc_time memClk) {
|
|
|
|
|
void SMS::updateMPKCs(sc_time const &memClk) {
|
|
|
|
|
if (sc_time_stamp() % (MPKC_RESET_CYCLE * memClk) <= memClk) {
|
|
|
|
|
// reset for every 10k clk cycles
|
|
|
|
|
for (auto& cacheMiss : cacheMisses) {
|
|
|
|
|
for (const auto &cacheMiss : cacheMisses) {
|
|
|
|
|
MPKCs[cacheMiss.first] = 0;
|
|
|
|
|
}
|
|
|
|
|
debugManager.printDebugMessage(name(), "Reset MKKCs");
|
|
|
|
|
} else {
|
|
|
|
|
// update MPKC for every thread
|
|
|
|
|
for (auto& cacheMiss : cacheMisses) {
|
|
|
|
|
for (const auto &cacheMiss : cacheMisses) {
|
|
|
|
|
MPKCs[cacheMiss.first] = (cacheMiss.second * 1000.0 * memClk) / (sc_time_stamp());
|
|
|
|
|
}
|
|
|
|
|
debugManager.printDebugMessage(name(), "Update MPKCs");
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool SMS::isExceededReqBufferSize(Thread thread) {
|
|
|
|
|
bool SMS::isExceededReqBufferSize(Thread const &thread) {
|
|
|
|
|
return requestBuffers[thread].size() == Configuration::getInstance().RequestBufferSize;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool SMS::isRequestBuffersEmpty() {
|
|
|
|
|
for (auto& requestBuffer : requestBuffers) {
|
|
|
|
|
bool SMS::isRequestBuffersEmpty() const {
|
|
|
|
|
for (const auto &requestBuffer : requestBuffers) {
|
|
|
|
|
if (!requestBuffer.second.empty()) {
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
@@ -260,8 +248,8 @@ bool SMS::isRequestBuffersEmpty() {
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool SMS::existReadyBatches() {
|
|
|
|
|
for (auto& each : readyBatchIters) {
|
|
|
|
|
bool SMS::existReadyBatches() const {
|
|
|
|
|
for (const auto &each : readyBatchIters) {
|
|
|
|
|
if (!each.second.empty()) {
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
@@ -276,46 +264,47 @@ bool SMS::existReadyBatches() {
|
|
|
|
|
* @param begin
|
|
|
|
|
* @return true if this batch is ready, otherwise false
|
|
|
|
|
*/
|
|
|
|
|
bool SMS::batchFormation(sc_time memClk, std::pair<Thread, std::deque<gp*>> &requestBuffer,
|
|
|
|
|
std::deque<gp*>::iterator beginIter)
|
|
|
|
|
bool SMS::batchFormation(sc_time const &memClk, Thread const &thread, std::deque<gp*> const &requestBuffer, std::deque<gp*>::iterator const &beginIter)
|
|
|
|
|
{
|
|
|
|
|
if (requestBuffer.second.empty())
|
|
|
|
|
if (requestBuffer.empty())
|
|
|
|
|
{
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (requestBuffer.second.end() == beginIter)
|
|
|
|
|
if (requestBuffer.end() == beginIter)
|
|
|
|
|
{
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (MPKCs[requestBuffer.first] < LOW_MPKC || isSystemLightlyLoaded())
|
|
|
|
|
if (MPKCs[thread] < LOW_MPKC || isSystemLightlyLoaded())
|
|
|
|
|
{
|
|
|
|
|
// bypass requests by forming batch with only one request (threshold age is ZERO)
|
|
|
|
|
readyBatchIters[requestBuffer.first].push_back(beginIter);
|
|
|
|
|
readyBatchIters[thread].push_back(beginIter);
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
// forming batch with FIFO size & threshold age constraints
|
|
|
|
|
auto firstDifferentRowAccessReqIter = beginIter;
|
|
|
|
|
std::deque<gp*>::iterator firstDifferentRowAccessReqIter = beginIter;
|
|
|
|
|
Row firstRow = DramExtension::getRow(*beginIter);
|
|
|
|
|
while (firstDifferentRowAccessReqIter != requestBuffer.second.end()
|
|
|
|
|
while (firstDifferentRowAccessReqIter != requestBuffer.end()
|
|
|
|
|
&& DramExtension::getRow(*firstDifferentRowAccessReqIter) == firstRow)
|
|
|
|
|
{
|
|
|
|
|
firstDifferentRowAccessReqIter++;
|
|
|
|
|
++firstDifferentRowAccessReqIter;
|
|
|
|
|
if (firstDifferentRowAccessReqIter == requestBuffer.end ()) {
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// deem this batch ready
|
|
|
|
|
if ((firstDifferentRowAccessReqIter != requestBuffer.second.end())
|
|
|
|
|
|| isExceededReqBufferSize(requestBuffer.first)
|
|
|
|
|
|| isThresholdAgeExceeded(requestBuffer.first, memClk, beginIter,
|
|
|
|
|
firstDifferentRowAccessReqIter))
|
|
|
|
|
if ((firstDifferentRowAccessReqIter != requestBuffer.end())
|
|
|
|
|
|| isExceededReqBufferSize(thread)
|
|
|
|
|
|| isThresholdAgeExceeded(thread, memClk, beginIter, firstDifferentRowAccessReqIter))
|
|
|
|
|
{
|
|
|
|
|
firstDifferentRowAccessReqIter--;
|
|
|
|
|
readyBatchIters[requestBuffer.first].push_back(firstDifferentRowAccessReqIter);
|
|
|
|
|
--firstDifferentRowAccessReqIter;
|
|
|
|
|
readyBatchIters[thread].push_back(firstDifferentRowAccessReqIter);
|
|
|
|
|
debugManager.printDebugMessage(name(),
|
|
|
|
|
"Deem batch ready - thread " + to_string(requestBuffer.first.ID()));
|
|
|
|
|
"Deem batch ready - thread " + to_string(thread.ID()));
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
@@ -325,29 +314,29 @@ bool SMS::batchFormation(sc_time memClk, std::pair<Thread, std::deque<gp*>> &req
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void SMS::multiBatchFormation(sc_time memClk)
|
|
|
|
|
void SMS::multiBatchFormation(sc_time const &memClk)
|
|
|
|
|
{
|
|
|
|
|
for (auto& requestBuffer : requestBuffers)
|
|
|
|
|
for (auto &requestBuffer : requestBuffers)
|
|
|
|
|
{
|
|
|
|
|
bool formed;
|
|
|
|
|
do
|
|
|
|
|
{
|
|
|
|
|
if (readyBatchIters[requestBuffer.first].empty())
|
|
|
|
|
{
|
|
|
|
|
formed = batchFormation(memClk, (std::pair<Thread, std::deque<gp*>>&)requestBuffer, requestBuffer.second.begin());
|
|
|
|
|
formed = batchFormation(memClk, requestBuffer.first, requestBuffer.second, requestBuffer.second.begin());
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
formed = batchFormation(memClk, (std::pair<Thread, std::deque<gp*>>&)requestBuffer, readyBatchIters[requestBuffer.first].back() + 1);
|
|
|
|
|
formed = batchFormation(memClk, requestBuffer.first, requestBuffer.second, readyBatchIters[requestBuffer.first].back() + 1);
|
|
|
|
|
}
|
|
|
|
|
} while (formed);
|
|
|
|
|
} while (!requestBuffer.second.empty() && formed);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
gp* SMS::getPendingRequest(Bank bank)
|
|
|
|
|
{
|
|
|
|
|
for (auto& requestBuffer : requestBuffers) {
|
|
|
|
|
for (auto& request : requestBuffer.second) {
|
|
|
|
|
for (const auto &requestBuffer : requestBuffers) {
|
|
|
|
|
for (const auto &request : requestBuffer.second) {
|
|
|
|
|
if (DramExtension::getBank(request) == bank) {
|
|
|
|
|
return request;
|
|
|
|
|
}
|
|
|
|
|
|