diff --git a/DRAMSys/library/library.pro b/DRAMSys/library/library.pro index d2e26c1f..f9c718f7 100644 --- a/DRAMSys/library/library.pro +++ b/DRAMSys/library/library.pro @@ -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 \ diff --git a/DRAMSys/library/src/common/TlmRecorder.cpp b/DRAMSys/library/src/common/TlmRecorder.cpp index 9cc03443..0fae8cd7 100644 --- a/DRAMSys/library/src/common/TlmRecorder.cpp +++ b/DRAMSys/library/src/common/TlmRecorder.cpp @@ -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; } diff --git a/DRAMSys/library/src/common/TlmRecorder.h b/DRAMSys/library/src/common/TlmRecorder.h index f984dc4a..31deb14d 100644 --- a/DRAMSys/library/src/common/TlmRecorder.h +++ b/DRAMSys/library/src/common/TlmRecorder.h @@ -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) diff --git a/DRAMSys/library/src/controller/Controller.cpp b/DRAMSys/library/src/controller/Controller.cpp index e7bb8af2..ad4879a3 100644 --- a/DRAMSys/library/src/controller/Controller.cpp +++ b/DRAMSys/library/src/controller/Controller.cpp @@ -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 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 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()); } diff --git a/DRAMSys/library/src/controller/Controller.h b/DRAMSys/library/src/controller/Controller.h index 90c787f3..f09fedfa 100644 --- a/DRAMSys/library/src/controller/Controller.h +++ b/DRAMSys/library/src/controller/Controller.h @@ -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 controllerCorePEQ; DebugManager &debugManager; - TlmRecorder *tlmRecorder; // Bandwidth realted: sc_time idleStart; diff --git a/DRAMSys/library/src/controller/RecordableController.cpp b/DRAMSys/library/src/controller/RecordableController.cpp new file mode 100644 index 00000000..51ff4f21 --- /dev/null +++ b/DRAMSys/library/src/controller/RecordableController.cpp @@ -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); + } +} diff --git a/DRAMSys/library/src/controller/RecordableController.h b/DRAMSys/library/src/controller/RecordableController.h new file mode 100644 index 00000000..3f37870c --- /dev/null +++ b/DRAMSys/library/src/controller/RecordableController.h @@ -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 diff --git a/DRAMSys/library/src/controller/core/ControllerCore.cpp b/DRAMSys/library/src/controller/core/ControllerCore.cpp index 0a9f434a..fd278bb6 100644 --- a/DRAMSys/library/src/controller/core/ControllerCore.cpp +++ b/DRAMSys/library/src/controller/core/ControllerCore.cpp @@ -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 &ControllerCore::getBanks() diff --git a/DRAMSys/library/src/controller/core/ControllerCore.h b/DRAMSys/library/src/controller/core/ControllerCore.h index 7a3818ef..7b00f1ea 100644 --- a/DRAMSys/library/src/controller/core/ControllerCore.h +++ b/DRAMSys/library/src/controller/core/ControllerCore.h @@ -58,7 +58,7 @@ public: std::map &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 &getBanks(); diff --git a/DRAMSys/library/src/controller/core/powerdown/PowerDownManager.cpp b/DRAMSys/library/src/controller/core/powerdown/PowerDownManager.cpp index 45923fdd..93cab1a6 100644 --- a/DRAMSys/library/src/controller/core/powerdown/PowerDownManager.cpp +++ b/DRAMSys/library/src/controller/core/powerdown/PowerDownManager.cpp @@ -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) diff --git a/DRAMSys/library/src/controller/core/scheduling/ScheduledCommand.cpp b/DRAMSys/library/src/controller/core/scheduling/ScheduledCommand.cpp index 34ed336e..3b367eda 100644 --- a/DRAMSys/library/src/controller/core/scheduling/ScheduledCommand.cpp +++ b/DRAMSys/library/src/controller/core/scheduling/ScheduledCommand.cpp @@ -45,7 +45,6 @@ bool ScheduledCommand::isNoCommand() const && executionTime == SC_ZERO_TIME && end == SC_ZERO_TIME); } - bool ScheduledCommand::isValidCommand() const { return !isNoCommand(); diff --git a/DRAMSys/library/src/controller/core/scheduling/ScheduledCommand.h b/DRAMSys/library/src/controller/core/scheduling/ScheduledCommand.h index 8bb57653..c2a5a2fc 100644 --- a/DRAMSys/library/src/controller/core/scheduling/ScheduledCommand.h +++ b/DRAMSys/library/src/controller/core/scheduling/ScheduledCommand.h @@ -62,7 +62,6 @@ public: { } - ScheduledCommand() : command(Command::NOP), start(SC_ZERO_TIME), executionTime(SC_ZERO_TIME), end(SC_ZERO_TIME), extension() diff --git a/DRAMSys/library/src/controller/scheduler/Fifo.cpp b/DRAMSys/library/src/controller/scheduler/Fifo.cpp index fe041319..6eb46aa8 100644 --- a/DRAMSys/library/src/controller/scheduler/Fifo.cpp +++ b/DRAMSys/library/src/controller/scheduler/Fifo.cpp @@ -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); } diff --git a/DRAMSys/library/src/controller/scheduler/Fifo.h b/DRAMSys/library/src/controller/scheduler/Fifo.h index 7194fad6..912570d2 100644 --- a/DRAMSys/library/src/controller/scheduler/Fifo.h +++ b/DRAMSys/library/src/controller/scheduler/Fifo.h @@ -50,7 +50,7 @@ public: Fifo(ControllerCore &controllerCore) : IScheduler(controllerCore) {} virtual ~Fifo() {} - void schedule(gp *payload) override; + void storeRequest(gp *payload) override; std::pair getNextRequest( Bank bank) override; virtual gp *getPendingRequest(Bank bank) override; diff --git a/DRAMSys/library/src/controller/scheduler/FifoStrict.cpp b/DRAMSys/library/src/controller/scheduler/FifoStrict.cpp index 035031d0..9b3f8ec3 100644 --- a/DRAMSys/library/src/controller/scheduler/FifoStrict.cpp +++ b/DRAMSys/library/src/controller/scheduler/FifoStrict.cpp @@ -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, payload)); diff --git a/DRAMSys/library/src/controller/scheduler/FifoStrict.h b/DRAMSys/library/src/controller/scheduler/FifoStrict.h index 74e85b2e..acd22086 100644 --- a/DRAMSys/library/src/controller/scheduler/FifoStrict.h +++ b/DRAMSys/library/src/controller/scheduler/FifoStrict.h @@ -56,7 +56,7 @@ public: controller(controller) {} virtual ~FifoStrict() {} - void schedule(gp *payload) override; + void storeRequest(gp *payload) override; std::pair getNextRequest( Bank bank) override; virtual gp *getPendingRequest(Bank bank) override; diff --git a/DRAMSys/library/src/controller/scheduler/Fr_Fcfs.cpp b/DRAMSys/library/src/controller/scheduler/Fr_Fcfs.cpp index a50212e6..05a4e745 100644 --- a/DRAMSys/library/src/controller/scheduler/Fr_Fcfs.cpp +++ b/DRAMSys/library/src/controller/scheduler/Fr_Fcfs.cpp @@ -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 (?). diff --git a/DRAMSys/library/src/controller/scheduler/Fr_Fcfs.h b/DRAMSys/library/src/controller/scheduler/Fr_Fcfs.h index 02b46ca0..983c664a 100644 --- a/DRAMSys/library/src/controller/scheduler/Fr_Fcfs.h +++ b/DRAMSys/library/src/controller/scheduler/Fr_Fcfs.h @@ -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 getNextRequest( Bank bank) override; virtual gp *getPendingRequest(Bank bank) override; diff --git a/DRAMSys/library/src/controller/scheduler/IScheduler.h b/DRAMSys/library/src/controller/scheduler/IScheduler.h index 7d7837a6..0b0cf0f5 100644 --- a/DRAMSys/library/src/controller/scheduler/IScheduler.h +++ b/DRAMSys/library/src/controller/scheduler/IScheduler.h @@ -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 getNextRequest(Bank bank) = 0; virtual gp *getPendingRequest(Bank bank) = 0; static std::string sendername; diff --git a/DRAMSys/library/src/controller/scheduler/SMS.cpp b/DRAMSys/library/src/controller/scheduler/SMS.cpp index 9406237a..0f407775 100644 --- a/DRAMSys/library/src/controller/scheduler/SMS.cpp +++ b/DRAMSys/library/src/controller/scheduler/SMS.cpp @@ -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(); diff --git a/DRAMSys/library/src/controller/scheduler/SMS.h b/DRAMSys/library/src/controller/scheduler/SMS.h index 0cb18882..d60c033a 100644 --- a/DRAMSys/library/src/controller/scheduler/SMS.h +++ b/DRAMSys/library/src/controller/scheduler/SMS.h @@ -46,7 +46,7 @@ public: { } - virtual void schedule(gp *payload) override; + virtual void storeRequest(gp *payload) override; virtual std::pair getNextRequest(Bank bank) override; virtual gp *getPendingRequest(Bank bank) override; diff --git a/DRAMSys/library/src/simulation/Arbiter.h b/DRAMSys/library/src/simulation/Arbiter.h index 027184d2..7f60913d 100644 --- a/DRAMSys/library/src/simulation/Arbiter.h +++ b/DRAMSys/library/src/simulation/Arbiter.h @@ -79,11 +79,6 @@ public: tSocket.register_transport_dbg(this, &Arbiter::transport_dbg); } - void setTlmRecorders(std::vector recorders) - { - tlmRecorders = recorders; - } - private: tlm_utils::peq_with_cb_and_phase 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> receivedResponses; - std::vector tlmRecorders; - //used to map the transaction from devices to the arbiter's target socket ID. std::map 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; } diff --git a/DRAMSys/library/src/simulation/DRAMSys.cpp b/DRAMSys/library/src/simulation/DRAMSys.cpp index 031e4bc4..a1b48a58 100644 --- a/DRAMSys/library/src/simulation/DRAMSys.cpp +++ b/DRAMSys/library/src/simulation/DRAMSys.cpp @@ -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); diff --git a/DRAMSys/library/src/simulation/DRAMSys.h b/DRAMSys/library/src/simulation/DRAMSys.h index 0a3c2337..25bf4bad 100644 --- a/DRAMSys/library/src/simulation/DRAMSys.h +++ b/DRAMSys/library/src/simulation/DRAMSys.h @@ -42,13 +42,13 @@ #include #include -#include "Dram.h" +#include "RecordableDram.h" #include "Arbiter.h" #include "TraceGenerator.h" #include "ReorderBuffer.h" #include #include -#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" diff --git a/DRAMSys/library/src/simulation/Dram.h b/DRAMSys/library/src/simulation/Dram.h index be46ff2a..566f9b83 100644 --- a/DRAMSys/library/src/simulation/Dram.h +++ b/DRAMSys/library/src/simulation/Dram.h @@ -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; diff --git a/DRAMSys/library/src/simulation/RecordableDram.h b/DRAMSys/library/src/simulation/RecordableDram.h new file mode 100644 index 00000000..00a2d073 --- /dev/null +++ b/DRAMSys/library/src/simulation/RecordableDram.h @@ -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_ */ +