#include "TlmRecorder.h" #include "protocol.h" #include "dramExtension.h" #include "xmlAddressdecoder.h" #include "../controller/core/configuration/Configuration.h" #include #include #include using namespace std; string TlmRecorder::dbName = ""; string TlmRecorder::sqlScriptURI = ""; string TlmRecorder::senderName = "TlmRecorder"; bool TlmRecorder::recordingEnabled = true; // ------------- public ----------------------- TlmRecorder::TlmRecorder() : totalNumTransactions(1), simulationTimeCoveredByRecording(SC_ZERO_TIME) { if(recordingEnabled) { 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(); printDebugMessage("Starting new database transaction"); } } TlmRecorder::~TlmRecorder() { if (db) closeConnection(); } 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); 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; } } 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; } } void TlmRecorder::recordDebugMessage(std::string message, sc_time time) { if(TlmRecorder::recordingEnabled) insertDebugMessageInDB(message, time); } // ------------- internal ----------------------- void TlmRecorder::introduceTransactionSystem(tlm::tlm_generic_payload& trans) { unsigned int id = totalNumTransactions++; currentTransactionsInSystem[&trans].id = id; currentTransactionsInSystem[&trans].address = trans.get_address(); currentTransactionsInSystem[&trans].burstlength = trans.get_streaming_width(); currentTransactionsInSystem[&trans].dramExtension = DramExtension::getExtension(trans); if(DramExtension::getExtension(trans).getThread().ID() == 0) currentTransactionsInSystem[&trans].timeOfGeneration = SC_ZERO_TIME; else currentTransactionsInSystem[&trans].timeOfGeneration = GenerationExtension::getExtension(&trans).TimeOfGeneration(); if (id % transactionCommitRate == 0) { printDebugMessage( "Committing transactions " + to_string(id - transactionCommitRate + 1) + " - " + to_string(id)); commitRecordedDataToDB(); } } void TlmRecorder::removeTransactionFromSystem(tlm::tlm_generic_payload& trans) { assert(currentTransactionsInSystem.count(&trans) != 0); Transaction& recordingData = currentTransactionsInSystem[&trans]; recordedData.push_back(recordingData); currentTransactionsInSystem.erase(&trans); } void TlmRecorder::commitRecordedDataToDB() { sqlite3_exec(db, "BEGIN;", 0, 0, 0); for(Transaction& recordingData: recordedData) { assert(recordingData.recordedPhases.size() > 0); insertTransactionInDB(recordingData); for(Transaction::Phase& phaseData: recordingData.recordedPhases) { insertPhaseInDB(phaseData.name,phaseData.interval.start,phaseData.interval.end,recordingData.id); } sc_time rangeBegin = recordingData.recordedPhases.front().interval.start; sc_time rangeEnd = recordingData.recordedPhases.back().interval.end; insertRangeInDB(recordingData.id,rangeBegin,rangeEnd); } sqlite3_exec(db, "COMMIT;", 0, 0, 0); recordedData.clear(); } void TlmRecorder::Transaction::insertPhase(string name, sc_time begin) { recordedPhases.push_back(Phase(name,begin)); } void TlmRecorder::Transaction::setPhaseEnd(string name, sc_time end) { for(Phase& data: recordedPhases) { if(data.name == name) { data.interval.end = end; return; } } SC_REPORT_FATAL("Recording Error", "While trying to set phase end: phaseBegin has not been recorded"); } void TlmRecorder::openDB(std::string name) { boost::filesystem::wpath file(name); if(boost::filesystem::exists(file)) boost::filesystem::remove(file); if (sqlite3_open(name.c_str(), &db)) { SC_REPORT_FATAL("Error in TraceRecorder", "Error cannot open database"); sqlite3_close(db); } } void TlmRecorder::createTables(string pathToURI) { string initial = loadTextFileContents(pathToURI); executeSqlCommand(initial); } void TlmRecorder::setUpTransactionTerminatingPhases() { transactionTerminatingPhases.push_back(tlm::END_RESP); transactionTerminatingPhases.push_back(static_cast(END_REFA)); transactionTerminatingPhases.push_back(static_cast(END_REFB)); transactionTerminatingPhases.push_back(static_cast(END_PDNP)); transactionTerminatingPhases.push_back(static_cast(END_PDNA)); transactionTerminatingPhases.push_back(static_cast(END_SREF)); transactionTerminatingPhases.push_back(static_cast(END_PDNPB)); transactionTerminatingPhases.push_back(static_cast(END_PDNAB)); transactionTerminatingPhases.push_back(static_cast(END_SREFB)); } void TlmRecorder::prepareSqlStatements() { insertTransactionString = "INSERT INTO Transactions VALUES (:id,:rangeID,:address,:burstlength,:thread,:channel,:bank,:bankgroup,:row,:column,:dataStrobeBegin,:dataStrobeEnd, :timeOfGeneration,:command)"; insertRangeString = "INSERT INTO Ranges VALUES (:id,:begin,:end)"; updateRangeString = "UPDATE Ranges SET End = :end WHERE ID = :id"; updateDataStrobeString = "UPDATE Transactions SET DataStrobeBegin = :begin, DataStrobeEnd = :end WHERE ID = :id"; insertPhaseString = "INSERT INTO Phases (PhaseName,PhaseBegin,PhaseEnd,Transact) VALUES (:name,:begin,:end,:transaction)"; updatePhaseString = "UPDATE Phases SET PhaseEnd = :end WHERE Transact = :trans AND PhaseName = :name"; insertGeneralInfoString = "INSERT INTO GeneralInfo (NumberOfTransactions,TraceEnd,NumberOfBanks,clk,UnitOfTime,Memconfig,Memspec,Traces) Values " "(:numberOfTransactions,:end,:numberOfBanks,:clk,:unitOfTime,:memconfig,:memspec,:traces)"; insertDebugMessageString = "INSERT INTO DebugMessages (Time,Message) Values (:time,:message)"; sqlite3_prepare_v2(db, insertTransactionString.c_str(), -1, &insertTransactionStatement, 0); sqlite3_prepare_v2(db, insertRangeString.c_str(), -1, &insertRangeStatement, 0); sqlite3_prepare_v2(db, updateRangeString.c_str(), -1, &updateRangeStatement, 0); sqlite3_prepare_v2(db, insertPhaseString.c_str(), -1, &insertPhaseStatement, 0); sqlite3_prepare_v2(db, updatePhaseString.c_str(), -1, &updatePhaseStatement, 0); sqlite3_prepare_v2(db, updateDataStrobeString.c_str(), -1, &updateDataStrobeStatement, 0); sqlite3_prepare_v2(db, insertGeneralInfoString.c_str(), -1, &insertGeneralInfoStatement, 0); sqlite3_prepare_v2(db, insertDebugMessageString.c_str(), -1, &insertDebugMessageStatement, 0); } void TlmRecorder::insertDebugMessageInDB(string message, const sc_time& time) { sqlite3_bind_int64(insertDebugMessageStatement, 1, time.value()); sqlite3_bind_text(insertDebugMessageStatement, 2, message.c_str(), message.length(), 0); executeSqlStatement(insertDebugMessageStatement); } void TlmRecorder::insertGeneralInfo() { sqlite3_bind_int64(insertGeneralInfoStatement, 1, totalNumTransactions - 1); sqlite3_bind_int64(insertGeneralInfoStatement, 2, simulationTimeCoveredByRecording.value()); sqlite3_bind_int(insertGeneralInfoStatement, 3, core::Configuration::getInstance().NumberOfBanks); sqlite3_bind_int(insertGeneralInfoStatement, 4, core::Configuration::getInstance().Timings.clk.value()); sqlite3_bind_text(insertGeneralInfoStatement, 5, "PS", 2, NULL); sqlite3_bind_text(insertGeneralInfoStatement, 6, memconfig.c_str(), memconfig.length(), NULL); sqlite3_bind_text(insertGeneralInfoStatement, 7, memspec.c_str(), memspec.length(), NULL); sqlite3_bind_text(insertGeneralInfoStatement, 8, traces.c_str(), traces.length(), NULL); executeSqlStatement(insertGeneralInfoStatement); } void TlmRecorder::insertTransactionInDB(Transaction& recordingData) { sqlite3_bind_int(insertTransactionStatement, 1, recordingData.id); sqlite3_bind_int(insertTransactionStatement, 2, recordingData.id); sqlite3_bind_int(insertTransactionStatement, 3, recordingData.address); sqlite3_bind_int(insertTransactionStatement, 4, recordingData.burstlength); sqlite3_bind_int(insertTransactionStatement, 5, recordingData.dramExtension.getThread().ID()); sqlite3_bind_int(insertTransactionStatement, 6, recordingData.dramExtension.getChannel().ID()); sqlite3_bind_int(insertTransactionStatement, 7, recordingData.dramExtension.getBank().ID()); sqlite3_bind_int(insertTransactionStatement, 8, recordingData.dramExtension.getBankGroup().ID()); sqlite3_bind_int(insertTransactionStatement, 9, recordingData.dramExtension.getRow().ID()); sqlite3_bind_int(insertTransactionStatement, 10, recordingData.dramExtension.getColumn().ID()); sqlite3_bind_int64(insertTransactionStatement, 11, recordingData.timeOnDataStrobe.start.value()); sqlite3_bind_int64(insertTransactionStatement, 12, recordingData.timeOnDataStrobe.end.value()); sqlite3_bind_int64(insertTransactionStatement, 13, recordingData.timeOfGeneration.value()); executeSqlStatement(insertTransactionStatement); } void TlmRecorder::insertRangeInDB(unsigned int id, const sc_time& begin, const sc_time& end) { sqlite3_bind_int(insertRangeStatement, 1, id); sqlite3_bind_int64(insertRangeStatement, 2, begin.value()); sqlite3_bind_int64(insertRangeStatement, 3, end.value()); executeSqlStatement(insertRangeStatement); } void TlmRecorder::insertPhaseInDB(string phaseName, const sc_time& begin, const sc_time& end, unsigned int transactionID) { sqlite3_bind_text(insertPhaseStatement, 1, phaseName.c_str(), phaseName.length(), 0); sqlite3_bind_int64(insertPhaseStatement, 2, begin.value()); sqlite3_bind_int64(insertPhaseStatement, 3, end.value()); sqlite3_bind_int(insertPhaseStatement, 4, transactionID); executeSqlStatement(insertPhaseStatement); } void TlmRecorder::executeSqlStatement(sqlite3_stmt* statement) { int errorCode = sqlite3_step(statement); if (errorCode != SQLITE_DONE) { reportFatal("Error in TraceRecorder", string("Could not execute statement. Error code: ") + to_string(errorCode)); } sqlite3_reset(statement); } void TlmRecorder::executeSqlCommand(string command) { printDebugMessage("Creating database by running provided sql script"); char * errMsg = 0; int rc = sqlite3_exec(db, command.c_str(), NULL, 0, &errMsg); if (rc != SQLITE_OK) { SC_REPORT_FATAL("SQLITE Error", errMsg); sqlite3_free(errMsg); } printDebugMessage("Database created successfully"); } void TlmRecorder::printDebugMessage(std::string message) { DebugManager::getInstance().printDebugMessage(TlmRecorder::senderName, 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_close(db); db = NULL; } }