Files
DRAMSys/DRAMSys/traceAnalyzer/data/tracedb.cpp
Éder F. Zulian a787b7bb5b coding style
2018-07-03 10:59:20 +02:00

438 lines
15 KiB
C++

/*
* Copyright (c) 2015, 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:
* Janik Schlemminger
* Robert Gernhardt
* Matthias Jung
*/
#include<QString>
#include<QFile>
#include<QStringList>
#include<QTextStream>
#include<QSqlError>
#include<iostream>
#include <QFileInfo>
#include"data/tracedb.h"
#include"businessObjects/comment.h"
#include "businessObjects/phases/phasefactory.h"
//define symbol printqueries if all queries should be printed to the console
#define printqueries
using namespace std;
TraceDB::TraceDB(QString path, bool openExisting)
{
this->pathToDB = path;
database = QSqlDatabase::database(path);
if (database.isValid() && database.isOpen()) {
// Close the database connection if it exists and was not closed yet.
database.removeDatabase(path);
database.close();
}
database = QSqlDatabase::addDatabase("QSQLITE", path);
database.setDatabaseName(path);
database.open();
if (!openExisting)
dropAndCreateTables();
prepareQueries();
generalInfo = getGeneralInfoFromDB();
}
void TraceDB::prepareQueries()
{
selectTransactionsByTimespan = QSqlQuery(database);
selectTransactionsByTimespan.prepare(queryTexts.selectTransactionsByTimespan);
selectTransactionById = QSqlQuery(database);
selectTransactionById.prepare(queryTexts.selectTransactionById);
selectDebugMessagesByTimespan = QSqlQuery(database);
selectDebugMessagesByTimespan.prepare("SELECT time, Message FROM DebugMessages WHERE :begin <= time AND time <= :end ");
selectDebugMessagesByTimespanWithLimit = QSqlQuery(database);
selectDebugMessagesByTimespanWithLimit.prepare("SELECT time, Message FROM DebugMessages WHERE :begin <= time AND time <= :end LIMIT :limit");
}
void TraceDB::updateComments(vector<Comment> comments)
{
QSqlQuery query(database);
query.prepare("DELETE FROM Comments");
executeQuery(query);
query.prepare("insert into Comments values(:time,:text)");
for (const Comment &comment : comments) {
query.bindValue(":time", comment.Time());
query.bindValue(":text", comment.Text());
executeQuery(query);
}
}
void TraceDB::updateFileDescription(const QString &description)
{
QSqlQuery query(database);
query.prepare("UPDATE GeneralInfo SET Description=:description");
query.bindValue(":description", description);
executeQuery(query);
}
void TraceDB::refreshData()
{
generalInfo = getGeneralInfoFromDB();
}
//QueryText must select the fields
//TransactionID, Ranges.begin, Ranges.end, Address, TThread, TChannel, TBank, TRow, TColumn, Phases.ID AS PhaseID, PhaseName, PhaseBegin, PhaseEnd
vector<shared_ptr<Transaction>> TraceDB::getTransactionsWithCustomQuery(
QString queryText)
{
QSqlQuery query(database);
query.prepare(queryText);
executeQuery(query);
return parseTransactionsFromQuery(query);
}
vector<shared_ptr<Transaction>> TraceDB::getTransactionsInTimespan(
const Timespan &span)
{
selectTransactionsByTimespan.bindValue(":begin", span.Begin());
selectTransactionsByTimespan.bindValue(":end", span.End());
executeQuery(selectTransactionsByTimespan);
return parseTransactionsFromQuery(selectTransactionsByTimespan);
}
//TODO Remove exception
shared_ptr<Transaction> TraceDB::getTransactionByID(ID id)
{
selectTransactionById.bindValue(":id", id);
executeQuery(selectTransactionById);
auto result = parseTransactionsFromQuery(selectTransactionById);
if (!result.empty())
return result[0];
else
throw sqlException(("Transaction with ID " + QString::number(
id) + " not in DB").toStdString(), this->pathToDB.toStdString());
}
shared_ptr<Transaction> TraceDB::getNextActivate(ID currentTransactionId)
{
QSqlQuery query(database);
QString queryText = queryTexts.queryHead +
"WHERE TransactionID > :currentID AND PhaseName = 'ACT' LIMIT 1";
query.prepare(queryText);
query.bindValue(":currentID", currentTransactionId);
executeQuery(query);
return parseTransactionFromQuery(query);
}
shared_ptr<Transaction> TraceDB::getNextPrecharge(ID currentTransactionId)
{
QSqlQuery query(database);
QString queryText = queryTexts.queryHead +
"WHERE TransactionID > :currentID AND PhaseName IN ('PRE','PRE_ALL') LIMIT 1";
query.prepare(queryText);
query.bindValue(":currentID", currentTransactionId);
executeQuery(query);
return parseTransactionFromQuery(query);
}
shared_ptr<Transaction> TraceDB::getNextActb(ID currentTransactionId)
{
QSqlQuery query(database);
QString queryText = queryTexts.queryHead +
"WHERE TransactionID > :currentID AND PhaseName = 'ACTB' LIMIT 1";
query.prepare(queryText);
query.bindValue(":currentID", currentTransactionId);
executeQuery(query);
return parseTransactionFromQuery(query);
}
shared_ptr<Transaction> TraceDB::getNextPreb(ID currentTransactionId)
{
QSqlQuery query(database);
QString queryText = queryTexts.queryHead +
"WHERE TransactionID > :currentID AND PhaseName = 'PREB' LIMIT 1";
query.prepare(queryText);
query.bindValue(":currentID", currentTransactionId);
executeQuery(query);
return parseTransactionFromQuery(query);
}
shared_ptr<Transaction> TraceDB::getNextRefresh(ID currentTransactionId)
{
QSqlQuery query(database);
QString queryText = queryTexts.queryHead +
"WHERE TransactionID > :currentID AND PhaseName IN ('REFA') LIMIT 1";
query.prepare(queryText);
query.bindValue(":currentID", currentTransactionId);
executeQuery(query);
return parseTransactionFromQuery(query);
}
shared_ptr<Transaction> TraceDB::getNextRefb(ID currentTransactionId)
{
QSqlQuery query(database);
QString queryText = queryTexts.queryHead +
"WHERE TransactionID > :currentID AND PhaseName = 'REFB' LIMIT 1";
query.prepare(queryText);
query.bindValue(":currentID", currentTransactionId);
executeQuery(query);
return parseTransactionFromQuery(query);
}
ID TraceDB::getTransactionIDFromPhaseID(ID phaseID)
{
QSqlQuery query(database);
query.prepare("SELECT Transact FROM Phases WHERE ID=:id");
query.bindValue(":id", phaseID);
executeQuery(query);
if (query.next()) {
return query.value(0).toInt();
} else {
throw sqlException("Phase with ID " + to_string(phaseID) + " not in db",
this->pathToDB.toStdString());
}
}
GeneralInfo TraceDB::getGeneralInfoFromDB()
{
QSqlQuery query(database);
query.prepare("SELECT NumberOfTransactions,TraceEnd,NumberOfBanks,Clk,UnitOfTime,Traces,Memspec,MCconfig, WindowSize, ControllerThread FROM GeneralInfo");
executeQuery(query);
if (query.next()) {
unsigned int numberOfTransactions = query.value(0).toInt();
traceTime traceEnd = query.value(1).toLongLong();
unsigned int numberOfBanks = query.value(2).toInt();
unsigned int clkPeriod = query.value(3).toInt();
QString unitOfTime = query.value(4).toString();
unsigned int numberOfPhases = getNumberOfPhases();
QString traces = "Traces: " + query.value(5).toString();
QString memspec = "Memspec: " + query.value(6).toString();
QString mcconfig = "MCconfig: " + query.value(7).toString();
unsigned int windowSize = query.value(8).toInt();
unsigned int controllerThread = query.value(9).toUInt();
QString description = (traces + "\n");
description += mcconfig + "\n";
description += memspec + "\n";
description += "Number of Transactions: " + QString::number(
numberOfTransactions) + "\n";
description += "Clock period: " + QString::number(clkPeriod) + " " + unitOfTime
+ "\n";
description += "Length of trace: " + prettyFormatTime(traceEnd) + "\n";
description += "Window size:" + QString::number(windowSize) + "\n";
return GeneralInfo(numberOfTransactions, numberOfPhases, Timespan(0, traceEnd),
numberOfBanks, description, unitOfTime, clkPeriod, windowSize,
controllerThread);
} else {
throw sqlException("Tracefile corrupted. No general info table",
this->pathToDB.toStdString());
}
}
unsigned int TraceDB::getNumberOfPhases()
{
QSqlQuery query(database);
query.prepare("SELECT COUNT(ID) FROM Phases");
executeQuery(query);
query.next();
return query.value(0).toInt();
}
vector<Comment> TraceDB::getComments()
{
QSqlQuery query(database);
query.prepare("SELECT Time,Text From Comments");
executeQuery(query);
return parseCommentsFromQuery(query);
}
vector<Comment> TraceDB::getDebugMessagesInTimespan(const Timespan &span)
{
selectDebugMessagesByTimespan.bindValue(":begin", span.Begin());
selectDebugMessagesByTimespan.bindValue(":end", span.End());
executeQuery(selectDebugMessagesByTimespan);
return parseCommentsFromQuery(selectDebugMessagesByTimespan);
}
vector<Comment> TraceDB::getDebugMessagesInTimespan(const Timespan &span,
unsigned int limit = 50)
{
selectDebugMessagesByTimespanWithLimit.bindValue(":begin", span.Begin());
selectDebugMessagesByTimespanWithLimit.bindValue(":end", span.End());
selectDebugMessagesByTimespanWithLimit.bindValue(":limit", limit);
executeQuery(selectDebugMessagesByTimespanWithLimit);
return parseCommentsFromQuery(selectDebugMessagesByTimespanWithLimit);
}
/* Helpers
*
*
*
*/
shared_ptr<Transaction> TraceDB::parseTransactionFromQuery(QSqlQuery &query)
{
auto result = parseTransactionsFromQuery(query);
if (!result.empty())
return result[0];
else
return shared_ptr<Transaction>();
}
vector<shared_ptr<Transaction>> TraceDB::parseTransactionsFromQuery(
QSqlQuery &query)
{
vector<shared_ptr<Transaction>> result;
bool firstIteration = true;
ID currentID = 0;
int i = -1;
while (query.next()) {
ID id = query.value(0).toInt();
if (currentID != id || firstIteration) {
++i;
firstIteration = false;
currentID = id;
Timespan span(query.value(1).toLongLong(), query.value(2).toLongLong());
Timespan spanOnStrobe(query.value(3).toLongLong(), query.value(4).toLongLong());
unsigned int address = query.value(5).toInt();
unsigned int burstlength = query.value(6).toInt();
unsigned int thread = query.value(7).toInt();
unsigned int channel = query.value(8).toInt();
unsigned int bank = query.value(9).toInt();
unsigned int bankgroup = query.value(10).toInt();
unsigned int row = query.value(11).toInt();
unsigned int column = query.value(12).toInt();
result.push_back(shared_ptr<Transaction>(new Transaction(id, address,
burstlength, thread, channel, bank, bankgroup, row, column, span,
spanOnStrobe)));
}
unsigned int phaseID = query.value(13).toInt();
QString phaseName = query.value(14).toString();
Timespan span(query.value(15).toLongLong(), query.value(16).toLongLong());
result.at(result.size() - 1)->addPhase(PhaseFactory::CreatePhase(phaseID,
phaseName, span, result.at(result.size() - 1), *this));
}
return result;
}
vector<Comment> TraceDB::parseCommentsFromQuery(QSqlQuery &query)
{
vector<Comment> result;
while (query.next()) {
result.push_back(Comment(query.value(0).toLongLong(),
query.value(1).toString()));
}
return result;
}
void TraceDB::executeQuery(QSqlQuery query)
{
//query.exec returns bool indicating if the query was sucessfull
if (query.exec()) {
#ifdef printqueries
cout << queryToString(query).toStdString() << endl;
#endif
}
else {
throw sqlException( ("Query:\n " + queryToString(query) + "\n failed. Error: \n"
+
query.lastError().text()).toStdString(), this->pathToDB.toStdString());
}
}
QString TraceDB::queryToString(QSqlQuery query)
{
QString str = query.lastQuery();
QMapIterator<QString, QVariant> it(query.boundValues());
while (it.hasNext()) {
it.next();
str.replace(it.key(), it.value().toString());
}
return str;
}
void TraceDB::dropAndCreateTables()
{
executeScriptFile("common/static/createTraceDB.sql");
}
void TraceDB::executeScriptFile(QString fileName)
{
QSqlQuery query(database);
QFile scriptFile(fileName);
if (scriptFile.open(QIODevice::ReadOnly)) {
// The SQLite driver executes only a single (the first) query in the QSqlQuery
// if the script contains more queries, it needs to be splitted.
QStringList scriptQueries = QTextStream(&scriptFile).readAll().split(';');
for (QString &queryTxt : scriptQueries) {
if (queryTxt.trimmed().isEmpty()) {
continue;
}
if (!query.exec(queryTxt)) {
throw sqlException("Querry failed:" + query.lastError().text().toStdString(),
this->pathToDB.toStdString());
}
query.finish();
}
}
}