283 lines
10 KiB
C++
283 lines
10 KiB
C++
#include "TlmRecorder.h"
|
|
#include "protocol.h"
|
|
#include "dramExtension.h"
|
|
#include "xmlAddressdecoder.h"
|
|
#include "Utils.h"
|
|
#include "../core/configuration/Configuration.h"
|
|
#include <iostream>
|
|
|
|
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<const tlm::tlm_phase>(END_AUTO_REFRESH));
|
|
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));
|
|
}
|
|
|
|
void TlmRecorder::prepareSqlStatements()
|
|
{
|
|
insertTransactionString =
|
|
"INSERT INTO Transactions VALUES (:id,:rangeID,:address,:burstlength,:thread,:channel,:bank,:row,:column,:command,:dataStrobeBegin,:dataStrobeEnd)";
|
|
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,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, updateDataStrobeString.c_str(), -1, &updateDataStrobeStatement, 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,
|
|
core::Configuration::getInstance().NumberOfBanks);
|
|
sqlite3_bind_text(insertGeneralInfoStatement, 4, "", 0, NULL);
|
|
sqlite3_bind_int(insertGeneralInfoStatement, 5, core::Configuration::getInstance().Timings.clk.value());
|
|
sqlite3_bind_text(insertGeneralInfoStatement, 6, "PS", 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_int(insertTransactionStatement, 4, trans.get_streaming_width());
|
|
sqlite3_bind_text(insertTransactionStatement, 10,
|
|
trans.get_command() == tlm::TLM_READ_COMMAND ? "R" : "W", 1, 0);
|
|
|
|
const DramExtension& extension = DramExtension::getExtension(trans);
|
|
sqlite3_bind_int(insertTransactionStatement, 5, extension.getThread().ID());
|
|
sqlite3_bind_int(insertTransactionStatement, 6, extension.getChannel().ID());
|
|
sqlite3_bind_int(insertTransactionStatement, 7, extension.getBank().ID());
|
|
sqlite3_bind_int(insertTransactionStatement, 8, extension.getRow().ID());
|
|
sqlite3_bind_int(insertTransactionStatement, 9, extension.getColumn().ID());
|
|
sqlite3_bind_int(insertTransactionStatement, 10, 0);
|
|
sqlite3_bind_int(insertTransactionStatement, 11, 0);
|
|
|
|
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::updateDataStrobe(const sc_time& begin,const sc_time& end, tlm::tlm_generic_payload& trans)
|
|
{
|
|
unsigned int id = getElementFromMap(currentTransactionsInSystem, &trans);
|
|
sqlite3_bind_int64(updateDataStrobeStatement, 1, begin.value());
|
|
sqlite3_bind_int64(updateDataStrobeStatement, 2, end.value());
|
|
sqlite3_bind_int(updateDataStrobeStatement, 3, id);
|
|
executeSqlStatement(updateDataStrobeStatement);
|
|
}
|
|
|
|
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);
|
|
}
|
|
else
|
|
{
|
|
reportFatal("Error in TraceRecorder", "Could not load sql script from " + filename);
|
|
return "";
|
|
}
|
|
}
|
|
|
|
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;
|
|
}
|
|
|