Files
DRAMSys/dram/src/common/TlmRecorder.cpp

333 lines
13 KiB
C++

#include "TlmRecorder.h"
#include "protocol.h"
#include "dramExtension.h"
#include "xmlAddressdecoder.h"
#include "../controller/core/configuration/Configuration.h"
#include <iostream>
#include <algorithm>
#include <boost/filesystem.hpp>
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<const tlm::tlm_phase>(END_REFA));
transactionTerminatingPhases.push_back(static_cast<const tlm::tlm_phase>(END_REFB));
transactionTerminatingPhases.push_back(static_cast<const tlm::tlm_phase>(END_PDNP));
transactionTerminatingPhases.push_back(static_cast<const tlm::tlm_phase>(END_PDNA));
transactionTerminatingPhases.push_back(static_cast<const tlm::tlm_phase>(END_SREF));
transactionTerminatingPhases.push_back(static_cast<const tlm::tlm_phase>(END_PDNPB));
transactionTerminatingPhases.push_back(static_cast<const tlm::tlm_phase>(END_PDNAB));
transactionTerminatingPhases.push_back(static_cast<const tlm::tlm_phase>(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;
}
}