RecordableController and RecordableDram

This commit is contained in:
Éder F. Zulian
2018-07-05 11:39:04 +02:00
parent 5c6df18a4f
commit 9b237be228
26 changed files with 487 additions and 349 deletions

View File

@@ -123,6 +123,7 @@ SOURCES += \
src/error/ecchamming.cpp \
src/controller/scheduler/Fr_Fcfs_read_priority.cpp \
src/controller/scheduler/Fr_Fcfs_grouper.cpp \
src/controller/RecordableController.cpp \
src/common/AddressDecoder.cpp \
src/common/jsonAddressDecoder.cpp
@@ -201,6 +202,8 @@ HEADERS += \
src/controller/scheduler/Fr_Fcfs_grouper.h \
src/simulation/IArbiter.h \
src/simulation/SimpleArbiter.h \
src/controller/RecordableController.h \
src/simulation/RecordableDram.h \
src/common/AddressDecoder.h \
src/common/jsonAddressDecoder.h
#src/common/third_party/json/include/nlohmann/json.hpp \

View File

@@ -48,90 +48,90 @@
using namespace std;
TlmRecorder::TlmRecorder(sc_module_name /*name*/, string uri, string dbname,
bool recenable) : sqlScriptURI(uri), dbName(dbname),
recordingEnabled(recenable), totalNumTransactions(1),
TlmRecorder::TlmRecorder(sc_module_name /*name*/, string uri,
string dbname) : sqlScriptURI(uri), dbName(dbname), totalNumTransactions(1),
simulationTimeCoveredByRecording(SC_ZERO_TIME)
{
if (TlmRecorder::recordingEnabled == true) {
recordedData.reserve(transactionCommitRate);
setUpTransactionTerminatingPhases();
openDB(TlmRecorder::dbName.c_str());
char *sErrMsg;
sqlite3_exec(db, "PRAGMA main.page_size = 4096", NULL, NULL, &sErrMsg);
sqlite3_exec(db, "PRAGMA main.cache_size=10000", NULL, NULL, &sErrMsg);
sqlite3_exec(db, "PRAGMA main.locking_mode=EXCLUSIVE", NULL, NULL, &sErrMsg);
sqlite3_exec(db, "PRAGMA main.synchronous=OFF", NULL, NULL, &sErrMsg);
sqlite3_exec(db, "PRAGMA journal_mode = OFF", NULL, NULL, &sErrMsg);
recordedData.reserve(transactionCommitRate);
setUpTransactionTerminatingPhases();
openDB(TlmRecorder::dbName.c_str());
char *sErrMsg;
sqlite3_exec(db, "PRAGMA main.page_size = 4096", NULL, NULL, &sErrMsg);
sqlite3_exec(db, "PRAGMA main.cache_size=10000", NULL, NULL, &sErrMsg);
sqlite3_exec(db, "PRAGMA main.locking_mode=EXCLUSIVE", NULL, NULL, &sErrMsg);
sqlite3_exec(db, "PRAGMA main.synchronous=OFF", NULL, NULL, &sErrMsg);
sqlite3_exec(db, "PRAGMA journal_mode = OFF", NULL, NULL, &sErrMsg);
createTables(TlmRecorder::sqlScriptURI);
prepareSqlStatements();
createTables(TlmRecorder::sqlScriptURI);
prepareSqlStatements();
printDebugMessage("Starting new database transaction");
}
printDebugMessage("Starting new database transaction");
}
TlmRecorder::~TlmRecorder()
{
if (db)
closeConnection();
sqlite3_finalize(insertTransactionStatement);
sqlite3_finalize(insertRangeStatement);
sqlite3_finalize(updateRangeStatement);
sqlite3_finalize(insertPhaseStatement);
sqlite3_finalize(updatePhaseStatement);
sqlite3_finalize(insertGeneralInfoStatement);
sqlite3_finalize(insertDebugMessageStatement);
sqlite3_finalize(updateDataStrobeStatement);
sqlite3_finalize(insertPowerStatement);
}
void TlmRecorder::recordPower(double timeInSeconds, double averagePower)
{
if (TlmRecorder::recordingEnabled) {
sqlite3_bind_double(insertPowerStatement, 1, timeInSeconds);
sqlite3_bind_double(insertPowerStatement, 2, averagePower);
executeSqlStatement(insertPowerStatement);
}
sqlite3_bind_double(insertPowerStatement, 1, timeInSeconds);
sqlite3_bind_double(insertPowerStatement, 2, averagePower);
executeSqlStatement(insertPowerStatement);
}
void TlmRecorder::recordPhase(tlm::tlm_generic_payload &trans,
tlm::tlm_phase phase, sc_time time)
{
if (TlmRecorder::recordingEnabled) {
if (currentTransactionsInSystem.count(&trans) == 0)
introduceTransactionSystem(trans);
if (currentTransactionsInSystem.count(&trans) == 0)
introduceTransactionSystem(trans);
string phaseName = phaseNameToString(phase);
string phaseBeginPrefix = "BEGIN_";
string phaseEndPrefix = "END_";
string phaseName = phaseNameToString(phase);
string phaseBeginPrefix = "BEGIN_";
string phaseEndPrefix = "END_";
if (phaseName.find(phaseBeginPrefix) != string::npos) {
phaseName.erase(0, phaseBeginPrefix.length());
assert(currentTransactionsInSystem.count(&trans) != 0);
currentTransactionsInSystem[&trans].insertPhase(phaseName, time);
} else {
phaseName.erase(0, phaseEndPrefix.length());
assert(currentTransactionsInSystem.count(&trans) != 0);
currentTransactionsInSystem[&trans].setPhaseEnd(phaseName, time);
}
bool phaseTerminatesTransaction = count(transactionTerminatingPhases.begin(),
transactionTerminatingPhases.end(), phase) == 1;
if (phaseTerminatesTransaction)
removeTransactionFromSystem(trans);
simulationTimeCoveredByRecording = time;
if (phaseName.find(phaseBeginPrefix) != string::npos) {
phaseName.erase(0, phaseBeginPrefix.length());
assert(currentTransactionsInSystem.count(&trans) != 0);
currentTransactionsInSystem[&trans].insertPhase(phaseName, time);
} else {
phaseName.erase(0, phaseEndPrefix.length());
assert(currentTransactionsInSystem.count(&trans) != 0);
currentTransactionsInSystem[&trans].setPhaseEnd(phaseName, time);
}
bool phaseTerminatesTransaction = count(transactionTerminatingPhases.begin(),
transactionTerminatingPhases.end(), phase) == 1;
if (phaseTerminatesTransaction)
removeTransactionFromSystem(trans);
simulationTimeCoveredByRecording = time;
}
void TlmRecorder::updateDataStrobe(const sc_time &begin, const sc_time &end,
tlm::tlm_generic_payload &trans)
{
if (TlmRecorder::recordingEnabled) {
assert(currentTransactionsInSystem.count(&trans) != 0);
currentTransactionsInSystem[&trans].timeOnDataStrobe.start = begin;
currentTransactionsInSystem[&trans].timeOnDataStrobe.end = end;
}
assert(currentTransactionsInSystem.count(&trans) != 0);
currentTransactionsInSystem[&trans].timeOnDataStrobe.start = begin;
currentTransactionsInSystem[&trans].timeOnDataStrobe.end = end;
}
void TlmRecorder::recordDebugMessage(std::string message, sc_time time)
{
if (TlmRecorder::recordingEnabled)
insertDebugMessageInDB(message, time);
insertDebugMessageInDB(message, time);
}
@@ -434,24 +434,13 @@ void TlmRecorder::printDebugMessage(std::string message)
void TlmRecorder::closeConnection()
{
if (TlmRecorder::recordingEnabled) {
commitRecordedDataToDB();
insertGeneralInfo();
printDebugMessage(
"Number of transactions written to DB: " + std::to_string(
totalNumTransactions - 1));
printDebugMessage("tlmPhaseRecorder:\tEnd Recording");
sqlite3_finalize(insertTransactionStatement);
sqlite3_finalize(insertRangeStatement);
sqlite3_finalize(updateRangeStatement);
sqlite3_finalize(insertPhaseStatement);
sqlite3_finalize(updatePhaseStatement);
sqlite3_finalize(insertGeneralInfoStatement);
sqlite3_finalize(insertDebugMessageStatement);
sqlite3_finalize(updateDataStrobeStatement);
sqlite3_finalize(insertPowerStatement);
sqlite3_close(db);
db = NULL;
}
commitRecordedDataToDB();
insertGeneralInfo();
printDebugMessage(
"Number of transactions written to DB: " + std::to_string(
totalNumTransactions - 1));
printDebugMessage("tlmPhaseRecorder:\tEnd Recording");
sqlite3_close(db);
db = NULL;
}

View File

@@ -60,9 +60,8 @@ class TlmRecorder : public sc_module
public:
std::string sqlScriptURI;
std::string dbName;
bool recordingEnabled;
TlmRecorder(sc_module_name /*name*/, string uri, string dbname, bool recenable);
TlmRecorder(sc_module_name /*name*/, string uri, string dbname);
~TlmRecorder();
void recordMCconfig(string mcconfig)

View File

@@ -75,114 +75,83 @@ void Controller::send(const ScheduledCommand &command,
tlm_generic_payload &payload)
{
sc_assert(command.getStart() >= sc_time_stamp());
TimeInterval dataStrobe;
tlm_phase phase;
switch (command.getCommand()) {
//TODO: refactor tlm recorder
case Command::Read:
dataStrobe = command.getIntervalOnDataStrobe();
tlmRecorder->updateDataStrobe(dataStrobe.start, dataStrobe.end, payload);
controllerCorePEQ.notify(payload, BEGIN_RD,
command.getStart() - sc_time_stamp());
phase = BEGIN_RD;
break;
case Command::ReadA:
dataStrobe = command.getIntervalOnDataStrobe();
tlmRecorder->updateDataStrobe(dataStrobe.start, dataStrobe.end, payload);
controllerCorePEQ.notify(payload, BEGIN_RDA,
command.getStart() - sc_time_stamp());
phase = BEGIN_RDA;
break;
case Command::Write:
dataStrobe = command.getIntervalOnDataStrobe();
tlmRecorder->updateDataStrobe(dataStrobe.start, dataStrobe.end, payload);
controllerCorePEQ.notify(payload, BEGIN_WR,
command.getStart() - sc_time_stamp());
phase = BEGIN_WR;
break;
case Command::WriteA:
dataStrobe = command.getIntervalOnDataStrobe();
tlmRecorder->updateDataStrobe(dataStrobe.start, dataStrobe.end, payload);
controllerCorePEQ.notify(payload, BEGIN_WRA,
command.getStart() - sc_time_stamp());
phase = BEGIN_WRA;
break;
case Command::AutoRefresh:
if (!Configuration::getInstance().BankwiseLogic) {
controllerCorePEQ.notify(payload, BEGIN_REFA,
command.getStart() - sc_time_stamp());
phase = BEGIN_REFA;
} else
controllerCorePEQ.notify(payload, BEGIN_REFB,
command.getStart() - sc_time_stamp());
break;
case Command::ActB:
controllerCorePEQ.notify(payload, BEGIN_ACTB,
command.getStart() - sc_time_stamp());
phase = BEGIN_REFB;
break;
case Command::Activate:
controllerCorePEQ.notify(payload, BEGIN_ACT,
command.getStart() - sc_time_stamp());
break;
case Command::PreB:
controllerCorePEQ.notify(payload, BEGIN_PREB,
command.getStart() - sc_time_stamp());
phase = BEGIN_ACT;
break;
case Command::Precharge:
controllerCorePEQ.notify(payload, BEGIN_PRE,
command.getStart() - sc_time_stamp());
phase = BEGIN_PRE;
break;
case Command::PrechargeAll:
controllerCorePEQ.notify(payload, BEGIN_PRE_ALL,
command.getStart() - sc_time_stamp());
phase = BEGIN_PRE_ALL;
break;
case Command::PDNA:
if (!Configuration::getInstance().BankwiseLogic) {
controllerCorePEQ.notify(payload, BEGIN_PDNA,
command.getStart() - sc_time_stamp());
phase = BEGIN_PDNA;
} else
controllerCorePEQ.notify(payload, BEGIN_PDNAB,
command.getStart() - sc_time_stamp());
phase = BEGIN_PDNAB;
break;
case Command::PDNAX:
if (!Configuration::getInstance().BankwiseLogic) {
controllerCorePEQ.notify(payload, END_PDNA,
command.getStart() - sc_time_stamp());
phase = END_PDNA;
} else
controllerCorePEQ.notify(payload, END_PDNAB,
command.getStart() - sc_time_stamp());
phase = END_PDNAB;
break;
case Command::PDNP:
if (!Configuration::getInstance().BankwiseLogic) {
controllerCorePEQ.notify(payload, BEGIN_PDNP,
command.getStart() - sc_time_stamp());
phase = BEGIN_PDNP;
} else
controllerCorePEQ.notify(payload, BEGIN_PDNPB,
command.getStart() - sc_time_stamp());
phase = BEGIN_PDNPB;
break;
case Command::PDNPX:
if (!Configuration::getInstance().BankwiseLogic) {
controllerCorePEQ.notify(payload, END_PDNP,
command.getStart() - sc_time_stamp());
phase = END_PDNP;
} else
controllerCorePEQ.notify(payload, END_PDNPB,
command.getStart() - sc_time_stamp());
phase = END_PDNPB;
break;
case Command::SREF:
if (!Configuration::getInstance().BankwiseLogic) {
controllerCorePEQ.notify(payload, BEGIN_SREF,
command.getStart() - sc_time_stamp());
phase = BEGIN_SREF;
} else
controllerCorePEQ.notify(payload, BEGIN_SREFB,
command.getStart() - sc_time_stamp());
phase = BEGIN_SREFB;
break;
case Command::SREFX:
if (!Configuration::getInstance().BankwiseLogic) {
controllerCorePEQ.notify(payload, END_SREF,
command.getStart() - sc_time_stamp());
phase = END_SREF;
} else
controllerCorePEQ.notify(payload, END_SREFB,
command.getStart() - sc_time_stamp());
phase = END_SREFB;
break;
default:
SC_REPORT_FATAL(0, "unsupported command was sent by controller");
break;
}
sc_time notDelay = command.getStart() - sc_time_stamp();
printDebugMessage(phaseNameToString(phase) + " notification in " +
notDelay.to_string());
controllerCorePEQ.notify(payload, phase, notDelay);
}
//Trigger the next planned refresh or the power down mode on the DRAM
@@ -191,14 +160,20 @@ void Controller::send(Trigger trigger, sc_time time,
{
sc_assert(time >= sc_time_stamp());
sc_time delay = time - sc_time_stamp();
tlm_phase phase;
if (trigger == Trigger::REFTrigger) {
controllerCorePEQ.notify(payload, REF_TRIGGER, delay);
phase = REF_TRIGGER;
} else if (trigger == Trigger::PDNTrigger) {
controllerCorePEQ.notify(payload, PDN_TRIGGER, delay);
phase = PDN_TRIGGER;
} else {
SC_REPORT_FATAL("controller wrapper", "unknown trigger");
}
sc_time delay = time - sc_time_stamp();
printDebugMessage(phaseNameToString(phase) + " notification in " +
delay.to_string());
controllerCorePEQ.notify(payload, phase, delay);
}
void Controller::controllerCorePEQCallback(tlm_generic_payload &payload,
@@ -237,63 +212,33 @@ void Controller::controllerCorePEQCallback(tlm_generic_payload &payload,
}
else
SC_REPORT_FATAL(0,
"refreshTriggerPEQCallback queue in controller wrapper was triggered with unsupported phase");
"Controller Core PEQ in controller wrapper was triggered with unsupported phase");
}
}
tlm_sync_enum Controller::nb_transport_fw(tlm_generic_payload &payload,
tlm_phase &phase, sc_time &fwDelay)
{
sc_time recTime;
sc_time notDelay;
unsigned int thr = DramExtension::getExtension(payload).getThread().ID();
unsigned int ch = DramExtension::getExtension(payload).getChannel().ID();
unsigned int bg = DramExtension::getExtension(payload).getBankGroup().ID();
unsigned int bank = DramExtension::getExtension(payload).getBank().ID();
unsigned int row = DramExtension::getExtension(payload).getRow().ID();
unsigned int col = DramExtension::getExtension(payload).getColumn().ID();
sc_time notDelay = fwDelay;
if (phase == BEGIN_REQ) {
recTime = fwDelay + sc_time_stamp();
notDelay = clkAlign(sc_time_stamp() + fwDelay) - (sc_time_stamp() + fwDelay) +
Configuration::getInstance().memSpec.clk;
printDebugMessage("[fw] Recording " + phaseNameToString(
phase) + " thread " + to_string(thr) + " channel " + to_string(
ch) + " bank group " + to_string(bg) + " bank " + to_string(
bank) + " row " + to_string(row) + " column " + to_string(
col) + " at " + recTime.to_string() + " notification in " +
notDelay.to_string());
tlmRecorder->recordPhase(payload, phase, recTime);
frontendPEQ.notify(payload, phase, notDelay);
notDelay += Configuration::getInstance().memSpec.clk;
//Bandwidth IDLE
if ((getTotalNumberOfPayloadsInSystem() == 0) && idleState) {
endBandwidthIdleCollector();
}
} else if (phase == END_RESP) {
recTime = fwDelay + sc_time_stamp() + Configuration::getInstance().memSpec.clk;
notDelay = clkAlign(sc_time_stamp() + fwDelay) - (sc_time_stamp() + fwDelay);
printDebugMessage("[fw] Recording " + phaseNameToString(
phase) + " thread " + to_string(thr) + " channel " + to_string(
ch) + " bank group " + to_string(bg) + " bank " + to_string(
bank) + " row " + to_string(row) + " column " + to_string(
col) + " at " + recTime.to_string() + " notification in " +
notDelay.to_string());
// Badnwith IDLE
if (getTotalNumberOfPayloadsInSystem() == 1) {
startBandwidthIdleCollector();
}
tlmRecorder->recordPhase(payload, phase, recTime);
frontendPEQ.notify(payload, phase, notDelay);
}
printDebugMessage("[fw] " + phaseNameToString(phase) + " notification in " +
notDelay.to_string());
frontendPEQ.notify(payload, phase, notDelay);
return TLM_ACCEPTED;
}
@@ -319,7 +264,7 @@ void Controller::frontendPEQCallback(tlm_generic_payload &payload,
payload.set_response_status(tlm::TLM_OK_RESPONSE);
sendToFrontend(payload, END_REQ, SC_ZERO_TIME);
scheduler->schedule(&payload);
scheduler->storeRequest(&payload);
scheduleNextFromScheduler(DramExtension::getExtension(payload).getBank());
} else if (phase == PendingRequest) {
// Schedule a pending request.
@@ -330,7 +275,7 @@ void Controller::frontendPEQCallback(tlm_generic_payload &payload,
backpressure->set_response_status(tlm::TLM_OK_RESPONSE);
sendToFrontend(*backpressure, END_REQ, SC_ZERO_TIME);
scheduler->schedule(backpressure);
scheduler->storeRequest(backpressure);
scheduleNextFromScheduler(DramExtension::getExtension(backpressure).getBank());
backpressure = NULL;
}
@@ -339,7 +284,7 @@ void Controller::frontendPEQCallback(tlm_generic_payload &payload,
payload.release();
} else {
SC_REPORT_FATAL(0,
"Frontend PEQ event queue in controller wrapper was triggered with unknown phase");
"Front-end PEQ in controller wrapper was triggered with unknown phase");
}
}
@@ -381,7 +326,6 @@ unsigned int Controller::getTotalNumberOfPayloadsInSystem()
void Controller::scheduleNextFromScheduler(Bank bank)
{
if (controllerCore->bankIsBusy(bank)) {
return;
}
@@ -390,11 +334,7 @@ void Controller::scheduleNextFromScheduler(Bank bank)
pair<Command, tlm::tlm_generic_payload *> nextRequest =
scheduler->getNextRequest(bank);
if (nextRequest.second != NULL) {
controllerCore->powerDownManager->wakeUp(DramExtension::getExtension(
nextRequest.second).getBank(), sc_time_stamp());
controllerCore->scheduleRequest(nextRequest.first, *nextRequest.second);
printDebugMessage("\t-> Next payload was scheduled by core [" + commandToString(
nextRequest.first) + "]");
schedule(nextRequest.first, *nextRequest.second);
} else {
gp *pendingRequest = scheduler->getPendingRequest(bank);
if (pendingRequest != NULL) {
@@ -412,11 +352,7 @@ void Controller::scheduleNextFromScheduler(Bank bank)
pair<Command, tlm::tlm_generic_payload *> nextRequest =
scheduler->getNextRequest(bank);
if (nextRequest.second != NULL) {
controllerCore->powerDownManager->wakeUp(DramExtension::getExtension(
nextRequest.second).getBank(), sc_time_stamp());
controllerCore->scheduleRequest(nextRequest.first, *nextRequest.second);
printDebugMessage("\t-> Next payload was scheduled by core [" + commandToString(
nextRequest.first) + "] (unblocked)");
schedule(nextRequest.first, *nextRequest.second);
} else {
gp *pendingRequest = scheduler->getPendingRequest(bank);
if (pendingRequest != NULL) {
@@ -433,6 +369,16 @@ void Controller::scheduleNextFromScheduler(Bank bank)
blockedRequests = blocked;
}
void Controller::schedule(Command command, gp &payload)
{
controllerCore->powerDownManager->wakeUp(DramExtension::getBank(payload),
sc_time_stamp());
if (controllerCore->scheduleRequest(command, payload)) {
printDebugMessage("\t-> Next payload was scheduled by core [" + commandToString(
command) + "] (unblocked)");
}
}
void Controller::sendToFrontend(tlm_generic_payload &payload,
const tlm_phase &phase, const sc_time &delay)
{
@@ -444,26 +390,9 @@ void Controller::sendToFrontend(tlm_generic_payload &payload,
tlm_sync_enum Controller::nb_transport_bw(tlm_generic_payload &payload,
tlm_phase &phase, sc_time &bwDelay)
{
sc_time recTime = bwDelay + sc_time_stamp();
sc_time notDelay = bwDelay;
unsigned int thr = DramExtension::getExtension(payload).getThread().ID();
unsigned int ch = DramExtension::getExtension(payload).getChannel().ID();
unsigned int bg = DramExtension::getExtension(payload).getBankGroup().ID();
unsigned int bank = DramExtension::getExtension(payload).getBank().ID();
unsigned int row = DramExtension::getExtension(payload).getRow().ID();
unsigned int col = DramExtension::getExtension(payload).getColumn().ID();
printDebugMessage("[bw] Recording " + phaseNameToString(
phase) + " thread " + to_string(thr) + " channel " + to_string(
ch) + " bank group " + to_string(bg) + " bank " + to_string(
bank) + " row " + to_string(row) + " column " + to_string(
col) + " at " + recTime.to_string() + " notification in " +
notDelay.to_string());
dramPEQ.notify(payload, phase, notDelay);
tlmRecorder->recordPhase(payload, phase, recTime);
printDebugMessage("[bw] " + phaseNameToString(phase) + " notification in " +
bwDelay.to_string());
dramPEQ.notify(payload, phase, bwDelay);
return TLM_ACCEPTED;
}
@@ -510,7 +439,7 @@ void Controller::dramPEQCallback(tlm_generic_payload &payload,
// scheduler implementation)
} else {
string str =
string("dramPEQCallback queue in controller wrapper was triggered with unsupported phase ")
string("DRAM PEQ in controller wrapper was triggered with unsupported phase ")
+ phaseNameToString(phase);
SC_REPORT_FATAL(0, str.c_str());
}

View File

@@ -80,11 +80,11 @@ DECLARE_EXTENDED_PHASE(PendingRequest);
class Controller: public sc_module, public IController
{
public:
Controller(sc_module_name /*name*/, TlmRecorder *rec) :
Controller(sc_module_name /*name*/) :
frontendPEQ(this, &Controller::frontendPEQCallback), dramPEQ(this,
&Controller::dramPEQCallback), controllerCorePEQ(this,
&Controller::controllerCorePEQCallback),
debugManager(DebugManager::getInstance()), tlmRecorder(rec)
debugManager(DebugManager::getInstance())
{
controllerCore = new ControllerCore("core", *this, numberOfPayloadsInSystem);
buildScheduler();
@@ -121,27 +121,28 @@ public:
return controllerThreadId;
}
private:
protected:
void buildScheduler();
void payloadEntersSystem(tlm_generic_payload &payload);
void payloadLeavesSystem(tlm_generic_payload &payload);
// --- FRONTEND ------
tlm_sync_enum nb_transport_fw(tlm_generic_payload &payload, tlm_phase &phase,
sc_time &fwDelay);
virtual tlm_sync_enum nb_transport_fw(tlm_generic_payload &payload,
tlm_phase &phase, sc_time &fwDelay);
virtual unsigned int transport_dbg(tlm::tlm_generic_payload &trans);
void frontendPEQCallback(tlm_generic_payload &payload, const tlm_phase &phase);
void sendToFrontend(tlm_generic_payload &payload, const tlm_phase &phase,
const sc_time &delay);
virtual void sendToFrontend(tlm_generic_payload &payload,
const tlm_phase &phase, const sc_time &delay);
// --- DRAM ------
tlm_sync_enum nb_transport_bw(tlm_generic_payload &payload, tlm_phase &phase,
sc_time &bwDelay);
virtual tlm_sync_enum nb_transport_bw(tlm_generic_payload &payload,
tlm_phase &phase, sc_time &bwDelay);
void dramPEQCallback(tlm_generic_payload &payload, const tlm_phase &phase);
void sendToDram(tlm_generic_payload &payload, const tlm_phase &phase,
const sc_time &delay);
// ------- CONTROLLER CORE ---------
virtual void schedule(Command command, gp &payload);
void controllerCorePEQCallback(tlm_generic_payload &payload,
const tlm_phase &phase);
@@ -161,7 +162,6 @@ private:
tlm_utils::peq_with_cb_and_phase<Controller> controllerCorePEQ;
DebugManager &debugManager;
TlmRecorder *tlmRecorder;
// Bandwidth realted:
sc_time idleStart;

View File

@@ -0,0 +1,92 @@
/*
* Copyright (c) 2018, University of Kaiserslautern
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* 3. Neither the name of the copyright holder nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER
* OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* Authors:
* Felipe S. Prado
* Matthias Jung
*/
#include "RecordableController.h"
tlm_sync_enum RecordableController::nb_transport_fw(tlm_generic_payload
&payload, tlm_phase &phase, sc_time &fwDelay)
{
recordPhase(payload, phase, fwDelay);
return Controller::nb_transport_fw(payload, phase, fwDelay);
}
void RecordableController::sendToFrontend(tlm_generic_payload &payload,
const tlm_phase &phase, const sc_time &delay)
{
recordPhase(payload, phase, delay);
Controller::sendToFrontend(payload, phase, delay);
}
tlm_sync_enum RecordableController::nb_transport_bw(tlm_generic_payload
&payload, tlm_phase &phase, sc_time &bwDelay)
{
recordPhase(payload, phase, bwDelay);
return Controller::nb_transport_bw(payload, phase, bwDelay);
}
void RecordableController::recordPhase(tlm::tlm_generic_payload &trans,
tlm::tlm_phase phase, sc_time delay)
{
sc_time recTime = delay + sc_time_stamp();
unsigned int thr = DramExtension::getExtension(trans).getThread().ID();
unsigned int ch = DramExtension::getExtension(trans).getChannel().ID();
unsigned int bg = DramExtension::getExtension(trans).getBankGroup().ID();
unsigned int bank = DramExtension::getExtension(trans).getBank().ID();
unsigned int row = DramExtension::getExtension(trans).getRow().ID();
unsigned int col = DramExtension::getExtension(trans).getColumn().ID();
printDebugMessage("Recording " + phaseNameToString(phase) + " thread " +
to_string(thr) + " channel " + to_string(ch) + " bank group " + to_string(
bg) + " bank " + to_string(bank) + " row " + to_string(row) + " column " +
to_string(col) + " at " + recTime.to_string());
tlmRecorder->recordPhase(trans, phase, recTime);
}
void RecordableController::schedule(Command command, gp &payload)
{
Controller::schedule(command, payload);
if (commandIsIn(command, {Command::Read, Command::ReadA, Command::Write, Command::WriteA})) {
ScheduledCommand scheduledCommand = controllerCore->state->getLastCommand(
command, DramExtension::getBank(payload));
TimeInterval dataStrobe = scheduledCommand.getIntervalOnDataStrobe();
tlmRecorder->updateDataStrobe(dataStrobe.start, dataStrobe.end, payload);
}
}

View File

@@ -0,0 +1,64 @@
/*
* Copyright (c) 2018, University of Kaiserslautern
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* 3. Neither the name of the copyright holder nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER
* OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* Authors:
* Felipe S. Prado
* Matthias Jung
*/
#ifndef RECORDABLECONTROLLER_H
#define RECORDABLECONTROLLER_H
#include "Controller.h"
struct RecordableController: public Controller {
public:
RecordableController(sc_module_name name, TlmRecorder *rec) :
Controller(name), tlmRecorder(rec)
{
}
protected:
TlmRecorder *tlmRecorder;
virtual tlm_sync_enum nb_transport_fw(tlm_generic_payload &payload,
tlm_phase &phase, sc_time &fwDelay) override;
virtual tlm_sync_enum nb_transport_bw(tlm_generic_payload &payload,
tlm_phase &phase, sc_time &bwDelay) override;
virtual void sendToFrontend(tlm_generic_payload &payload,
const tlm_phase &phase, const sc_time &delay) override;
virtual void schedule(Command command, tlm_generic_payload &payload) override;
void recordPhase(tlm::tlm_generic_payload &trans, tlm::tlm_phase phase,
sc_time delay);
};
#endif // RECORDABLECONTROLLER_H

View File

@@ -166,7 +166,7 @@ void ControllerCore::triggerRefresh(tlm::tlm_generic_payload &payload)
}
}
void ControllerCore::scheduleRequest(Command command,
bool ControllerCore::scheduleRequest(Command command,
tlm::tlm_generic_payload &payload)
{
sc_time start = clkAlign(sc_time_stamp());
@@ -175,13 +175,16 @@ void ControllerCore::scheduleRequest(Command command,
if (config.ControllerCoreDisableRefresh == true) {
state->change(scheduledCommand);
controller.send(scheduledCommand, payload);
return true;
} else {
if (!((command == Command::Precharge || command == Command::Activate)
&& refreshManager->hasCollision(scheduledCommand))) {
state->change(scheduledCommand);
controller.send(scheduledCommand, payload);
return true;
}
}
return false;
}
ScheduledCommand ControllerCore::schedule(Command command, sc_time start,
@@ -236,7 +239,6 @@ bool ControllerCore::bankIsBusy(Bank bank)
SC_REPORT_FATAL("Core", "Last command unkown");
return false;
}
}
const std::vector<Bank> &ControllerCore::getBanks()

View File

@@ -58,7 +58,7 @@ public:
std::map<Bank, int> &numberOfPayloads);
virtual ~ControllerCore();
void scheduleRequest(Command command, tlm::tlm_generic_payload &payload);
bool scheduleRequest(Command command, tlm::tlm_generic_payload &payload);
void triggerRefresh(tlm::tlm_generic_payload &payload);
const std::vector<Bank> &getBanks();

View File

@@ -172,7 +172,6 @@ void PowerDownManager::sendPowerDownPayload(ScheduledCommand &pdnToSend)
pdnToSend.getCommand()) + " on bank " + to_string(pdnToSend.getBank().ID()) +
" start time " + pdnToSend.getStart().to_string() + " end time " +
pdnToSend.getEnd().to_string());
}
void PowerDownManager::setPowerDownState(PowerDownState state)

View File

@@ -45,7 +45,6 @@ bool ScheduledCommand::isNoCommand() const
&& executionTime == SC_ZERO_TIME && end == SC_ZERO_TIME);
}
bool ScheduledCommand::isValidCommand() const
{
return !isNoCommand();

View File

@@ -62,7 +62,6 @@ public:
{
}
ScheduledCommand() :
command(Command::NOP), start(SC_ZERO_TIME), executionTime(SC_ZERO_TIME),
end(SC_ZERO_TIME), extension()

View File

@@ -38,7 +38,7 @@
using namespace std;
void Fifo::schedule(gp *payload)
void Fifo::storeRequest(gp *payload)
{
buffer[DramExtension::getExtension(payload).getBank()].emplace_back(payload);
}

View File

@@ -50,7 +50,7 @@ public:
Fifo(ControllerCore &controllerCore) : IScheduler(controllerCore) {}
virtual ~Fifo() {}
void schedule(gp *payload) override;
void storeRequest(gp *payload) override;
std::pair<Command, tlm::tlm_generic_payload *> getNextRequest(
Bank bank) override;
virtual gp *getPendingRequest(Bank bank) override;

View File

@@ -38,7 +38,7 @@
#include "FifoStrict.h"
void FifoStrict::schedule(tlm::tlm_generic_payload *payload)
void FifoStrict::storeRequest(tlm::tlm_generic_payload *payload)
{
Bank bank = DramExtension::getExtension(payload).getBank();
buffer.push_back(std::pair<Bank, tlm::tlm_generic_payload *>(bank, payload));

View File

@@ -56,7 +56,7 @@ public:
controller(controller) {}
virtual ~FifoStrict() {}
void schedule(gp *payload) override;
void storeRequest(gp *payload) override;
std::pair<Command, tlm::tlm_generic_payload *> getNextRequest(
Bank bank) override;
virtual gp *getPendingRequest(Bank bank) override;

View File

@@ -58,9 +58,8 @@ using namespace std;
// Bank6: OOOOO0XX
// Bank7: XXXXXXXX
void FR_FCFS::schedule(gp *payload)
void FR_FCFS::storeRequest(gp *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 (?).

View File

@@ -51,7 +51,7 @@ public:
FR_FCFS(ControllerCore &controllerCore) : IScheduler(controllerCore) {}
virtual ~FR_FCFS() {}
void schedule(gp *payload) override;
void storeRequest(gp *payload) override;
std::pair<Command, tlm::tlm_generic_payload *> getNextRequest(
Bank bank) override;
virtual gp *getPendingRequest(Bank bank) override;

View File

@@ -52,7 +52,7 @@ public:
virtual ~IScheduler() {}
IScheduler(ControllerCore &controllerCore) : controllerCore(controllerCore) {}
virtual void schedule(gp *payload) = 0;
virtual void storeRequest(gp *payload) = 0;
virtual std::pair<Command, gp *> getNextRequest(Bank bank) = 0;
virtual gp *getPendingRequest(Bank bank) = 0;
static std::string sendername;

View File

@@ -3,7 +3,7 @@
using namespace std;
void SMS::schedule(gp *payload)
void SMS::storeRequest(gp *payload)
{
Thread thread = DramExtension::getExtension(payload).getThread();
bool wasEmpty = isRequestBuffersEmpty();

View File

@@ -46,7 +46,7 @@ public:
{
}
virtual void schedule(gp *payload) override;
virtual void storeRequest(gp *payload) override;
virtual std::pair<Command, gp *> getNextRequest(Bank bank) override;
virtual gp *getPendingRequest(Bank bank) override;

View File

@@ -79,11 +79,6 @@ public:
tSocket.register_transport_dbg(this, &Arbiter::transport_dbg);
}
void setTlmRecorders(std::vector<TlmRecorder *> recorders)
{
tlmRecorders = recorders;
}
private:
tlm_utils::peq_with_cb_and_phase<Arbiter> payloadEventQueue;
@@ -96,8 +91,6 @@ private:
// This is a queue of responses comming from the memory side. The phase of these transactions is BEGIN_RESP.
std::map<unsigned int, queue<tlm_generic_payload *>> receivedResponses;
std::vector<TlmRecorder *> tlmRecorders;
//used to map the transaction from devices to the arbiter's target socket ID.
std::map<tlm_generic_payload *, int> routeMap;
@@ -111,15 +104,10 @@ private:
payload).getChannel().ID()) {
SC_REPORT_FATAL("Arbiter", "Payload extension was corrupted");
}
sc_time recTime = bwDelay + sc_time_stamp();
sc_time notDelay = bwDelay;
printDebugMessage("[bw] Recording " + phaseNameToString(
phase) + " at " + recTime.to_string() + " notification in " +
notDelay.to_string());
tlmRecorders[channelId]->recordPhase(payload, phase, recTime);
payloadEventQueue.notify(payload, phase, notDelay);
printDebugMessage("[bw] " + phaseNameToString(phase) + " notification in " +
bwDelay.to_string());
payloadEventQueue.notify(payload, phase, bwDelay);
return TLM_ACCEPTED;
}
@@ -128,6 +116,8 @@ private:
tlm_sync_enum nb_transport_fw(int id, tlm_generic_payload &payload,
tlm_phase &phase, sc_time &fwDelay)
{
sc_time notDelay = clkAlign(sc_time_stamp() + fwDelay) -
(sc_time_stamp() + fwDelay);
if (phase == BEGIN_REQ) {
// adjust address offset:
payload.set_address(payload.get_address() -
@@ -141,12 +131,15 @@ private:
appendDramExtension(id, payload);
payload.acquire();
} else if (phase == END_RESP) {
notDelay += Configuration::getInstance().memSpec.clk;
// Erase before the payload is released.
routeMap.erase(&payload);
payload.release();
}
payloadEventQueue.notify(payload, phase, fwDelay);
printDebugMessage("[fw] " + phaseNameToString(phase) + " notification in " +
notDelay.to_string());
payloadEventQueue.notify(payload, phase, notDelay);
return TLM_ACCEPTED;
}

View File

@@ -198,8 +198,7 @@ void DRAMSys::setupTlmRecorders(const string &traceName,
TlmRecorder *tlmRecorder =
new TlmRecorder(recorderName.c_str(),
sqlScriptURI.c_str(),
dbName.c_str(),
Configuration::getInstance().DatabaseRecording);
dbName.c_str());
tlmRecorder->recordMCconfig(Configuration::getInstance().mcconfigUri);
tlmRecorder->recordMemspec(Configuration::getInstance().memspecUri);
@@ -219,7 +218,9 @@ void DRAMSys::instantiateModules(const string &traceName,
// Create and properly initialize TLM recorders.
// They need to be ready before creating some modules.
setupTlmRecorders(traceName, pathToResources);
bool recordingEnabled = Configuration::getInstance().DatabaseRecording;
if (recordingEnabled)
setupTlmRecorders(traceName, pathToResources);
// Create new ECC Controller
switch (Configuration::getInstance().ECCMode) {
@@ -236,19 +237,26 @@ void DRAMSys::instantiateModules(const string &traceName,
// Create arbiter
arbiter = new Arbiter("arbiter");
arbiter->setTlmRecorders(tlmRecorders);
// Create DRAM
for (size_t i = 0;
i < Configuration::getInstance().NumberOfMemChannels;
i++) {
std::string str = "controller" + std::to_string(i);
Controller *controller = new Controller(str.c_str(), tlmRecorders[i]);
Controller *controller;
if (recordingEnabled)
controller = new RecordableController(str.c_str(), tlmRecorders[i]);
else
controller = new Controller(str.c_str());
controllers.push_back(controller);
str = "dram" + std::to_string(i);
Dram *dram = new Dram(str.c_str());
dram->setTlmRecorder(tlmRecorders[i]);
Dram *dram;
if (recordingEnabled)
dram = new RecordableDram(str.c_str(), tlmRecorders[i]);
else
dram = new Dram(str.c_str());
dram->setDramController(controllers[i]);
drams.push_back(dram);

View File

@@ -42,13 +42,13 @@
#include <string>
#include <systemc.h>
#include "Dram.h"
#include "RecordableDram.h"
#include "Arbiter.h"
#include "TraceGenerator.h"
#include "ReorderBuffer.h"
#include <tlm_utils/multi_passthrough_target_socket.h>
#include <tlm_utils/multi_passthrough_initiator_socket.h>
#include "../controller/Controller.h"
#include "../controller/RecordableController.h"
#include "../common/third_party/tinyxml2/tinyxml2.h"
#include "../common/tlm2_base_protocol_checker.h"
#include "../error/eccbaseclass.h"

View File

@@ -56,7 +56,6 @@
#include "../controller/core/configuration/Configuration.h"
#include "../common/protocol.h"
#include "../common/Utils.h"
#include "../common/TlmRecorder.h"
#include "../common/third_party/DRAMPower/src/libdrampower/LibDRAMPower.h"
#include "../error/errormodel.h"
@@ -72,8 +71,6 @@ struct Dram : sc_module {
// Power Model related
bool powerAnalysis = Configuration::getInstance().PowerAnalysis;
sc_time powerWindowSize = Configuration::getInstance().memSpec.clk *
Configuration::getInstance().WindowSize;
libDRAMPower *DRAMPower;
// Bandwidth realted:
@@ -88,7 +85,6 @@ struct Dram : sc_module {
// Data Storage:
unsigned char *memory;
TlmRecorder *tlmRecorder;
Controller *dramController;
SC_CTOR(Dram) : tSocket("socket")
@@ -97,7 +93,6 @@ struct Dram : sc_module {
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
@@ -209,11 +204,6 @@ struct Dram : sc_module {
memSpec.memArchSpec = memArchSpec;
DRAMPower = new libDRAMPower( memSpec, 0 );
// Create a thread that is triggered every $powerWindowSize
// to generate a Power over Time plot in the Trace analyzer:
if (Configuration::getInstance().EnableWindowing)
SC_THREAD(powerWindow);
}
// Bandwidth Calculation:
@@ -244,13 +234,8 @@ struct Dram : sc_module {
~Dram()
{
if (powerAnalysis == true) {
// Obtain the residual energy which was not covered by
// previous windows
DRAMPower->calcEnergy();
tlmRecorder->recordPower(sc_time_stamp().to_seconds(),
DRAMPower->getPower().window_average_power
* Configuration::getInstance().NumberOfDevicesOnDIMM);
if (!Configuration::getInstance().DatabaseRecording)
DRAMPower->calcEnergy();
// Print the final total energy and the average power for
// the simulation:
@@ -313,88 +298,18 @@ struct Dram : sc_module {
for (auto e : ememory) {
delete e;
}
tlmRecorder->closeConnection();
}
// When working with floats, we have to decide ourselves what is an
// acceptable definition for "equal". Here the number is compared with a
// suitable error margin (0.00001).
bool is_equal(double a, double b, const double epsilon = 1e-05)
{
return std::fabs(a - b) < epsilon;
}
// This Thread is only triggered when Power Simulation is enabled.
// It estimates the current average power which will be stored in the trace database for visualization purposes.
void powerWindow()
{
unsigned long long clk_cycles = 0;
do {
// At the very beginning (zero clock cycles) the energy is 0, so we wait first
wait(powerWindowSize);
clk_cycles = sc_time_stamp().value() /
Configuration::getInstance().memSpec.clk.value();
DRAMPower->calcWindowEnergy(clk_cycles);
// During operation the energy should never be zero since the device is always consuming
assert(!is_equal(DRAMPower->getEnergy().window_energy, 0.0));
// Store the time (in seconds) and the current average power (in mW) into the database
tlmRecorder->recordPower(sc_time_stamp().to_seconds(),
DRAMPower->getPower().window_average_power *
Configuration::getInstance().NumberOfDevicesOnDIMM);
// Here considering that DRAMPower provides the energy in pJ and the power in mW
printDebugMessage(string("\tWindow Energy: \t") + to_string(
DRAMPower->getEnergy().window_energy *
Configuration::getInstance().NumberOfDevicesOnDIMM) + string("\t[pJ]"));
printDebugMessage(string("\tWindow Average Power: \t") + to_string(
DRAMPower->getPower().window_average_power *
Configuration::getInstance().NumberOfDevicesOnDIMM) + string("\t[mW]"));
} while (true);
}
virtual tlm::tlm_sync_enum nb_transport_fw(tlm::tlm_generic_payload &payload,
tlm::tlm_phase &phase, sc_time &delay)
{
// Recording time used by the traceAnalyzer
sc_time recTime = sc_time_stamp() + delay;
if (numberOfTransactionsServed == 0) {
firstAccess = sc_time_stamp();
} else {
lastAccess = sc_time_stamp();
}
// These are terminating phases recorded by the DRAM. The execution
// time of the related command must be taken into consideration.
if (phase == END_PDNA || phase == END_PDNAB) {
recTime += getExecutionTime(Command::PDNAX, payload);
} else if (phase == END_PDNP || phase == END_PDNPB) {
recTime += getExecutionTime(Command::PDNPX, payload);
} else if (phase == END_SREF || phase == END_SREFB) {
recTime += getExecutionTime(Command::SREFX, payload);
}
unsigned int thr = DramExtension::getExtension(payload).getThread().ID();
unsigned int ch = DramExtension::getExtension(payload).getChannel().ID();
unsigned int bg = DramExtension::getExtension(payload).getBankGroup().ID();
unsigned int bank = DramExtension::getExtension(payload).getBank().ID();
unsigned int row = DramExtension::getExtension(payload).getRow().ID();
unsigned int col = DramExtension::getExtension(payload).getColumn().ID();
printDebugMessage("[fw] Recording " + phaseNameToString(
phase) + " thread " + to_string(thr) + " channel " + to_string(
ch) + " bank group " + to_string(bg) + " bank " + to_string(
bank) + " row " + to_string(row) + " column " + to_string(
col) + " at " + recTime.to_string());
tlmRecorder->recordPhase(payload, phase, recTime);
// This is only needed for power simulation:
unsigned long long cycle = 0;
@@ -650,10 +565,6 @@ struct Dram : sc_module {
DebugManager::getInstance().printDebugMessage(name(), message);
}
void setTlmRecorder(TlmRecorder *rec)
{
tlmRecorder = rec;
}
void setDramController(Controller *contr)
{
dramController = contr;

View File

@@ -0,0 +1,152 @@
/*
* Copyright (c) 2018, University of Kaiserslautern
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* 3. Neither the name of the copyright holder nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER
* OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* Authors:
* Felipe S. Prado
* Matthias Jung
*/
#ifndef RECORDABLEDRAM_H_
#define RECORDABLEDRAM_H_
#include "Dram.h"
#include "../common/TlmRecorder.h"
struct RecordableDram : public Dram {
SC_HAS_PROCESS(RecordableDram);
RecordableDram(sc_module_name name, TlmRecorder *tlmRecorder):
Dram(name), tlmRecorder(tlmRecorder)
{
// Create a thread that is triggered every $powerWindowSize
// to generate a Power over Time plot in the Trace analyzer:
if (Configuration::getInstance().PowerAnalysis
&& Configuration::getInstance().EnableWindowing)
SC_THREAD(powerWindow);
}
~RecordableDram()
{
if (Configuration::getInstance().PowerAnalysis) {
// Obtain the residual energy which was not covered by
// previous windows
DRAMPower->calcEnergy();
recordPower();
}
tlmRecorder->closeConnection();
}
TlmRecorder *tlmRecorder;
sc_time powerWindowSize = Configuration::getInstance().memSpec.clk *
Configuration::getInstance().WindowSize;
virtual tlm::tlm_sync_enum nb_transport_fw(tlm::tlm_generic_payload &payload,
tlm::tlm_phase &phase, sc_time &delay)
{
// Recording time used by the traceAnalyzer
sc_time recTime = sc_time_stamp() + delay;
// These are terminating phases recorded by the DRAM. The execution
// time of the related command must be taken into consideration.
if (phase == END_PDNA || phase == END_PDNAB) {
recTime += getExecutionTime(Command::PDNAX, payload);
} else if (phase == END_PDNP || phase == END_PDNPB) {
recTime += getExecutionTime(Command::PDNPX, payload);
} else if (phase == END_SREF || phase == END_SREFB) {
recTime += getExecutionTime(Command::SREFX, payload);
}
unsigned int thr = DramExtension::getExtension(payload).getThread().ID();
unsigned int ch = DramExtension::getExtension(payload).getChannel().ID();
unsigned int bg = DramExtension::getExtension(payload).getBankGroup().ID();
unsigned int bank = DramExtension::getExtension(payload).getBank().ID();
unsigned int row = DramExtension::getExtension(payload).getRow().ID();
unsigned int col = DramExtension::getExtension(payload).getColumn().ID();
printDebugMessage("Recording " + phaseNameToString(phase) + " thread " +
to_string(thr) + " channel " + to_string(ch) + " bank group " + to_string(
bg) + " bank " + to_string(bank) + " row " + to_string(row) + " column " +
to_string(col) + " at " + recTime.to_string());
tlmRecorder->recordPhase(payload, phase, recTime);
return Dram::nb_transport_fw(payload, phase, delay);
}
// When working with floats, we have to decide ourselves what is an
// acceptable definition for "equal". Here the number is compared with a
// suitable error margin (0.00001).
bool is_equal(double a, double b, const double epsilon = 1e-05)
{
return std::fabs(a - b) < epsilon;
}
// This Thread is only triggered when Power Simulation is enabled.
// It estimates the current average power which will be stored in the trace database for visualization purposes.
void powerWindow()
{
unsigned long long clk_cycles = 0;
do {
// At the very beginning (zero clock cycles) the energy is 0, so we wait first
wait(powerWindowSize);
clk_cycles = sc_time_stamp().value() /
Configuration::getInstance().memSpec.clk.value();
DRAMPower->calcWindowEnergy(clk_cycles);
// During operation the energy should never be zero since the device is always consuming
assert(!is_equal(DRAMPower->getEnergy().window_energy, 0.0));
// Store the time (in seconds) and the current average power (in mW) into the database
recordPower();
// Here considering that DRAMPower provides the energy in pJ and the power in mW
printDebugMessage(string("\tWindow Energy: \t") + to_string(
DRAMPower->getEnergy().window_energy *
Configuration::getInstance().NumberOfDevicesOnDIMM) + string("\t[pJ]"));
printDebugMessage(string("\tWindow Average Power: \t") + to_string(
DRAMPower->getPower().window_average_power *
Configuration::getInstance().NumberOfDevicesOnDIMM) + string("\t[mW]"));
} while (true);
}
void recordPower()
{
tlmRecorder->recordPower(sc_time_stamp().to_seconds(),
DRAMPower->getPower().window_average_power
* Configuration::getInstance().NumberOfDevicesOnDIMM);
}
};
#endif /* RECORDABLEDRAM_H_ */