#include "TlmRecorder.h" #include "protocol.h" #include "dramExtension.h" #include "xmlAddressdecoder.h" #include "Utils.h" #include using namespace std; string TlmRecorder::dbName = ""; string TlmRecorder::sqlScriptURI = ""; string TlmRecorder::senderName = "TlmRecorder"; TlmRecorder::TlmRecorder() : transactionIDCounter(1), recordingEndTime(SC_ZERO_TIME) { setUpTransactionTerminatingPhases(); openDB(TlmRecorder::dbName.c_str()); createTables(TlmRecorder::sqlScriptURI); prepareSqlStatements(); sqlite3_exec(db, "BEGIN", 0, 0, 0); printDebugMessage("Starting new database transaction"); } TlmRecorder::~TlmRecorder() { if (db) closeConnection(); } TlmRecorder& TlmRecorder::getInstance() { static TlmRecorder decoder; return decoder; } void TlmRecorder::recordPhase(tlm::tlm_generic_payload& trans, tlm::tlm_phase phase, sc_time time) { if (currentTransactionsInSystem.count(&trans) == 0) introduceNewTransactionToSystem(time, trans); unsigned int id = currentTransactionsInSystem[&trans]; string phaseName = phaseNameToString(phase); string phaseBeginPrefix = "BEGIN_"; string phaseEndPrefix = "END_"; if (phaseName.find(phaseBeginPrefix) != string::npos) { phaseName.erase(0, phaseBeginPrefix.length()); insertPhaseInDB(phaseName, time, time, trans); } else { phaseName.erase(0, phaseEndPrefix.length()); updatePhaseEndInDB(phaseName, time, trans); } bool phaseTerminatesTransaction = count(transactionTerminatingPhases.begin(), transactionTerminatingPhases.end(), phase) == 1; if (phaseTerminatesTransaction) removeTransactionFromSystem(time, trans); recordingEndTime = time; } void TlmRecorder::recordDebugMessage(std::string message, sc_time time) { insertDebugMessageInDB(message, time); } void TlmRecorder::createTables(string pathToURI) { string initial = getFileContents(pathToURI); executeSqlCommand(initial); } void TlmRecorder::setUpTransactionTerminatingPhases() { transactionTerminatingPhases.push_back(tlm::END_RESP); transactionTerminatingPhases.push_back(static_cast(END_AUTO_REFRESH)); transactionTerminatingPhases.push_back(static_cast(END_PDNP)); transactionTerminatingPhases.push_back(static_cast(END_PDNA)); transactionTerminatingPhases.push_back(static_cast(END_SREF)); } void TlmRecorder::prepareSqlStatements() { insertTransactionString = "INSERT INTO Transactions VALUES (:id,:rangeID,:address,:thread,:channel,:bank,:row,:column,:command)"; insertRangeString = "INSERT INTO Ranges VALUES (:id,:begin,:end)"; updateRangeString = "UPDATE Ranges SET End = :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,description,clk,UnitOfTime) Values (:numberOfTransactions,:end,:numberOfBanks,:description,:clk,:unitOfTime)"; insertDebugMessageString = "INSERT INTO DebugMessages (Time,Message) Values (:time,:message)"; sqlite3_prepare(db, insertTransactionString.c_str(), -1, &insertTransactionStatement, 0); sqlite3_prepare(db, insertRangeString.c_str(), -1, &insertRangeStatement, 0); sqlite3_prepare(db, updateRangeString.c_str(), -1, &updateRangeStatement, 0); sqlite3_prepare(db, insertPhaseString.c_str(), -1, &insertPhaseStatement, 0); sqlite3_prepare(db, updatePhaseString.c_str(), -1, &updatePhaseStatement, 0); sqlite3_prepare(db, insertGeneralInfoString.c_str(), -1, &insertGeneralInfoStatement, 0); sqlite3_prepare(db, insertDebugMessageString.c_str(), -1, &insertDebugMessageStatement, 0); } void TlmRecorder::openDB(std::string name) { if (sqlite3_open(name.c_str(), &db)) { SC_REPORT_FATAL("Error in TraceRecorder", "Error cannot open database"); sqlite3_close(db); } } 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, transactionIDCounter - 1); sqlite3_bind_int64(insertGeneralInfoStatement, 2, recordingEndTime.value()); sqlite3_bind_int(insertGeneralInfoStatement, 3, xmlAddressDecoder::getInstance().getNumberOfBanks()); sqlite3_bind_text(insertGeneralInfoStatement, 4, "", 0, NULL); sqlite3_bind_int(insertGeneralInfoStatement, 5, 6); sqlite3_bind_text(insertGeneralInfoStatement, 6, "NS", 2, NULL); executeSqlStatement(insertGeneralInfoStatement); } void TlmRecorder::insertTransactionInDB(unsigned int id, tlm::tlm_generic_payload& trans) { sqlite3_bind_int(insertTransactionStatement, 1, id); sqlite3_bind_int(insertTransactionStatement, 2, id); sqlite3_bind_int(insertTransactionStatement, 3, trans.get_address()); sqlite3_bind_text(insertTransactionStatement, 9, trans.get_command() == tlm::TLM_READ_COMMAND ? "R" : "W", 1, 0); const DramExtension& extension = DramExtension::getExtension(trans); sqlite3_bind_int(insertTransactionStatement, 4, extension.getThread().ID()); sqlite3_bind_int(insertTransactionStatement, 5, extension.getChannel().ID()); sqlite3_bind_int(insertTransactionStatement, 6, extension.getBank().ID()); sqlite3_bind_int(insertTransactionStatement, 7, extension.getRow().ID()); sqlite3_bind_int(insertTransactionStatement, 8, extension.getColumn().ID()); executeSqlStatement(insertTransactionStatement); } void TlmRecorder::insertRangeInDB(unsigned int id, const sc_time& time) { sqlite3_bind_int(insertRangeStatement, 1, id); sqlite3_bind_int64(insertRangeStatement, 2, time.value()); sqlite3_bind_int64(insertRangeStatement, 3, time.value()); executeSqlStatement(insertRangeStatement); } void TlmRecorder::insertPhaseInDB(string phaseName, const sc_time& begin, const sc_time& end, tlm::tlm_generic_payload& trans) { unsigned int id = getElementFromMap(currentTransactionsInSystem, &trans); 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, id); executeSqlStatement(insertPhaseStatement); } void TlmRecorder::updatePhaseEndInDB(string phaseName, const sc_time& time, tlm::tlm_generic_payload& trans) { unsigned int id = getElementFromMap(currentTransactionsInSystem, &trans); sqlite3_bind_int64(updatePhaseStatement, 1, time.value()); sqlite3_bind_int(updatePhaseStatement, 2, id); sqlite3_bind_text(updatePhaseStatement, 3, phaseName.c_str(), phaseName.length(), 0); executeSqlStatement(updatePhaseStatement); } void TlmRecorder::introduceNewTransactionToSystem(const sc_time& time, tlm::tlm_generic_payload& trans) { unsigned int id = transactionIDCounter++; currentTransactionsInSystem[&trans] = id; insertTransactionInDB(id, trans); insertRangeInDB(id, time); if (id % transactionCommitRate == 0) { sqlite3_exec(db, "COMMIT", 0, 0, 0); printDebugMessage( "Committing transactions " + to_string(id - transactionCommitRate + 1) + " - " + to_string(id)); sqlite3_exec(db, "BEGIN", 0, 0, 0); } } void TlmRecorder::removeTransactionFromSystem(const sc_time& time, tlm::tlm_generic_payload& trans) { unsigned int id = getElementFromMap(currentTransactionsInSystem, &trans); currentTransactionsInSystem.erase(&trans); sqlite3_bind_int64(updateRangeStatement, 1, time.value()); sqlite3_bind_int(updateRangeStatement, 2, id); executeSqlStatement(updateRangeStatement); } void TlmRecorder::executeSqlStatement(sqlite3_stmt* statement) { if (sqlite3_step(statement) != SQLITE_DONE) { SC_REPORT_FATAL("Error in TraceRecorder", "Could not execute statement"); } 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"); } string TlmRecorder::getFileContents(string filename) { ifstream in(filename.c_str(), ios::in | ios::binary); if (in) { string contents; in.seekg(0, ios::end); contents.resize(in.tellg()); in.seekg(0, ios::beg); in.read(&contents[0], contents.size()); in.close(); return (contents); } throw(errno); } void TlmRecorder::printDebugMessage(std::string message) { DebugManager::getInstance().printDebugMessage(TlmRecorder::senderName, message); } void TlmRecorder::closeConnection() { insertGeneralInfo(); sqlite3_exec(db, "COMMIT", 0, 0, 0); printDebugMessage( "Number of transactions written to DB: " + std::to_string(transactionIDCounter - 1)); printDebugMessage("tlmPhaseRecorder:\tEnd Recording"); sqlite3_close(db); db = NULL; }