diff --git a/DRAMSys/analyzer/businessObjects/phases/phase.h b/DRAMSys/analyzer/businessObjects/phases/phase.h index 62c5ea27..ef8d187a 100644 --- a/DRAMSys/analyzer/businessObjects/phases/phase.h +++ b/DRAMSys/analyzer/businessObjects/phases/phase.h @@ -180,7 +180,7 @@ public: using AUTO_REFRESH::AUTO_REFRESH; protected: virtual QString Name() const override {return "REFA";} - virtual bool isBankwise() const {return false;} + virtual bool isBankwise() const override {return false;} }; class REFB : public AUTO_REFRESH @@ -201,7 +201,7 @@ protected: virtual std::vector getTimesOnCommandBus() const {return {span.Begin()};} virtual QColor getColor(const TraceDrawingProperties &drawingProperties) const override {Q_UNUSED(drawingProperties) return getPhaseColor();} virtual QColor getPhaseColor() const override {return ColorGenerator::getColor(10);} - virtual bool isBankwise() const {return false;} + virtual bool isBankwise() const override {return false;} }; class PDNAB : public Phase @@ -222,7 +222,7 @@ public: using PDNAB::PDNAB; protected: virtual QString Name() const override {return "PDNA";} - virtual bool isBankwise() const {return false;} + virtual bool isBankwise() const override {return false;} }; class PDNPB : public Phase @@ -243,7 +243,7 @@ public: using PDNPB::PDNPB; protected: virtual QString Name() const override {return "PDNP";} - virtual bool isBankwise() const {return false;} + virtual bool isBankwise() const override {return false;} }; class SREFB : public Phase @@ -251,8 +251,8 @@ class SREFB : public Phase public: using Phase::Phase; protected: - virtual QString Name() const {return "SREFB";} - virtual Qt::BrushStyle getBrushStyle() const {return Qt::Dense1Pattern;} + virtual QString Name() const override {return "SREFB";} + virtual Qt::BrushStyle getBrushStyle() const override {return Qt::Dense1Pattern;} virtual QColor getColor(const TraceDrawingProperties &drawingProperties) const override {Q_UNUSED(drawingProperties) return getPhaseColor();} virtual QColor getPhaseColor() const override {return QColor(Qt::black);} virtual Phase::PhaseSymbol getPhaseSymbol() const override {return PhaseSymbol::Rect;} @@ -264,7 +264,7 @@ public: using SREFB::SREFB; protected: virtual QString Name() const override {return "SREF";} - virtual bool isBankwise() const {return false;} + virtual bool isBankwise() const override {return false;} }; diff --git a/DRAMSys/analyzer/businessObjects/timespan.h b/DRAMSys/analyzer/businessObjects/timespan.h index c54f99b0..dcc32839 100644 --- a/DRAMSys/analyzer/businessObjects/timespan.h +++ b/DRAMSys/analyzer/businessObjects/timespan.h @@ -38,6 +38,7 @@ #ifndef TIMESPAN_H #define TIMESPAN_H #include +#include #include "tracetime.h" class Timespan @@ -47,7 +48,7 @@ class Timespan public: Timespan(traceTime begin = 0, traceTime end = 0) : begin(begin), end(end){} - traceTime timeCovered() const{return abs(End()-Begin());} + traceTime timeCovered() const{return std::abs(End()-Begin());} traceTime Begin() const{return begin;} void setBegin(traceTime time){begin = time;} traceTime End() const{return end;} diff --git a/DRAMSys/simulator/library.pro b/DRAMSys/simulator/library.pro index 5e9f63a4..4cac1673 100644 --- a/DRAMSys/simulator/library.pro +++ b/DRAMSys/simulator/library.pro @@ -81,6 +81,7 @@ SOURCES += \ src/controller/scheduler/PARBS.cpp \ src/controller/scheduler/Fr_Fcfs.cpp \ src/controller/scheduler/Fifo.cpp \ + src/controller/scheduler/SMS.cpp \ src/controller/core/refresh/RefreshManagerBankwise.cpp \ src/controller/core/refresh/RefreshManager.cpp \ src/controller/core/scheduling/checker/WriteChecker.cpp \ @@ -130,6 +131,7 @@ HEADERS += \ src/controller/scheduler/PARBS.h \ src/controller/scheduler/Fr_Fcfs.h \ src/controller/scheduler/Fifo.h \ + src/controller/scheduler/SMS.h \ src/controller/Controller.h \ src/controller/core/refresh/RefreshManagerBankwise.h \ src/controller/core/refresh/RefreshManager.h \ diff --git a/DRAMSys/simulator/resources/configs/mcconfigs/sms.xml b/DRAMSys/simulator/resources/configs/mcconfigs/sms.xml new file mode 100644 index 00000000..088a9f66 --- /dev/null +++ b/DRAMSys/simulator/resources/configs/mcconfigs/sms.xml @@ -0,0 +1,16 @@ + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/DRAMSys/simulator/resources/configs/simulator/sms.xml b/DRAMSys/simulator/resources/configs/simulator/sms.xml new file mode 100644 index 00000000..deec1b3b --- /dev/null +++ b/DRAMSys/simulator/resources/configs/simulator/sms.xml @@ -0,0 +1,14 @@ + + + + + + + + + + + + + + diff --git a/DRAMSys/simulator/resources/resources.pri b/DRAMSys/simulator/resources/resources.pri index fc1d85c7..914daa88 100644 --- a/DRAMSys/simulator/resources/resources.pri +++ b/DRAMSys/simulator/resources/resources.pri @@ -5,14 +5,14 @@ OTHER_FILES += resources/simulations/ddr3-example.xml OTHER_FILES += resources/simulations/ddr3-single-device.xml OTHER_FILES += resources/simulations/wideio-example.xml - +OTHER_FILES += resources/simulations/sms-example.xml # Simulator Files OTHER_FILES += resources/configs/simulator/wideio.xml OTHER_FILES += resources/configs/simulator/ddr3.xml OTHER_FILES += resources/configs/simulator/ddr3-single-device.xml OTHER_FILES += resources/configs/simulator/wideio_thermal.xml - +OTHER_FILES += resources/configs/simulator/sms.xml # Scripts OTHER_FILES += resources/scripts/address_scrambler.pl @@ -60,12 +60,17 @@ OTHER_FILES += resources/traces/mediabench-adpcmdecode_32.stl OTHER_FILES += resources/traces/ddr3_example.stl OTHER_FILES += resources/traces/ddr3_single_dev_example.stl OTHER_FILES += resources/traces/ddr3_SAMSUNG_M471B5674QH0_DIMM_example.stl +OTHER_FILES += resources/traces/sms_t1.stl +OTHER_FILES += resources/traces/sms_t2.stl +OTHER_FILES += resources/traces/sms_t3.stl +OTHER_FILES += resources/traces/sms_t4.stl # Memory Controller Configs OTHER_FILES += resources/configs/mcconfigs/fifoStrict.xml OTHER_FILES += resources/configs/mcconfigs/fifo.xml OTHER_FILES += resources/configs/mcconfigs/fr_fcfs.xml OTHER_FILES += resources/configs/mcconfigs/par_bs.xml +OTHER_FILES += resources/configs/mcconfigs/sms.xml # Memspecs OTHER_FILES += resources/configs/memspecs/memspec.dtd diff --git a/DRAMSys/simulator/resources/simulations/sms-example.xml b/DRAMSys/simulator/resources/simulations/sms-example.xml new file mode 100644 index 00000000..d40e0e8c --- /dev/null +++ b/DRAMSys/simulator/resources/simulations/sms-example.xml @@ -0,0 +1,26 @@ + + + + + + + + + + + + + + + ddr3_example.stl + sms_t1.stl + sms_t2.stl + sms_t3.stl + sms_t4.stl + stream.stl + random.stl + chstone-adpcm_32.stl + + + + diff --git a/DRAMSys/simulator/src/common/tlm2_base_protocol_checker.h b/DRAMSys/simulator/src/common/tlm2_base_protocol_checker.h index eb0833a1..99b5ce10 100755 --- a/DRAMSys/simulator/src/common/tlm2_base_protocol_checker.h +++ b/DRAMSys/simulator/src/common/tlm2_base_protocol_checker.h @@ -343,7 +343,7 @@ void tlm2_base_protocol_checker:: BOILERPLATE b_transport_pre_checks( - tlm::tlm_generic_payload& trans, sc_core::sc_time& delay) + tlm::tlm_generic_payload& trans, sc_core::sc_time& /*delay*/) { ++ m_map[&trans].b_call; @@ -372,7 +372,7 @@ b_transport_pre_checks( BOILERPLATE b_transport_post_checks( - tlm::tlm_generic_payload& trans, sc_core::sc_time& delay) + tlm::tlm_generic_payload& trans, sc_core::sc_time& /*delay*/) { check_response_path(trans, "b_transport"); check_trans_not_modified(trans, "b_transport"); @@ -914,7 +914,7 @@ get_direct_mem_ptr_pre_checks( BOILERPLATE -get_direct_mem_ptr_post_checks( tlm::tlm_generic_payload& trans, tlm::tlm_dmi& dmi_data ) +get_direct_mem_ptr_post_checks( tlm::tlm_generic_payload& trans, tlm::tlm_dmi& /*dmi_data*/ ) { tlm::tlm_generic_payload* init = m_map[&trans].gp; diff --git a/DRAMSys/simulator/src/controller/Controller.cpp b/DRAMSys/simulator/src/controller/Controller.cpp index eee71da6..bf68d7d4 100644 --- a/DRAMSys/simulator/src/controller/Controller.cpp +++ b/DRAMSys/simulator/src/controller/Controller.cpp @@ -53,6 +53,10 @@ void Controller::buildScheduler() { scheduler = new FR_FCFS(*controllerCore); } + else if (selectedScheduler == "SMS") + { + scheduler = new SMS("SMS", *controllerCore, Configuration::getInstance().SJFProbability); + } //else if (selectedScheduler == "PAR_BS") //{ // scheduler = new PAR_BS(*controllerCore,Configuration::getInstance().RefreshAwareScheduling, @@ -296,6 +300,11 @@ void Controller::frontendPEQCallback(tlm_generic_payload &payload, const tlm_pha scheduler->schedule(&payload); scheduleNextFromScheduler(DramExtension::getExtension(payload).getBank()); } + else if (phase == PendingRequest) + { + // Schedule a pending request. + scheduleNextFromScheduler(DramExtension::getExtension(payload).getBank()); + } else if (phase == END_RESP) { if (backpressure != NULL) @@ -361,6 +370,7 @@ void Controller::scheduleNextFromScheduler(Bank bank) return; } + bool rescheduled = true; pair nextRequest = scheduler->getNextRequest(bank); if(nextRequest.second != NULL) { @@ -368,7 +378,17 @@ void Controller::scheduleNextFromScheduler(Bank bank) controllerCore->scheduleRequest(nextRequest.first, *nextRequest.second); printDebugMessage("\t-> Next payload was scheduled by core [" + commandToString(nextRequest.first) + "]"); } + else + { + gp* pendingRequest = scheduler->getPendingRequest(bank); + if (pendingRequest != NULL) + { + rescheduled = true; + frontendPEQ.notify(*(pendingRequest), PendingRequest, Configuration::getInstance().memSpec.clk); + } + } + queue blocked; while (!blockedRequests.empty()) { bank = blockedRequests.front(); blockedRequests.pop(); @@ -379,7 +399,23 @@ void Controller::scheduleNextFromScheduler(Bank bank) controllerCore->scheduleRequest(nextRequest.first, *nextRequest.second); printDebugMessage("\t-> Next payload was scheduled by core [" + commandToString(nextRequest.first) + "] (unblocked)"); } + else + { + gp* pendingRequest = scheduler->getPendingRequest(bank); + if(pendingRequest != NULL) + { + //Pending request + if(!rescheduled) + { + rescheduled = true; + frontendPEQ.notify(*(pendingRequest), PendingRequest, Configuration::getInstance().memSpec.clk); + } + else + blocked.push(bank); + } + } } + blockedRequests = blocked; } void Controller::sendToFrontend(tlm_generic_payload &payload, const tlm_phase &phase, const sc_time &delay) diff --git a/DRAMSys/simulator/src/controller/Controller.h b/DRAMSys/simulator/src/controller/Controller.h index 74695fe3..b5f67ff7 100644 --- a/DRAMSys/simulator/src/controller/Controller.h +++ b/DRAMSys/simulator/src/controller/Controller.h @@ -67,11 +67,14 @@ #include "scheduler/Fifo.h" #include "scheduler/FifoStrict.h" #include "scheduler/Fr_Fcfs.h" +#include "scheduler/SMS.h" #include "scheduler/IScheduler.h" using namespace std; using namespace tlm; +DECLARE_EXTENDED_PHASE(PendingRequest); + struct Controller: public sc_module, public IController { public: @@ -85,7 +88,7 @@ public: tSocket.register_transport_dbg(this, &Controller::transport_dbg); } - ~Controller() + virtual ~Controller() { delete controllerCore; delete scheduler; @@ -109,7 +112,7 @@ private: void buildScheduler(); void payloadEntersSystem(tlm_generic_payload& payload); void payloadLeavesSystem(tlm_generic_payload& payload); - void scheduleNextFromScheduler(Bank bank); + void scheduleNextFromScheduler(Bank bank) override; // --- FRONTEND ------ tlm_sync_enum nb_transport_fw(tlm_generic_payload& payload, tlm_phase& phase, sc_time& fwDelay); diff --git a/DRAMSys/simulator/src/controller/core/ControllerCore.h b/DRAMSys/simulator/src/controller/core/ControllerCore.h index 7f32e805..821c2944 100644 --- a/DRAMSys/simulator/src/controller/core/ControllerCore.h +++ b/DRAMSys/simulator/src/controller/core/ControllerCore.h @@ -55,7 +55,7 @@ class ControllerCore : public sc_module { public: ControllerCore(sc_module_name /*name*/, IController& controller, std::map& numberOfPayloads); - virtual ~ControllerCore() ; + virtual ~ControllerCore(); void scheduleRequest(Command command, tlm::tlm_generic_payload& payload); void triggerRefresh(tlm::tlm_generic_payload& payload); diff --git a/DRAMSys/simulator/src/controller/core/configuration/Configuration.cpp b/DRAMSys/simulator/src/controller/core/configuration/Configuration.cpp index ded14c17..f0fd7f68 100644 --- a/DRAMSys/simulator/src/controller/core/configuration/Configuration.cpp +++ b/DRAMSys/simulator/src/controller/core/configuration/Configuration.cpp @@ -140,6 +140,14 @@ void Configuration::setParameter(std::string name, std::string value) MaxNrOfTransactions = string2int(value); else if(name == "Scheduler") Scheduler = value; + else if(name == "SJFProbability") + if (string2int(value) > 100 || string2int(value) < 0) { + SC_REPORT_FATAL("Configuration", ("Invalid value for parameter " + name + ". This parameter must be between 0 and 100.").c_str()); + } else { + SJFProbability = string2int(value); + } + else if (name == "RequestBufferSize") + RequestBufferSize = string2int(value); else if(name == "Capsize") Capsize = string2int(value); else if(name == "PowerDownTimeout") diff --git a/DRAMSys/simulator/src/controller/core/configuration/Configuration.h b/DRAMSys/simulator/src/controller/core/configuration/Configuration.h index 8695b133..2f158053 100644 --- a/DRAMSys/simulator/src/controller/core/configuration/Configuration.h +++ b/DRAMSys/simulator/src/controller/core/configuration/Configuration.h @@ -62,6 +62,8 @@ struct Configuration bool OpenPagePolicy = true; unsigned int MaxNrOfTransactions = 8; std::string Scheduler; + unsigned int SJFProbability; + unsigned int RequestBufferSize; unsigned int Capsize = 5; sc_time getPowerDownTimeout(){return powerDownTimeoutInClk*memSpec.clk;} EPowerDownMode PowerDownMode = EPowerDownMode::Staggered; diff --git a/DRAMSys/simulator/src/controller/scheduler/Fifo.cpp b/DRAMSys/simulator/src/controller/scheduler/Fifo.cpp index beb57612..7d7a90e1 100644 --- a/DRAMSys/simulator/src/controller/scheduler/Fifo.cpp +++ b/DRAMSys/simulator/src/controller/scheduler/Fifo.cpp @@ -60,4 +60,9 @@ pair Fifo::getNextRequest(Bank bank) return pair(Command::NOP, NULL); } +gp* Fifo::getPendingRequest(Bank bank) +{ + return NULL; +} + diff --git a/DRAMSys/simulator/src/controller/scheduler/Fifo.h b/DRAMSys/simulator/src/controller/scheduler/Fifo.h index 0576bb32..1b060b12 100644 --- a/DRAMSys/simulator/src/controller/scheduler/Fifo.h +++ b/DRAMSys/simulator/src/controller/scheduler/Fifo.h @@ -52,6 +52,7 @@ public: void schedule(gp* payload) override; std::pair getNextRequest(Bank bank) override; + virtual gp* getPendingRequest(Bank bank) override; private: std::map> buffer; diff --git a/DRAMSys/simulator/src/controller/scheduler/FifoStrict.cpp b/DRAMSys/simulator/src/controller/scheduler/FifoStrict.cpp index f9881fee..6e8bd292 100644 --- a/DRAMSys/simulator/src/controller/scheduler/FifoStrict.cpp +++ b/DRAMSys/simulator/src/controller/scheduler/FifoStrict.cpp @@ -128,3 +128,7 @@ std::pair FifoStrict::getNextRequest(Bank b return pair(Command::NOP, NULL); } +gp* FifoStrict::getPendingRequest(Bank bank) +{ + return NULL; +} diff --git a/DRAMSys/simulator/src/controller/scheduler/FifoStrict.h b/DRAMSys/simulator/src/controller/scheduler/FifoStrict.h index 1cc9ece0..855f7ff3 100644 --- a/DRAMSys/simulator/src/controller/scheduler/FifoStrict.h +++ b/DRAMSys/simulator/src/controller/scheduler/FifoStrict.h @@ -56,6 +56,7 @@ public: void schedule(gp* payload) override; std::pair getNextRequest(Bank bank) override; + virtual gp* getPendingRequest(Bank bank) override; private: std::deque> buffer; diff --git a/DRAMSys/simulator/src/controller/scheduler/Fr_Fcfs.cpp b/DRAMSys/simulator/src/controller/scheduler/Fr_Fcfs.cpp index 30750c7f..5b022ca6 100644 --- a/DRAMSys/simulator/src/controller/scheduler/Fr_Fcfs.cpp +++ b/DRAMSys/simulator/src/controller/scheduler/Fr_Fcfs.cpp @@ -121,3 +121,8 @@ deque::iterator FR_FCFS::FindRowHit(Bank bank) return queue.end(); } + +gp* FR_FCFS::getPendingRequest(Bank bank) +{ + return NULL; +} diff --git a/DRAMSys/simulator/src/controller/scheduler/Fr_Fcfs.h b/DRAMSys/simulator/src/controller/scheduler/Fr_Fcfs.h index 187b81ab..9347c21f 100644 --- a/DRAMSys/simulator/src/controller/scheduler/Fr_Fcfs.h +++ b/DRAMSys/simulator/src/controller/scheduler/Fr_Fcfs.h @@ -53,6 +53,7 @@ public: void schedule(gp* payload) override; std::pair getNextRequest(Bank bank) override; + virtual gp* getPendingRequest(Bank bank) override; private: std::map> buffer; diff --git a/DRAMSys/simulator/src/controller/scheduler/IScheduler.h b/DRAMSys/simulator/src/controller/scheduler/IScheduler.h index a951d015..efeebdc4 100644 --- a/DRAMSys/simulator/src/controller/scheduler/IScheduler.h +++ b/DRAMSys/simulator/src/controller/scheduler/IScheduler.h @@ -54,6 +54,7 @@ public: virtual void schedule(gp* payload) = 0; virtual std::pair getNextRequest(Bank bank) = 0; + virtual gp* getPendingRequest(Bank bank) = 0; static std::string sendername; protected: diff --git a/DRAMSys/simulator/src/controller/scheduler/SMS.cpp b/DRAMSys/simulator/src/controller/scheduler/SMS.cpp new file mode 100644 index 00000000..64882dc3 --- /dev/null +++ b/DRAMSys/simulator/src/controller/scheduler/SMS.cpp @@ -0,0 +1,357 @@ +#include "SMS.h" +#include + +using namespace std; + +void SMS::schedule(gp *payload) +{ + Thread thread = DramExtension::getExtension(payload).getThread(); + bool wasEmpty = isRequestBuffersEmpty(); + + requestBuffers[thread].emplace_back(payload); + + if (inFlightMemRequestCounter.find(thread) == inFlightMemRequestCounter.end()) { + inFlightMemRequestCounter[thread] = 0; + cacheMisses[thread] = 0; + } + inFlightMemRequestCounter[thread]++; + cacheMisses[thread]++; + + if (wasEmpty) { + newRequest.notify(SC_ZERO_TIME); + } +} + +std::pair 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::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, payload); + } +} + +void SMS::batchScheduler() +{ + 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(); + } + } else { + if (pickRR()) { + drain(memClk, (*lastSelectedThread).second.front()); + (*lastSelectedThread).second.pop_front(); + } + } + } else { + wait(memClk); + } + } + } +} + +/** + * Pick a Thread according to Shortest-Job Policy + * Save the picked one into lastSelectedThread + * @return true if it can, otherwise false + */ +bool SMS::pickSJF() +{ + // find threads with ready batches + std::vector threadsWithReadyBatches; + for (auto& each : readyBatchIters) + { + if (!each.second.empty()) + { + // 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; + } + } + + // 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; + } +} + +/** + * Drain the picked request buffer into bank buffers + * by move request one-by-one from start of the request buffer till last parameter + * @param memClk + * @param last + */ +void SMS::drain(sc_time memClk, std::deque::iterator last) +{ + 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(); + + debugManager.printDebugMessage(name(), + "[SJF] Drain request in the ready batch of thread " + + to_string((*lastSelectedThread).first.ID()) + " to bankbuffer " + + to_string(bank.ID())); + } +} + +/** + * Pick a Thread according to Round-Robin Policy + * Save the picked one into lastSelectedThread + * @return true if it can pick one, otherwise false + */ +bool SMS::pickRR() +{ + std::map>::iterator nextSelectedThread; + if (lastSelectedThread == readyBatchIters.end()) + { + lastSelectedThread = readyBatchIters.begin(); + nextSelectedThread = lastSelectedThread; + } + else + { + nextSelectedThread = lastSelectedThread; + nextSelectedThread++; + if (nextSelectedThread == readyBatchIters.end()) + nextSelectedThread = readyBatchIters.begin(); + } + + std::map>::iterator savedOriginalNextSelectedThread = nextSelectedThread; + + while ((*nextSelectedThread).second.empty()) + { + nextSelectedThread++; + if (nextSelectedThread == readyBatchIters.end()) + { + nextSelectedThread = readyBatchIters.begin(); + } + + if (nextSelectedThread == savedOriginalNextSelectedThread) + { + // 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; +} + +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::iterator begin, std::deque::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))) { + return true; + } else if ((MPKCs[thread] > MEDIUM_MPKC) && (oldestRequestAge > (HIGH_THRESHOLD_AGE * memClk))) { + return true; + } else { + 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; + } + 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()); + } + debugManager.printDebugMessage(name(), "Update MPKCs"); + } +} + +bool SMS::isExceededReqBufferSize(Thread thread) { + return requestBuffers[thread].size() == Configuration::getInstance().RequestBufferSize; +} + +bool SMS::isRequestBuffersEmpty() { + for (auto& requestBuffer : requestBuffers) { + if (!requestBuffer.second.empty()) { + return false; + } + } + return true; +} + +bool SMS::existReadyBatches() { + for (auto& each : readyBatchIters) { + if (!each.second.empty()) { + return true; + } + } + return false; +} + +/** + * Form batch from begin iterator parameter of a request buffer + * If this batch is deemed ready, save the iterator pointing to its last element + * @param memClk + * @param begin + * @return true if this batch is ready, otherwise false + */ +bool SMS::batchFormation(sc_time memClk, std::pair> &requestBuffer, + std::deque::iterator beginIter) +{ + 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) + { + firstDifferentRowAccessReqIter++; + } + + // deem this batch ready + if ((firstDifferentRowAccessReqIter != requestBuffer.second.end()) + || isExceededReqBufferSize(requestBuffer.first) + || isThresholdAgeExceeded(requestBuffer.first, memClk, beginIter, + firstDifferentRowAccessReqIter)) + { + firstDifferentRowAccessReqIter--; + readyBatchIters[requestBuffer.first].push_back(firstDifferentRowAccessReqIter); + debugManager.printDebugMessage(name(), + "Deem batch ready - thread " + to_string(requestBuffer.first.ID())); + return true; + } + else + { + return false; + } + } +} + +void SMS::multiBatchFormation(sc_time memClk) +{ + for (auto& requestBuffer : requestBuffers) + { + bool formed; + do + { + if (readyBatchIters[requestBuffer.first].empty()) + { + formed = batchFormation(memClk, (std::pair>&)requestBuffer, requestBuffer.second.begin()); + } + else + { + formed = batchFormation(memClk, (std::pair>&)requestBuffer, readyBatchIters[requestBuffer.first].back() + 1); + } + } while (formed); + } +} + +gp* SMS::getPendingRequest(Bank bank) +{ + for (auto& requestBuffer : requestBuffers) { + for (auto& request : requestBuffer.second) { + if (DramExtension::getBank(request) == bank) { + return request; + } + } + } + return NULL; +} diff --git a/DRAMSys/simulator/src/controller/scheduler/SMS.h b/DRAMSys/simulator/src/controller/scheduler/SMS.h new file mode 100644 index 00000000..2843b990 --- /dev/null +++ b/DRAMSys/simulator/src/controller/scheduler/SMS.h @@ -0,0 +1,84 @@ +#ifndef SMS_H +#define SMS_H + +#include +#include +#include "sysc/utils/sc_report.h" +#include "IScheduler.h" +#include "../core/ControllerCore.h" +#include "../core/configuration/Configuration.h" +#include "../../common/dramExtension.h" +#include "../../common/DebugManager.h" + +#define LOW_SYSTEM_LOAD 16 +#define LOW_MPKC 1 +#define MEDIUM_MPKC 10 +#define MEDIUM_THRESHOLD_AGE 50 +#define HIGH_THRESHOLD_AGE 200 +#define MPKC_RESET_CYCLE 10000 + +using namespace std; +typedef std::deque::iterator gp_deque_iterator; + +/** + * SMS - Staged Memory Scheduler involves 3 steps: + * 1. Arrage request in to each buffer of each thread + * 2. Forming ready batches for each thread, i.e all requests access the same row. The batch is deemed + * ready when the next request accesses different row OR When the buffer is full OR When this batch + * is too old + * 3. Send batches to bank buffers. The rules to send batches are Shortest-Job-First OR Round-Robin + * How we select the rule depends on the probability we setup earlier. + */ +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); + } + SC_HAS_PROCESS(SMS); + + virtual ~SMS() + { + } + + virtual void schedule(gp *payload) override; + virtual std::pair getNextRequest(Bank bank) override; + virtual gp* getPendingRequest(Bank bank) override; + + void batchScheduler(); + +private: + std::map> requestBuffers; + std::map> bankBuffers; + std::map> readyBatchIters; + + std::map inFlightMemRequestCounter; + std::map cacheMisses; + std::map MPKCs; + unsigned int SJFprobability; + + std::map>::iterator lastSelectedThread; + sc_event newRequest; + + DebugManager& debugManager; + + bool batchFormation(sc_time memClk, std::pair> &requestBuffer, std::deque::iterator beginIter); + void multiBatchFormation(sc_time memClk); + bool pickSJF(); + bool pickRR(); + void drain(sc_time memClk, std::deque::iterator last); + + bool existLowIntensityThread(); + bool isSystemLightlyLoaded(); + bool isThresholdAgeExceeded(Thread thread, sc_time memClk, std::deque::iterator begin, std::deque::iterator end); + bool isExceededReqBufferSize(Thread thread); + void updateMPKCs(sc_time memClk); + + bool isRequestBuffersEmpty(); + bool existReadyBatches(); +}; + +#endif // SMS_H diff --git a/DRAMSys/simulator/src/simulation/Dram.h b/DRAMSys/simulator/src/simulation/Dram.h index fa3d9dec..a5254d97 100644 --- a/DRAMSys/simulator/src/simulation/Dram.h +++ b/DRAMSys/simulator/src/simulation/Dram.h @@ -92,6 +92,9 @@ struct Dram : sc_module SC_CTOR(Dram) : tSocket("socket") { + dramController = NULL; + tlmRecorder = NULL; + std::uint64_t memorySize = Configuration::getInstance().getSimMemSizeInBytes(); // allocate and model storage of one DRAM channel using memory map memory = (unsigned char *)mmap(NULL, memorySize, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANON | MAP_NORESERVE, -1, 0); diff --git a/DRAMSys/simulator/src/simulation/TracePlayerListener.h b/DRAMSys/simulator/src/simulation/TracePlayerListener.h index 95c52773..bec9f043 100644 --- a/DRAMSys/simulator/src/simulation/TracePlayerListener.h +++ b/DRAMSys/simulator/src/simulation/TracePlayerListener.h @@ -43,6 +43,7 @@ class TracePlayerListener public: virtual void tracePlayerTerminates() = 0; virtual void transactionFinished() = 0; + virtual ~TracePlayerListener(){}; }; #endif // TRACEPLAYERLISTENER_H diff --git a/DRAMSys/simulator/src/simulation/TraceSetup.cpp b/DRAMSys/simulator/src/simulation/TraceSetup.cpp index 56df4b14..951b6360 100644 --- a/DRAMSys/simulator/src/simulation/TraceSetup.cpp +++ b/DRAMSys/simulator/src/simulation/TraceSetup.cpp @@ -96,8 +96,6 @@ traceSetup::traceSetup(std::string uri, NumberOfTracePlayers = devices->size(); } - - void traceSetup::tracePlayerTerminates() { finishedTracePlayers++; diff --git a/DRAMSys/simulator/src/simulation/TraceSetup.h b/DRAMSys/simulator/src/simulation/TraceSetup.h index a9f0b8e5..a11b4abe 100644 --- a/DRAMSys/simulator/src/simulation/TraceSetup.h +++ b/DRAMSys/simulator/src/simulation/TraceSetup.h @@ -53,6 +53,7 @@ public: virtual void tracePlayerTerminates() override; virtual void transactionFinished() override; + virtual ~traceSetup(){}; private: unsigned int NumberOfTracePlayers;