Added dependency visualizations.
This commit is contained in:
@@ -90,6 +90,7 @@ add_executable(TraceAnalyzer
|
||||
businessObjects/tracetestresults.cpp
|
||||
presentation/tracemetrictreewidget.cpp
|
||||
businessObjects/phases/phase.cpp
|
||||
businessObjects/phases/phasedependency.cpp
|
||||
presentation/tracedrawingproperties.cpp
|
||||
presentation/util/traceplotline.cpp
|
||||
presentation/util/traceplotlinecache.cpp
|
||||
|
||||
@@ -67,9 +67,22 @@ void Phase::draw(QPainter *painter, const QwtScaleMap &xMap,
|
||||
|
||||
for (auto line : getTracePlotLines(drawingProperties))
|
||||
{
|
||||
if (!line->isCollapsed())
|
||||
if (!line->isCollapsed()) {
|
||||
drawPhaseSymbol(span.Begin(), span.End(), line->getYVal(),
|
||||
drawingProperties.drawText, getPhaseSymbol(), painter, xMap, yMap);
|
||||
|
||||
if (getGranularity() == Granularity::Bankwise) {
|
||||
bool drawAllDependencies = false;
|
||||
bool drawDependencies = true;
|
||||
bool drawDependencyText = true;
|
||||
if (drawAllDependencies || (highlight && drawDependencies)) {
|
||||
drawPhaseDependencies(span.Begin(), span.End(), line->getYVal(),
|
||||
drawingProperties, drawDependencyText, painter, xMap, yMap);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
for (Timespan span : spansOnCommandBus)
|
||||
@@ -116,6 +129,45 @@ void Phase::drawPhaseSymbol(traceTime begin, traceTime end, double y,
|
||||
static_cast<int>(yVal + symbolHeight / 2)), TextPositioning::bottomRight);
|
||||
}
|
||||
|
||||
void Phase::drawPhaseDependencies(traceTime begin, traceTime end, double y, const TraceDrawingProperties &drawingProperties,
|
||||
bool drawtext, QPainter *painter, const QwtScaleMap &xMap,
|
||||
const QwtScaleMap &yMap) const
|
||||
{
|
||||
QPen pen;
|
||||
pen.setWidth(2);
|
||||
painter->setPen(pen);
|
||||
painter->setRenderHint(QPainter::Antialiasing);
|
||||
|
||||
double yVal = yMap.transform(y);
|
||||
double symbolHeight = yMap.transform(0) - yMap.transform(hexagonHeight);
|
||||
|
||||
traceTime offset = (begin == end) ? static_cast<traceTime>(0.05 * clk) : 0;
|
||||
|
||||
size_t invisibleDeps = 0;
|
||||
|
||||
QPoint depLineTo(static_cast<int>(xMap.transform(begin/* + (end + offset - begin)/4*/)), static_cast<int>(yVal));
|
||||
|
||||
for (auto dep : _dependencies) {
|
||||
bool visible = false;
|
||||
if (dep->isVisible()) {
|
||||
if (!dep->draw(depLineTo, drawingProperties, drawtext, painter, xMap, yMap) ) {
|
||||
invisibleDeps += 1;
|
||||
}
|
||||
|
||||
} else {
|
||||
invisibleDeps += 1;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
if (invisibleDeps > 0) {
|
||||
QPoint invisibleDepsPoint(static_cast<int>(xMap.transform(begin + (end + offset - begin)/2)), static_cast<int>(yVal + 0.1*symbolHeight));
|
||||
drawText(painter, QString(std::to_string(invisibleDeps).c_str()), invisibleDepsPoint, TextPositioning::centerCenter);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
QColor Phase::getColor(const TraceDrawingProperties &drawingProperties) const
|
||||
{
|
||||
switch (drawingProperties.colorGrouping) {
|
||||
@@ -197,3 +249,7 @@ std::vector<std::shared_ptr<TracePlotLine>> Phase::getTracePlotLines(const Trace
|
||||
% drawingProperties.banksPerGroup);
|
||||
}
|
||||
}
|
||||
|
||||
void Phase::addDependency(std::shared_ptr<PhaseDependency> dependency) {
|
||||
_dependencies.push_back(dependency);
|
||||
}
|
||||
|
||||
@@ -41,6 +41,7 @@
|
||||
#include "presentation/util/colorgenerator.h"
|
||||
#include "presentation/tracedrawingproperties.h"
|
||||
#include "businessObjects/timespan.h"
|
||||
#include "businessObjects/phases/phasedependency.h"
|
||||
#include <QString>
|
||||
#include <QPainter>
|
||||
#include <qwt_scale_map.h>
|
||||
@@ -75,6 +76,8 @@ public:
|
||||
}
|
||||
virtual QString Name() const = 0;
|
||||
|
||||
void addDependency(std::shared_ptr<PhaseDependency> dependency);
|
||||
|
||||
protected:
|
||||
ID id;
|
||||
Timespan span;
|
||||
@@ -82,6 +85,8 @@ protected:
|
||||
std::weak_ptr<Transaction> transaction;
|
||||
std::vector<Timespan> spansOnCommandBus;
|
||||
std::shared_ptr<Timespan> spanOnDataBus;
|
||||
std::vector<std::shared_ptr<PhaseDependency>> _dependencies;
|
||||
|
||||
double hexagonHeight;
|
||||
TextPositioning captionPosition;
|
||||
|
||||
@@ -94,6 +99,11 @@ protected:
|
||||
virtual void drawPhaseSymbol(traceTime begin, traceTime end, double y,
|
||||
bool drawtext, PhaseSymbol symbol, QPainter *painter, const QwtScaleMap &xMap,
|
||||
const QwtScaleMap &yMap) const;
|
||||
virtual void drawPhaseDependencies(traceTime begin, traceTime end, double y,
|
||||
const TraceDrawingProperties &drawingProperties,
|
||||
bool drawtext, QPainter *painter, const QwtScaleMap &xMap,
|
||||
const QwtScaleMap &yMap) const;
|
||||
|
||||
|
||||
virtual std::vector<std::shared_ptr<TracePlotLine>> getTracePlotLines(const TraceDrawingProperties &drawingProperties) const;
|
||||
|
||||
@@ -103,6 +113,8 @@ protected:
|
||||
{
|
||||
return Granularity::Bankwise;
|
||||
}
|
||||
|
||||
friend class PhaseDependency;
|
||||
};
|
||||
|
||||
class REQ : public Phase
|
||||
|
||||
@@ -0,0 +1,98 @@
|
||||
#include "phasedependency.h"
|
||||
#include "phase.h"
|
||||
#include <iostream>
|
||||
|
||||
PhaseDependency::PhaseDependency(DependencyType type, QString timeDependency, std::shared_ptr<Phase> dependency)
|
||||
{
|
||||
_type = type;
|
||||
_timeDependency = timeDependency;
|
||||
_dependency = dependency;
|
||||
}
|
||||
|
||||
PhaseDependency::PhaseDependency(DependencyType type, QString timeDependency)
|
||||
{
|
||||
_type = type;
|
||||
_timeDependency = timeDependency;
|
||||
_dependency = nullptr;
|
||||
_isInvisible = true;
|
||||
}
|
||||
|
||||
PhaseDependency::~PhaseDependency()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
bool PhaseDependency::draw(QPoint& end, const TraceDrawingProperties &drawingProperties,
|
||||
bool drawtext, QPainter *painter, const QwtScaleMap &xMap,
|
||||
const QwtScaleMap &yMap)
|
||||
{
|
||||
if (_isInvisible) return false;
|
||||
|
||||
traceTime depBegin = _dependency->span.Begin();
|
||||
traceTime depEnd = _dependency->span.End();
|
||||
|
||||
if (xMap.transform(depEnd) < 0) return false;
|
||||
|
||||
bool drawn = false;
|
||||
for (auto line : _dependency->getTracePlotLines(drawingProperties)) {
|
||||
if (!line->isCollapsed()) {
|
||||
_draw(end, line->getYVal(), drawingProperties, drawtext, painter, xMap, yMap);
|
||||
drawn = true;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
return drawn;
|
||||
}
|
||||
|
||||
void PhaseDependency::_draw(QPoint& end, double depY, const TraceDrawingProperties &drawingProperties,
|
||||
bool drawtext, QPainter *painter, const QwtScaleMap &xMap,
|
||||
const QwtScaleMap &yMap)
|
||||
{
|
||||
traceTime depBegin = _dependency->span.Begin();
|
||||
traceTime depEnd = _dependency->span.End();
|
||||
|
||||
traceTime depOffset = (depBegin == depEnd) ? static_cast<traceTime>(0.05 * _dependency->clk) : 0;
|
||||
|
||||
double depYVal = yMap.transform(depY);
|
||||
double depSymbolHeight = yMap.transform(0) - yMap.transform(_dependency->hexagonHeight);
|
||||
QPoint depLineFrom(static_cast<int>(xMap.transform(depBegin/* + (depEnd + depOffset - depBegin)/4*/)), static_cast<int>(depYVal));
|
||||
|
||||
QLineF line(depLineFrom, end);
|
||||
double angle = std::atan2(-line.dy(), line.dx());
|
||||
|
||||
qreal arrowSize = 10;
|
||||
QPointF arrowP1 = line.p2() - QPointF(sin(angle + M_PI / 3) * arrowSize, cos(angle + M_PI / 3) * arrowSize);
|
||||
QPointF arrowP2 = line.p2() - QPointF(sin(angle + M_PI - M_PI / 3) * arrowSize, cos(angle + M_PI - M_PI / 3) * arrowSize);
|
||||
QPolygonF arrowHead;
|
||||
arrowHead << line.p2() << arrowP1 << arrowP2;
|
||||
|
||||
QColor color = _dependency->getColor(drawingProperties);
|
||||
painter->setBrush(QBrush(color, _dependency->getBrushStyle()));
|
||||
|
||||
painter->drawLine(line);
|
||||
painter->drawPolygon(arrowHead);
|
||||
|
||||
if (drawtext) {
|
||||
QPoint textPosition(line.x1() + (line.x2() - line.x1()) / 2, line.y1() + (line.y2() - line.y1()) / 2);
|
||||
auto alignment = TextPositioning::topRight;
|
||||
|
||||
if (textPosition.y() == line.y1()) {
|
||||
alignment = TextPositioning::topCenter;
|
||||
|
||||
} else if (textPosition.x() == line.x1()) {
|
||||
if (line.y1() > line.y2()) {
|
||||
alignment = TextPositioning::bottomRight;
|
||||
}
|
||||
}
|
||||
|
||||
drawText(
|
||||
painter,
|
||||
_timeDependency,
|
||||
textPosition,
|
||||
alignment
|
||||
);
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,41 @@
|
||||
#pragma once
|
||||
|
||||
#include "presentation/tracedrawingproperties.h"
|
||||
#include "businessObjects/timespan.h"
|
||||
|
||||
#include <memory>
|
||||
#include <QStringList>
|
||||
#include <QString>
|
||||
#include <QPainter>
|
||||
#include <qwt_scale_map.h>
|
||||
|
||||
class Phase;
|
||||
|
||||
enum DependencyType {
|
||||
Bank, Rank, InterRank
|
||||
};
|
||||
|
||||
class PhaseDependency
|
||||
{
|
||||
public:
|
||||
PhaseDependency(DependencyType type, QString timeDependency, std::shared_ptr<Phase> dependency);
|
||||
PhaseDependency(DependencyType type, QString timeDependency);
|
||||
~PhaseDependency();
|
||||
|
||||
bool isVisible() { return !_isInvisible; }
|
||||
|
||||
bool draw(QPoint& end, const TraceDrawingProperties &drawingProperties,
|
||||
bool drawtext, QPainter *painter, const QwtScaleMap &xMap,
|
||||
const QwtScaleMap &yMap);
|
||||
|
||||
protected:
|
||||
DependencyType _type;
|
||||
QString _timeDependency;
|
||||
std::shared_ptr<Phase> _dependency;
|
||||
|
||||
bool _isInvisible = false;
|
||||
|
||||
void _draw(QPoint& end, double depY, const TraceDrawingProperties &drawingProperties,
|
||||
bool drawtext, QPainter *painter, const QwtScaleMap &xMap,
|
||||
const QwtScaleMap &yMap);
|
||||
};
|
||||
@@ -42,6 +42,7 @@
|
||||
struct TransactionQueryTexts {
|
||||
QString queryHead;
|
||||
QString selectTransactionsByTimespan, selectTransactionById;
|
||||
QString checkDependenciesExist, selectDependenciesByTimespan;
|
||||
|
||||
TransactionQueryTexts()
|
||||
{
|
||||
@@ -53,6 +54,13 @@ struct TransactionQueryTexts {
|
||||
" WHERE Ranges.end >= :begin AND Ranges.begin <= :end";
|
||||
selectTransactionById = queryHead + " WHERE Transactions.ID = :id";
|
||||
|
||||
checkDependenciesExist = "SELECT CASE WHEN 0 < (SELECT count(*) FROM sqlite_master WHERE type = 'table' AND name = 'DirectDependencies') THEN 1 ELSE 0 END AS result";
|
||||
selectDependenciesByTimespan = "WITH timespanTransactions AS (" + selectTransactionsByTimespan +
|
||||
") SELECT * from DirectDependencies WHERE DelayedPhaseID IN ("
|
||||
" SELECT DirectDependencies.DelayedPhaseID FROM DirectDependencies JOIN timespanTransactions "
|
||||
" ON DirectDependencies.DelayedPhaseID = timespanTransactions.PhaseID )";
|
||||
|
||||
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
@@ -85,6 +85,12 @@ void TraceDB::prepareQueries()
|
||||
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");
|
||||
|
||||
checkDependenciesExist = QSqlQuery(database);
|
||||
checkDependenciesExist.prepare(queryTexts.checkDependenciesExist);
|
||||
selectDependenciesByTimespan = QSqlQuery(database);
|
||||
selectDependenciesByTimespan.prepare(queryTexts.selectDependenciesByTimespan);
|
||||
|
||||
}
|
||||
|
||||
void TraceDB::updateComments(const std::vector<CommentModel::Comment> &comments)
|
||||
@@ -133,9 +139,25 @@ vector<shared_ptr<Transaction>> TraceDB::getTransactionsInTimespan(
|
||||
selectTransactionsByTimespan.bindValue(":begin", span.Begin());
|
||||
selectTransactionsByTimespan.bindValue(":end", span.End());
|
||||
executeQuery(selectTransactionsByTimespan);
|
||||
return parseTransactionsFromQuery(selectTransactionsByTimespan);
|
||||
return parseTransactionsFromQuery(selectTransactionsByTimespan, true);
|
||||
}
|
||||
|
||||
void TraceDB::updateDependenciesInTimespan(const Timespan &span)
|
||||
{
|
||||
executeQuery(checkDependenciesExist);
|
||||
if (checkDependenciesExist.next()) {
|
||||
|
||||
if (checkDependenciesExist.value(0).toInt() == 1) {
|
||||
selectDependenciesByTimespan.bindValue(":begin", span.Begin());
|
||||
selectDependenciesByTimespan.bindValue(":end", span.End());
|
||||
executeQuery(selectDependenciesByTimespan);
|
||||
_updateDependenciesFromQuery(selectDependenciesByTimespan);
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
//TODO Remove exception
|
||||
shared_ptr<Transaction> TraceDB::getTransactionByID(ID id)
|
||||
@@ -381,8 +403,13 @@ shared_ptr<Transaction> TraceDB::parseTransactionFromQuery(QSqlQuery &query)
|
||||
}
|
||||
|
||||
vector<shared_ptr<Transaction>> TraceDB::parseTransactionsFromQuery(
|
||||
QSqlQuery &query)
|
||||
QSqlQuery &query,
|
||||
bool updateVisiblePhases)
|
||||
{
|
||||
if (updateVisiblePhases) {
|
||||
_visiblePhases.clear();
|
||||
}
|
||||
|
||||
vector<shared_ptr<Transaction>> result;
|
||||
|
||||
bool firstIteration = true;
|
||||
@@ -416,12 +443,68 @@ vector<shared_ptr<Transaction>> TraceDB::parseTransactionsFromQuery(
|
||||
unsigned int phaseID = query.value(14).toInt();
|
||||
QString phaseName = query.value(15).toString();
|
||||
Timespan span(query.value(16).toLongLong(), query.value(17).toLongLong());
|
||||
result.at(result.size() - 1)->addPhase(PhaseFactory::CreatePhase(phaseID,
|
||||
phaseName, span, result.at(result.size() - 1), *this));
|
||||
auto phase = PhaseFactory::CreatePhase(phaseID, phaseName, span, result.at(result.size() - 1), *this);
|
||||
result.at(result.size() - 1)->addPhase(phase);
|
||||
|
||||
if (updateVisiblePhases) {
|
||||
_visiblePhases[phaseID] = phase;
|
||||
}
|
||||
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
void TraceDB::_updateDependenciesFromQuery(QSqlQuery &query) {
|
||||
DependencyType type;
|
||||
while(query.next()) {
|
||||
ID delayedID = query.value(0).toInt();
|
||||
ID dependencyID = query.value(4).toInt();
|
||||
|
||||
QString dependencyTypeStr = query.value(2).toString();
|
||||
if (dependencyTypeStr == "bank") {
|
||||
type = DependencyType::Bank;
|
||||
} else if (dependencyTypeStr == "rank") {
|
||||
type = DependencyType::Rank;
|
||||
} else if (dependencyTypeStr == "interRank") {
|
||||
type = DependencyType::InterRank;
|
||||
}
|
||||
|
||||
QString timeDependencyStr = query.value(3).toString();
|
||||
|
||||
if (_visiblePhases.count(delayedID) > 0) {
|
||||
|
||||
if (_visiblePhases.count(dependencyID) > 0) {
|
||||
|
||||
_visiblePhases[delayedID]->addDependency(
|
||||
std::shared_ptr<PhaseDependency>(
|
||||
new PhaseDependency(
|
||||
type,
|
||||
timeDependencyStr,
|
||||
_visiblePhases[dependencyID]
|
||||
)
|
||||
)
|
||||
);
|
||||
|
||||
} else {
|
||||
|
||||
_visiblePhases[delayedID]->addDependency(
|
||||
std::shared_ptr<PhaseDependency>(
|
||||
new PhaseDependency(
|
||||
type,
|
||||
timeDependencyStr
|
||||
)
|
||||
)
|
||||
);
|
||||
|
||||
}
|
||||
|
||||
} else {
|
||||
// TODO delayed phase not visible?
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
vector<CommentModel::Comment> TraceDB::parseCommentsFromQuery(QSqlQuery &query)
|
||||
{
|
||||
vector<CommentModel::Comment> result;
|
||||
|
||||
@@ -71,6 +71,7 @@ public:
|
||||
|
||||
void updateComments(const std::vector<CommentModel::Comment> &comments);
|
||||
void updateFileDescription(const QString &description);
|
||||
void updateDependenciesInTimespan(const Timespan &span);
|
||||
void refreshData();
|
||||
|
||||
const GeneralInfo &getGeneralInfo() const
|
||||
@@ -95,6 +96,7 @@ public:
|
||||
// std::shared_ptr<Transaction> getNextActb(ID currentTransactionId);
|
||||
// std::shared_ptr<Transaction> getNextRefb(ID currentTransactionId);
|
||||
|
||||
void _updateDependenciesFromQuery(QSqlQuery &query);
|
||||
|
||||
std::shared_ptr<Transaction> getTransactionByID(ID id);
|
||||
ID getTransactionIDFromPhaseID(ID phaseID);
|
||||
@@ -118,6 +120,8 @@ private:
|
||||
QSqlQuery selectTransactionById;
|
||||
QSqlQuery selectDebugMessagesByTimespan;
|
||||
QSqlQuery selectDebugMessagesByTimespanWithLimit;
|
||||
QSqlQuery checkDependenciesExist;
|
||||
QSqlQuery selectDependenciesByTimespan;
|
||||
|
||||
TransactionQueryTexts queryTexts;
|
||||
void prepareQueries();
|
||||
@@ -125,7 +129,8 @@ private:
|
||||
QString queryToString(QSqlQuery query);
|
||||
std::shared_ptr<Transaction> parseTransactionFromQuery(QSqlQuery &query);
|
||||
std::vector<std::shared_ptr<Transaction>> parseTransactionsFromQuery(
|
||||
QSqlQuery &query);
|
||||
QSqlQuery &query,
|
||||
bool updateVisiblePhases = false);
|
||||
std::vector<CommentModel::Comment> parseCommentsFromQuery(QSqlQuery &query);
|
||||
|
||||
void executeScriptFile(QString fileName);
|
||||
@@ -135,6 +140,8 @@ private:
|
||||
GeneralInfo *getGeneralInfoFromDB();
|
||||
CommandLengths getCommandLengthsFromDB();
|
||||
unsigned int getLengthOfCommandFromDB(const std::string& command);
|
||||
|
||||
std::map<unsigned int, std::shared_ptr<Phase>> _visiblePhases; // Updated at parseTransactionsFromQuery
|
||||
};
|
||||
|
||||
|
||||
|
||||
@@ -57,6 +57,7 @@ MainWindow::MainWindow(QWidget *parent) :
|
||||
traceNavigator->GeneralTraceInfo().TraceSpan());
|
||||
transactions = db->getTransactionsInTimespan(
|
||||
traceNavigator->GeneralTraceInfo().TraceSpan());
|
||||
db->updateDependenciesInTimespan(traceNavigator->GeneralTraceInfo().TraceSpan());
|
||||
|
||||
ui->qwtPlot->setAxisScale(QwtPlot::xBottom,
|
||||
traceNavigator->GeneralTraceInfo().TraceSpan().Begin(),
|
||||
|
||||
@@ -448,6 +448,8 @@ void TracePlot::currentTraceTimeChanged()
|
||||
{
|
||||
transactions = navigator->TraceFile().getTransactionsInTimespan(
|
||||
GetCurrentTimespan());
|
||||
navigator->TraceFile().updateDependenciesInTimespan(GetCurrentTimespan());
|
||||
|
||||
setAxisScale(xBottom, GetCurrentTimespan().Begin(), GetCurrentTimespan().End());
|
||||
replot();
|
||||
}
|
||||
|
||||
@@ -196,6 +196,8 @@ void TraceScroller::currentTraceTimeChanged()
|
||||
canvasClip->setInterval(spanOnTracePlot.Begin(), spanOnTracePlot.End());
|
||||
Timespan span = GetCurrentTimespan();
|
||||
transactions = navigator->TraceFile().getTransactionsInTimespan(span);
|
||||
navigator->TraceFile().updateDependenciesInTimespan(span);
|
||||
|
||||
setAxisScale(xBottom, span.Begin(), span.End());
|
||||
replot();
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user