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/gem5/gem5.pro b/DRAMSys/gem5/gem5.pro index cb3dcc2d..fe171ebd 100644 --- a/DRAMSys/gem5/gem5.pro +++ b/DRAMSys/gem5/gem5.pro @@ -48,7 +48,7 @@ INCLUDEPATH += ../simulator/src/common/third_party/DRAMPower/src/libdrampower INCLUDEPATH += $${gem5_root}/build/$${gem5_arch}/ INCLUDEPATH += $${gem5_root}/util/tlm/examples/slave_port INCLUDEPATH += $${gem5_root}/util/tlm/examples/common -INCLUDEPATH += $${gem5_root}/util/tlm/ +INCLUDEPATH += $${gem5_root}/util/tlm/src/ INCLUDEPATH += $${gem5_root}/util/systemc LIBS += -L$${systemc_home}/lib-$${systemc_target_arch} -lsystemc @@ -63,13 +63,13 @@ SOURCES += $${gem5_root}/util/systemc/sc_module.cc SOURCES += $${gem5_root}/util/systemc/stats.cc SOURCES += $${gem5_root}/util/tlm/examples/common/cli_parser.cc SOURCES += $${gem5_root}/util/tlm/examples/common/report_handler.cc -SOURCES += $${gem5_root}/util/tlm/master_transactor.cc -SOURCES += $${gem5_root}/util/tlm/sc_master_port.cc -SOURCES += $${gem5_root}/util/tlm/sc_slave_port.cc -SOURCES += $${gem5_root}/util/tlm/slave_transactor.cc -SOURCES += $${gem5_root}/util/tlm/sc_ext.cc -SOURCES += $${gem5_root}/util/tlm/sc_mm.cc -SOURCES += $${gem5_root}/util/tlm/sim_control.cc +SOURCES += $${gem5_root}/util/tlm/src/master_transactor.cc +SOURCES += $${gem5_root}/util/tlm/src/sc_master_port.cc +SOURCES += $${gem5_root}/util/tlm/src/sc_slave_port.cc +SOURCES += $${gem5_root}/util/tlm/src/slave_transactor.cc +SOURCES += $${gem5_root}/util/tlm/src/sc_ext.cc +SOURCES += $${gem5_root}/util/tlm/src/sc_mm.cc +SOURCES += $${gem5_root}/util/tlm/src/sim_control.cc SOURCES += main.cpp diff --git a/DRAMSys/simulator/library.pro b/DRAMSys/simulator/library.pro index c225875c..a0bb357c 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 \ @@ -135,6 +136,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 b3f97407..f240b193 100644 --- a/DRAMSys/simulator/resources/resources.pri +++ b/DRAMSys/simulator/resources/resources.pri @@ -7,6 +7,7 @@ OTHER_FILES += resources/simulations/ddr3-single-device.xml OTHER_FILES += resources/simulations/wideio-example.xml OTHER_FILES += resources/simulations/wideio-ecc.xml OTHER_FILES += resources/simulations/ddr3-ecc.xml +OTHER_FILES += resources/simulations/sms-example.xml # Simulator Files OTHER_FILES += resources/configs/simulator/wideio.xml @@ -15,6 +16,7 @@ OTHER_FILES += resources/configs/simulator/ddr3-single-device.xml OTHER_FILES += resources/configs/simulator/wideio_thermal.xml OTHER_FILES += resources/configs/simulator/wideio_ecc.xml OTHER_FILES += resources/configs/simulator/ddr3_ecc.xml +OTHER_FILES += resources/configs/simulator/sms.xml # Scripts OTHER_FILES += resources/scripts/address_scrambler.pl @@ -63,6 +65,10 @@ 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/test_ecc.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 @@ -70,6 +76,7 @@ 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/fifo_ecc.xml +OTHER_FILES += resources/configs/mcconfigs/sms.xml # Memspecs OTHER_FILES += resources/configs/memspecs/memspec.dtd diff --git a/DRAMSys/simulator/resources/scripts/memoryHog.pl b/DRAMSys/simulator/resources/scripts/memoryHog.pl new file mode 100644 index 00000000..29e68597 --- /dev/null +++ b/DRAMSys/simulator/resources/scripts/memoryHog.pl @@ -0,0 +1,21 @@ +#!/usr/bin/perl -w +use warnings; +use strict; + +open(LINEAR, "> ../traces/linear.stl"); +open(RANDOM, "> ../traces/random.stl"); + +my $length = shift || die ("please give length of traces"); +my $size = 0x40; + +for(my $i=0; $i < $length; $i++) +{ + my $r = int(rand($length)); + #print $r." ".($size*$r)."\n"; + print LINEAR "$i: read ".sprintf("0x%x",($size*$i))."\n"; + print RANDOM "$i: read ".sprintf("0x%x",($size*$r))."\n"; +} + + +close(LINEAR); +close(RANDOM); 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 c77fe1f6..6cb0ffb9 100644 --- a/DRAMSys/simulator/src/controller/core/configuration/Configuration.cpp +++ b/DRAMSys/simulator/src/controller/core/configuration/Configuration.cpp @@ -153,6 +153,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 6823e590..082d7530 100644 --- a/DRAMSys/simulator/src/controller/core/configuration/Configuration.h +++ b/DRAMSys/simulator/src/controller/core/configuration/Configuration.h @@ -66,6 +66,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 a9053f94..5b022ca6 100644 --- a/DRAMSys/simulator/src/controller/scheduler/Fr_Fcfs.cpp +++ b/DRAMSys/simulator/src/controller/scheduler/Fr_Fcfs.cpp @@ -42,20 +42,43 @@ using namespace std; - +// The FR_FCFS is descibed in a 2000 paper from Rixner et al.: +// Memory Access Scheduling +// +// The FR_FCFS scheduler features for each bank in the DRAM a specific +// scheduling buffer for example: +// +// Bank0: OOOOOOOO +// Bank1: OOXXXXXX +// ... ^ ^ +// ... | | +// ... back | +// ... front +// ... +// Bank6: OOOOO0XX +// Bank7: XXXXXXXX void FR_FCFS::schedule(gp *payload) { - buffer[DramExtension::getExtension(payload).getBank()].emplace_back(payload); + + // FIXME: Question: what if the buffer is full? IMHO the schedule function + // should provide a true or false when the placement into the buffer worked + // out or not (?). + buffer[DramExtension::getExtension(payload).getBank()] + .emplace_back(payload); } std::pair FR_FCFS::getNextRequest(Bank bank) { + // If the bank is empty like Bank0 in the example we do nothing if(buffer[bank].empty()) { return pair(Command::NOP, NULL); } + // In FR_FCFS row hits have always the highest priority, therefore we search + // for row hits. If we find a row hit, we remove the transaction from the + // queue and send it to the DRAM. deque::iterator it = FindRowHit(bank); if(it != buffer[bank].end()) { @@ -64,9 +87,19 @@ std::pair FR_FCFS::getNextRequest(Bank bank) return pair(getReadWriteCommand(*payload), payload); } - return pair(getNextCommand(buffer[bank].front()), buffer[bank].front()); + // If there is no row hit, the FR_FCFS takes always the oldest transaction + // in the buffer, i.e. the transaction in the front. + return pair(getNextCommand(buffer[bank].front()), + buffer[bank].front()); } +// This function searches for a row hit in the scheduling queue of the specific +// bank. If no row hit is found the end of the queue is returned. +// +// Note: end() Returns an iterator referring to the past-the-end element in the +// deque container. The past-the-end element is the theoretical element that +// would follow the last element in the deque container. It does not point to +// any element, and thus shall not be dereferenced. deque::iterator FR_FCFS::FindRowHit(Bank bank) { deque &queue = buffer[bank]; @@ -74,14 +107,22 @@ deque::iterator FR_FCFS::FindRowHit(Bank bank) if(!controllerCore.getRowBufferStates().rowBufferIsOpen(bank)) return queue.end(); + // Traverse the scheduling queue of the specific bank: for(auto it = queue.begin(); it!=queue.end(); it++) { gp* payload = *it; - //Found row-hit - if(DramExtension::getRow(payload) == controllerCore.getRowBufferStates().getRowInRowBuffer(bank)) + //Found row-hit and return the according iterator + if(DramExtension::getRow(payload) + == controllerCore.getRowBufferStates().getRowInRowBuffer(bank)) { return it; } } + 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/DRAMSys.cpp b/DRAMSys/simulator/src/simulation/DRAMSys.cpp index ac75db5b..4378b721 100644 --- a/DRAMSys/simulator/src/simulation/DRAMSys.cpp +++ b/DRAMSys/simulator/src/simulation/DRAMSys.cpp @@ -277,11 +277,6 @@ DRAMSys::~DRAMSys() delete arbiter; - for (auto controller : controllers) - { - delete controller; - } - for (auto dram : drams) { delete dram; @@ -296,6 +291,11 @@ DRAMSys::~DRAMSys() { delete tlmChecker; } + + for (auto controller : controllers) + { + delete controller; + } } void DRAMSys::report(string message) diff --git a/DRAMSys/simulator/src/simulation/Dram.h b/DRAMSys/simulator/src/simulation/Dram.h index a1156096..61d5f941 100644 --- a/DRAMSys/simulator/src/simulation/Dram.h +++ b/DRAMSys/simulator/src/simulation/Dram.h @@ -94,6 +94,8 @@ struct Dram : sc_module { // Adjust number of bytes per burst dynamically to the selected ecc controller bytesPerBurst = Configuration::getInstance().adjustNumBytesAfterECC(bytesPerBurst); + dramController = NULL; + tlmRecorder = NULL; std::uint64_t memorySize = Configuration::getInstance().getSimMemSizeInBytes(); // allocate and model storage of one DRAM channel using memory map 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; diff --git a/DRAMSys/simulator/src/simulation/main.cpp b/DRAMSys/simulator/src/simulation/main.cpp index 18e00f77..60246caf 100644 --- a/DRAMSys/simulator/src/simulation/main.cpp +++ b/DRAMSys/simulator/src/simulation/main.cpp @@ -78,15 +78,15 @@ int sc_main(int argc, char **argv) std::vector players; // Instantiate DRAMSys: - DRAMSys dramSys("DRAMSys", SimulationXML, resources); + DRAMSys *dramSys = new DRAMSys("DRAMSys", SimulationXML, resources); // Instantiate STL Players: - traceSetup(SimulationXML, resources, &players); + traceSetup *ts = new traceSetup(SimulationXML, resources, &players); // Bind STL Players with DRAMSys: for(auto& p : players) { - p->iSocket.bind(dramSys.tSocket); + p->iSocket.bind(dramSys->tSocket); } // Store the starting of the simulation in wallclock time: @@ -105,5 +105,8 @@ int sc_main(int argc, char **argv) double elapsed_secs = double(clock() - simStartTime) / CLOCKS_PER_SEC; cout << "Simulation took " + to_string(elapsed_secs) + " seconds" << endl; + delete dramSys; + delete ts; + return 0; }