Merge branch 'master' into master

This commit is contained in:
fzeder
2017-06-22 13:32:19 +02:00
committed by GitHub Enterprise
30 changed files with 673 additions and 37 deletions

View File

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

View File

@@ -38,6 +38,7 @@
#ifndef TIMESPAN_H
#define TIMESPAN_H
#include <QString>
#include <cstdlib>
#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;}

View File

@@ -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

View File

@@ -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 \

View File

@@ -0,0 +1,16 @@
<mcconfig>
<BankwiseLogic value="0"/>
<OpenPagePolicy value="1" />
<MaxNrOfTransactions value="20" />
<Scheduler value="SMS" />
<SJFProbability value="50" />
<RequestBufferSize value = "10" />
<PowerDownMode value="NoPowerDown" /> <!-- 4 Modes: NoPowerDown, Staggered, TimeoutPDN, TimeoutSREF -->
<PowerDownTimeout value="100" />
<!-- Error Modelling -->
<ErrorChipSeed value="42" />
<ErrorCSVFile value="../../DRAMSys/simulator/src/error/error.csv" />
<!-- Modes: NoStorage, Store (store data without errormodel), ErrorModel (store data with errormodel) -->
<StoreMode value="NoStorage" />
<ControllerCoreDisableRefresh value="0"/>
</mcconfig>

View File

@@ -0,0 +1,14 @@
<simconfig>
<SimulationName value="sms" />
<Debug value="0" />
<DatabaseRecording value="1" />
<PowerAnalysis value="1" />
<EnableWindowing value = "1" />
<WindowSize value="1000" />
<ThermalSimulation value="0"/>
<SimulationProgressBar value="1"/>
<NumberOfMemChannels value="4"/>
<NumberOfDevicesOnDIMM value = "1" />
<CheckTLM2Protocol value = "0" />
</simconfig>

View File

@@ -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

View File

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

View File

@@ -0,0 +1,26 @@
<simulation>
<!-- General Simulator Configuration (used for all simulation setups) -->
<simconfig src="sms.xml" />
<!-- Temperature Simulator Configuration (used for all simulation setups) -->
<thermalconfig src="config.xml" />
<memspec src="wideio.xml"></memspec>
<addressmapping src="am_wideio.xml"></addressmapping>
<mcconfig src="sms.xml"/>
<tracesetup id="sms">
<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>
</tracesetup>
</simulation>

View File

@@ -343,7 +343,7 @@ void tlm2_base_protocol_checker<BUSWIDTH>::
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;

View File

@@ -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<Command, tlm::tlm_generic_payload*> 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<Bank> 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)

View File

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

View File

@@ -55,7 +55,7 @@ class ControllerCore : public sc_module
{
public:
ControllerCore(sc_module_name /*name*/, IController& controller, std::map<Bank, int>& numberOfPayloads);
virtual ~ControllerCore() ;
virtual ~ControllerCore();
void scheduleRequest(Command command, tlm::tlm_generic_payload& payload);
void triggerRefresh(tlm::tlm_generic_payload& payload);

View File

@@ -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")

View File

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

View File

@@ -60,4 +60,9 @@ pair<Command, tlm::tlm_generic_payload*> Fifo::getNextRequest(Bank bank)
return pair<Command, tlm::tlm_generic_payload*>(Command::NOP, NULL);
}
gp* Fifo::getPendingRequest(Bank bank)
{
return NULL;
}

View File

@@ -52,6 +52,7 @@ public:
void schedule(gp* payload) override;
std::pair<Command, tlm::tlm_generic_payload*> getNextRequest(Bank bank) override;
virtual gp* getPendingRequest(Bank bank) override;
private:
std::map<Bank, std::deque<gp*>> buffer;

View File

@@ -128,3 +128,7 @@ std::pair<Command, tlm::tlm_generic_payload *> FifoStrict::getNextRequest(Bank b
return pair<Command, tlm::tlm_generic_payload*>(Command::NOP, NULL);
}
gp* FifoStrict::getPendingRequest(Bank bank)
{
return NULL;
}

View File

@@ -56,6 +56,7 @@ public:
void schedule(gp* payload) override;
std::pair<Command, tlm::tlm_generic_payload*> getNextRequest(Bank bank) override;
virtual gp* getPendingRequest(Bank bank) override;
private:
std::deque<std::pair<Bank, tlm::tlm_generic_payload *>> buffer;

View File

@@ -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<Command, gp*> 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, tlm::tlm_generic_payload*>(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<gp*>::iterator it = FindRowHit(bank);
if(it != buffer[bank].end())
{
@@ -64,9 +87,19 @@ std::pair<Command, gp*> FR_FCFS::getNextRequest(Bank bank)
return pair<Command, gp*>(getReadWriteCommand(*payload), payload);
}
return pair<Command, gp*>(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<Command, gp*>(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<gp*>::iterator FR_FCFS::FindRowHit(Bank bank)
{
deque<gp*> &queue = buffer[bank];
@@ -74,14 +107,22 @@ deque<gp*>::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;
}

View File

@@ -53,6 +53,7 @@ public:
void schedule(gp* payload) override;
std::pair<Command, tlm::tlm_generic_payload*> getNextRequest(Bank bank) override;
virtual gp* getPendingRequest(Bank bank) override;
private:
std::map<Bank, std::deque<gp*>> buffer;

View File

@@ -54,6 +54,7 @@ public:
virtual void schedule(gp* payload) = 0;
virtual std::pair<Command, gp*> getNextRequest(Bank bank) = 0;
virtual gp* getPendingRequest(Bank bank) = 0;
static std::string sendername;
protected:

View File

@@ -0,0 +1,357 @@
#include "SMS.h"
#include <random>
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<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)
{
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);
}
}
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<Thread> 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<gp*>::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<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())
{
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<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))) {
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<Thread, std::deque<gp*>> &requestBuffer,
std::deque<gp*>::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<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);
}
}
gp* SMS::getPendingRequest(Bank bank)
{
for (auto& requestBuffer : requestBuffers) {
for (auto& request : requestBuffer.second) {
if (DramExtension::getBank(request) == bank) {
return request;
}
}
}
return NULL;
}

View File

@@ -0,0 +1,84 @@
#ifndef SMS_H
#define SMS_H
#include <stdlib.h>
#include <time.h>
#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<gp*>::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<Command, gp*> getNextRequest(Bank bank) override;
virtual gp* getPendingRequest(Bank bank) override;
void batchScheduler();
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, 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;
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 pickSJF();
bool pickRR();
void drain(sc_time memClk, std::deque<gp*>::iterator last);
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 isRequestBuffersEmpty();
bool existReadyBatches();
};
#endif // SMS_H

View File

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

View File

@@ -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

View File

@@ -43,6 +43,7 @@ class TracePlayerListener
public:
virtual void tracePlayerTerminates() = 0;
virtual void transactionFinished() = 0;
virtual ~TracePlayerListener(){};
};
#endif // TRACEPLAYERLISTENER_H

View File

@@ -96,8 +96,6 @@ traceSetup::traceSetup(std::string uri,
NumberOfTracePlayers = devices->size();
}
void traceSetup::tracePlayerTerminates()
{
finishedTracePlayers++;

View File

@@ -53,6 +53,7 @@ public:
virtual void tracePlayerTerminates() override;
virtual void transactionFinished() override;
virtual ~traceSetup(){};
private:
unsigned int NumberOfTracePlayers;

View File

@@ -78,15 +78,15 @@ int sc_main(int argc, char **argv)
std::vector<StlPlayer*> 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;
}