Merge pull request #171 from trancong/Simple_SMS

SMS Fix on Iterator Invalidation
This commit is contained in:
fzeder
2017-07-25 17:44:27 +02:00
committed by GitHub Enterprise
6 changed files with 302 additions and 277 deletions

View File

@@ -1,7 +1,7 @@
<mcconfig>
<BankwiseLogic value="0"/>
<OpenPagePolicy value="1" />
<MaxNrOfTransactions value="20" />
<MaxNrOfTransactions value="30" />
<Scheduler value="SMS" />
<SJFProbability value="50" />
<RequestBufferSize value = "10" />
@@ -13,4 +13,4 @@
<!-- Modes: NoStorage, Store (store data without errormodel), ErrorModel (store data with errormodel) -->
<StoreMode value="NoStorage" />
<ControllerCoreDisableRefresh value="0"/>
</mcconfig>
</mcconfig>

View File

@@ -12,14 +12,15 @@
<mcconfig src="sms.xml"/>
<tracesetup id="sms">
<device clkMhz="200">ddr3_example.stl</device>
<!-- <device clkMhz="200">ddr3_example.stl</device>
<device clkMhz="200">sms_t1.stl</device>
<device clkMhz="200">sms_t2.stl</device>
<device clkMhz="200">sms_t3.stl</device>
<device clkMhz="200">sms_t4.stl</device>
<device clkMhz="200">stream.stl</device>
<device clkMhz="200">random.stl</device>
<device clkMhz="200">chstone-adpcm_32.stl</device>
<device clkMhz="200">sms_t4.stl</device>-->
<device clkMhz="1000">random.stl</device>
<device clkMhz="1000">chstone-adpcm_32.stl</device>
<device clkMhz="1000">stream.stl</device>
</tracesetup>
</simulation>

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

@@ -5,77 +5,72 @@ using namespace std;
void SMS::schedule(gp *payload)
{
Thread thread = DramExtension::getExtension(payload).getThread();
bool wasEmpty = isRequestBuffersEmpty();
Thread thread = DramExtension::getExtension(payload).getThread();
bool wasEmpty = isRequestBuffersEmpty();
requestBuffers[thread].emplace_back(payload);
requestBuffers[thread].emplace_back(payload);
if (inFlightMemRequestCounter.find(thread) == inFlightMemRequestCounter.end()) {
inFlightMemRequestCounter[thread] = 0;
cacheMisses[thread] = 0;
}
inFlightMemRequestCounter[thread]++;
cacheMisses[thread]++;
if (inFlightMemRequestCounter.find(thread) == inFlightMemRequestCounter.end()) {
inFlightMemRequestCounter[thread] = 0;
cacheMisses[thread] = 0;
}
inFlightMemRequestCounter[thread]++;
cacheMisses[thread]++;
if (wasEmpty) {
newRequest.notify(SC_ZERO_TIME);
}
if (wasEmpty) {
newRequest.notify(SC_ZERO_TIME);
}
}
std::pair<Command, gp*> SMS::getNextRequest(Bank bank)
{
if (bankBuffers[bank].empty())
{
debugManager.printDebugMessage(name(),
"Get next request on bank " + to_string(bank.ID()) + " : EMPTY buffer");
return pair<Command, tlm::tlm_generic_payload*>(Command::NOP, NULL);
}
else
{
gp* payload = bankBuffers[bank].front();
Command command = IScheduler::getNextCommand(*payload);
if (command == Command::Read || command == Command::ReadA || command == Command::Write
|| command == Command::WriteA)
if (bankBuffers[bank].empty())
{
inFlightMemRequestCounter[DramExtension::getExtension(payload).getThread()]--;
bankBuffers[bank].pop_front();
debugManager.printDebugMessage(name(),
"Get next request on bank " + to_string(bank.ID()) + " : EMPTY buffer");
return pair<Command, tlm::tlm_generic_payload*>(Command::NOP, NULL);
}
else
{
gp* payload = bankBuffers[bank].front();
Command command = IScheduler::getNextCommand(*payload);
if (command == Command::Read || command == Command::ReadA || command == Command::Write
|| command == Command::WriteA)
{
inFlightMemRequestCounter[DramExtension::getExtension(payload).getThread()]--;
bankBuffers[bank].pop_front();
}
debugManager.printDebugMessage(name(), "Get next request on bank " + to_string(bank.ID()));
return pair<Command, tlm::tlm_generic_payload*>(command, payload);
}
debugManager.printDebugMessage(name(), "Get next request on bank " + to_string(bank.ID()));
return pair<Command, tlm::tlm_generic_payload*>(command, payload);
}
}
void SMS::batchScheduler()
{
sc_time memClk = Configuration::getInstance().memSpec.clk;
std::default_random_engine generator;
std::bernoulli_distribution distribution((double) SJFprobability / 100.0);
sc_time memClk = Configuration::getInstance().memSpec.clk;
std::default_random_engine generator;
std::bernoulli_distribution distribution((double) SJFprobability / 100.0);
while (true)
{
updateMPKCs(memClk);
if (isRequestBuffersEmpty()) {
wait(newRequest);
} else {
multiBatchFormation(memClk);
if (existReadyBatches()) {
if (!isSystemLightlyLoaded() && (existLowIntensityThread() || distribution(generator))) {
if (pickSJF()) {
drain(memClk, (*lastSelectedThread).second.front());
(*lastSelectedThread).second.pop_front();
}
while (true)
{
updateMPKCs(memClk);
if (isRequestBuffersEmpty()) {
wait(newRequest);
} else {
if (pickRR()) {
drain(memClk, (*lastSelectedThread).second.front());
(*lastSelectedThread).second.pop_front();
}
multiBatchFormation(memClk);
if (existReadyBatches()) {
if (!isSystemLightlyLoaded() && (existLowIntensityThread() || distribution(generator))) {
pickSJF();
} else {
pickRR();
}
drainOnePayloadFromReadybatch(memClk);
} else {
wait(memClk);
}
}
} else {
wait(memClk);
}
}
}
}
/**
@@ -85,39 +80,39 @@ void SMS::batchScheduler()
*/
bool SMS::pickSJF()
{
// find threads with ready batches
std::vector<Thread> threadsWithReadyBatches;
for (auto& each : readyBatchIters)
{
if (!each.second.empty())
// find threads with ready batches
std::vector<Thread> threadsWithReadyBatches;
for (const auto &each : readyBatchInclusiveEndLocs)
{
// marked as thread with non-empty request buffer
threadsWithReadyBatches.push_back(each.first);
}
}
if (!threadsWithReadyBatches.empty())
{
// pick shortest-job thread among threads with non-empty request buffer
Thread minThread = threadsWithReadyBatches.front();
for (auto& thread : threadsWithReadyBatches)
{
if (inFlightMemRequestCounter[thread] < inFlightMemRequestCounter[minThread])
{
minThread = thread;
}
if (!each.second.empty())
{
// marked as thread with non-empty request buffer
threadsWithReadyBatches.push_back(each.first);
}
}
// save selected thread
lastSelectedThread = readyBatchIters.find(minThread);
debugManager.printDebugMessage(name(),
"[SJF] Select ready batch of thread " + to_string(minThread.ID()));
return true;
}
else
{
return false;
}
if (!threadsWithReadyBatches.empty())
{
// pick shortest-job thread among threads with non-empty request buffer
Thread &minThread = threadsWithReadyBatches.front();
for (const auto &thread : threadsWithReadyBatches)
{
if (inFlightMemRequestCounter[thread] < inFlightMemRequestCounter[minThread])
{
minThread = thread;
}
}
// save selected thread
lastSelectedThread = readyBatchInclusiveEndLocs.find(minThread);
debugManager.printDebugMessage(name(),
"[SJF] Select ready batch of thread " + to_string(minThread.ID()));
return true;
}
else
{
return false;
}
}
/**
@@ -126,26 +121,36 @@ bool SMS::pickSJF()
* @param memClk
* @param last
*/
void SMS::drain(sc_time memClk, std::deque<gp*>::iterator last)
void SMS::drainOnePayloadFromReadybatch(const sc_time &memClk)
{
Thread selectedThread = (*lastSelectedThread).first;
unsigned int batchSize = std::distance(requestBuffers[selectedThread].begin(), last) + 1;
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();
if (lastSelectedThread->second.empty()) {
return;
}
const Thread &selectedThread = lastSelectedThread->first;
debugManager.printDebugMessage(name(),
"[SJF] Drain request in the ready batch of thread "
+ to_string((*lastSelectedThread).first.ID()) + " to bankbuffer "
+ to_string(bank.ID()));
}
const size_t &inclusiveEndLoc = lastSelectedThread->second.front();
assert(inclusiveEndLoc < requestBuffers.size());
for (size_t i = 0; i <= inclusiveEndLoc; ++i)
{
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[selectedThread].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,118 +160,107 @@ 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 == readyBatchInclusiveEndLocs.end())
{
nextSelectedThread = readyBatchIters.begin();
lastSelectedThread = readyBatchInclusiveEndLocs.begin();
if (!(*lastSelectedThread).second.empty()) {
return true;
}
}
if (nextSelectedThread == savedOriginalNextSelectedThread)
std::map<Thread, std::deque<size_t>>::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 == readyBatchInclusiveEndLocs.end()) {
lastSelectedThread = readyBatchInclusiveEndLocs.begin();
}
if (lastSelectedThread == savedOriginalNextSelectedThread) {
return false;
}
} while ((*lastSelectedThread).second.empty());
bool SMS::isSystemLightlyLoaded() {
unsigned int totalRequest = 0;
for (auto& bankBuffer : bankBuffers) {
totalRequest += bankBuffer.second.size();
}
return (totalRequest <= LOW_SYSTEM_LOAD);
}
bool SMS::existLowIntensityThread() {
for (auto& mpkcPerThread : MPKCs) {
if (mpkcPerThread.second < LOW_MPKC) {
return true;
}
}
return false;
}
bool SMS::isThresholdAgeExceeded(Thread thread, sc_time memClk, std::deque<gp*>::iterator begin, std::deque<gp*>::iterator end) {
// 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();
if (reqGenerationTime < oldestGenerationTime) {
oldestGenerationTime = reqGenerationTime;
}
}
// check threshold age according to the thread's MPKC
sc_time oldestRequestAge = sc_time_stamp() - oldestGenerationTime;
if ((MPKCs[thread] <= MEDIUM_MPKC) && (oldestRequestAge > (MEDIUM_THRESHOLD_AGE * memClk))) {
debugManager.printDebugMessage(name(),
"[RR] Select ready batch of thread " + to_string((*lastSelectedThread).first.ID()));
return true;
} else if ((MPKCs[thread] > MEDIUM_MPKC) && (oldestRequestAge > (HIGH_THRESHOLD_AGE * memClk))) {
return true;
} else {
}
bool SMS::isSystemLightlyLoaded() const {
unsigned int totalRequest = 0;
for (const auto &bankBuffer : bankBuffers) {
totalRequest += bankBuffer.second.size();
}
return (totalRequest <= LOW_SYSTEM_LOAD);
}
bool SMS::existLowIntensityThread() const {
for (const auto &mpkcPerThread : MPKCs) {
if (mpkcPerThread.second < LOW_MPKC) {
return true;
}
}
return false;
}
}
void SMS::updateMPKCs(sc_time memClk) {
if (sc_time_stamp() % (MPKC_RESET_CYCLE * memClk) <= memClk) {
// reset for every 10k clk cycles
for (auto& cacheMiss : cacheMisses) {
MPKCs[cacheMiss.first] = 0;
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 (size_t i = inclusiveBeginLoc; i != exclusiveEndLoc; ++i) {
sc_time reqGenerationTime = GenerationExtension::getExtension(requestBuffers[thread][i]).TimeOfGeneration();
if (reqGenerationTime < oldestGenerationTime) {
oldestGenerationTime = reqGenerationTime;
}
}
debugManager.printDebugMessage(name(), "Reset MKKCs");
} else {
// update MPKC for every thread
for (auto& cacheMiss : cacheMisses) {
MPKCs[cacheMiss.first] = (cacheMiss.second * 1000.0 * memClk) / (sc_time_stamp());
// check threshold age according to the thread's MPKC
sc_time oldestRequestAge = sc_time_stamp() - oldestGenerationTime;
if ((MPKCs[thread] <= MEDIUM_MPKC) && (oldestRequestAge > (MEDIUM_THRESHOLD_AGE * memClk))) {
return true;
} else if ((MPKCs[thread] > MEDIUM_MPKC) && (oldestRequestAge > (HIGH_THRESHOLD_AGE * memClk))) {
return true;
} else {
return false;
}
debugManager.printDebugMessage(name(), "Update MPKCs");
}
}
bool SMS::isExceededReqBufferSize(Thread thread) {
return requestBuffers[thread].size() == Configuration::getInstance().RequestBufferSize;
void SMS::updateMPKCs(sc_time const &memClk) {
if (sc_time_stamp() % (MPKC_RESET_CYCLE * memClk) <= memClk) {
// reset for every 10k clk cycles
for (const auto &cacheMiss : cacheMisses) {
MPKCs[cacheMiss.first] = 0;
}
debugManager.printDebugMessage(name(), "Reset MKKCs");
} else {
// update MPKC for every thread
for (const auto &cacheMiss : cacheMisses) {
MPKCs[cacheMiss.first] = (cacheMiss.second * 1000.0 * memClk) / (sc_time_stamp());
}
debugManager.printDebugMessage(name(), "Update MPKCs");
}
}
bool SMS::isRequestBuffersEmpty() {
for (auto& requestBuffer : requestBuffers) {
if (!requestBuffer.second.empty()) {
return false;
}
}
return true;
bool SMS::isExceededReqBufferSize(size_t const &exclusiveEndLoc) {
return exclusiveEndLoc <= Configuration::getInstance().RequestBufferSize;
}
bool SMS::existReadyBatches() {
for (auto& each : readyBatchIters) {
if (!each.second.empty()) {
return true;
bool SMS::isRequestBuffersEmpty() const {
for (const auto &requestBuffer : requestBuffers) {
if (!requestBuffer.second.empty()) {
return false;
}
}
}
return false;
return true;
}
bool SMS::existReadyBatches() const {
for (const auto &each : readyBatchInclusiveEndLocs) {
if (!each.second.empty()) {
return true;
}
}
return false;
}
/**
@@ -276,82 +270,100 @@ 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, size_t const &inclusiveBeginLoc)
{
if (requestBuffer.second.empty())
{
return false;
}
if (requestBuffer.second.end() == beginIter)
{
return false;
}
if (MPKCs[requestBuffer.first] < LOW_MPKC || isSystemLightlyLoaded())
{
// bypass requests by forming batch with only one request (threshold age is ZERO)
readyBatchIters[requestBuffer.first].push_back(beginIter);
return true;
}
else
{
// forming batch with FIFO size & threshold age constraints
auto firstDifferentRowAccessReqIter = beginIter;
Row firstRow = DramExtension::getRow(*beginIter);
while (firstDifferentRowAccessReqIter != requestBuffer.second.end()
&& DramExtension::getRow(*firstDifferentRowAccessReqIter) == firstRow)
if (requestBuffer.empty())
{
firstDifferentRowAccessReqIter++;
return false;
}
// deem this batch ready
if ((firstDifferentRowAccessReqIter != requestBuffer.second.end())
|| isExceededReqBufferSize(requestBuffer.first)
|| isThresholdAgeExceeded(requestBuffer.first, memClk, beginIter,
firstDifferentRowAccessReqIter))
assert(inclusiveBeginLoc <= requestBuffer.size());
if (requestBuffer.size() == inclusiveBeginLoc)
{
firstDifferentRowAccessReqIter--;
readyBatchIters[requestBuffer.first].push_back(firstDifferentRowAccessReqIter);
debugManager.printDebugMessage(name(),
"Deem batch ready - thread " + to_string(requestBuffer.first.ID()));
return true;
return false;
}
if (MPKCs[thread] < LOW_MPKC || isSystemLightlyLoaded())
{
// bypass requests by forming batch with only one request (threshold age is ZERO)
readyBatchInclusiveEndLocs[thread].push_back(inclusiveBeginLoc);
return true;
}
else
{
return false;
// forming batch with FIFO size & threshold age constraints
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)
{
++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;
}
}
}
// store this ready batch location
if (isBatchReady)
{
--firstDifferentRowAccessReqLoc;
readyBatchInclusiveEndLocs[thread].push_back(firstDifferentRowAccessReqLoc);
debugManager.printDebugMessage(name(),
"Deem batch ready - thread " + to_string(thread.ID()));
return true;
}
else
{
return false;
}
}
}
}
void SMS::multiBatchFormation(sc_time memClk)
void SMS::multiBatchFormation(sc_time const &memClk)
{
for (auto& requestBuffer : requestBuffers)
{
bool formed;
do
for (auto &requestBuffer : requestBuffers)
{
if (readyBatchIters[requestBuffer.first].empty())
{
formed = batchFormation(memClk, (std::pair<Thread, std::deque<gp*>>&)requestBuffer, requestBuffer.second.begin());
}
else
{
formed = batchFormation(memClk, (std::pair<Thread, std::deque<gp*>>&)requestBuffer, readyBatchIters[requestBuffer.first].back() + 1);
}
} while (formed);
}
bool formed = false;
do
{
if (readyBatchInclusiveEndLocs[requestBuffer.first].empty())
{
formed = batchFormation(memClk, requestBuffer.first, requestBuffer.second, 0);
}
else
{
formed = batchFormation(memClk, requestBuffer.first, requestBuffer.second, readyBatchInclusiveEndLocs[requestBuffer.first].back() + 1);
}
} while (!requestBuffer.second.empty() && formed);
}
}
gp* SMS::getPendingRequest(Bank bank)
{
for (auto& requestBuffer : requestBuffers) {
for (auto& request : requestBuffer.second) {
if (DramExtension::getBank(request) == bank) {
return request;
}
for (const auto &requestBuffer : requestBuffers) {
for (const auto &request : requestBuffer.second) {
if (DramExtension::getBank(request) == bank) {
return request;
}
}
}
}
return NULL;
return NULL;
}

View File

@@ -34,9 +34,9 @@ class SMS: public sc_module, public IScheduler
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();
SC_THREAD(batchScheduler);
// initialize selected thread iterator
lastSelectedThread = readyBatchInclusiveEndLocs.end();
SC_THREAD(batchScheduler);
}
SC_HAS_PROCESS(SMS);
@@ -53,32 +53,32 @@ 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 memClk, std::pair<Thread, std::deque<gp*>> &requestBuffer, std::deque<gp*>::iterator beginIter);
void multiBatchFormation(sc_time memClk);
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(sc_time memClk, std::deque<gp*>::iterator last);
void drainOnePayloadFromReadybatch(const sc_time &memClk);
bool existLowIntensityThread();
bool isSystemLightlyLoaded();
bool isThresholdAgeExceeded(Thread thread, sc_time memClk, std::deque<gp*>::iterator begin, std::deque<gp*>::iterator end);
bool isExceededReqBufferSize(Thread thread);
void updateMPKCs(sc_time memClk);
bool existLowIntensityThread() const;
bool isSystemLightlyLoaded() const;
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();
bool existReadyBatches();
bool isRequestBuffersEmpty() const;
bool existReadyBatches() const;
};
#endif // SMS_H