summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJames Benton <jbenton@vmware.com>2012-08-28 18:41:43 +0100
committerJames Benton <jbenton@vmware.com>2012-08-28 18:41:43 +0100
commitb70a86af10057c5b7fcf79b674cfe5abbeaadebb (patch)
treebbadcb08f6009acea75106aff2ae484f4955d06a
parent56ea30956b10d22fc78d120f5506f352cfecd3cd (diff)
Combine timeline and histogram tabs.
Synchronise time / program selections between all profile data views.
-rw-r--r--common/trace_profiler.cpp9
-rw-r--r--common/trace_profiler.hpp2
-rw-r--r--gui/graphwidget.cpp355
-rw-r--r--gui/graphwidget.h60
-rw-r--r--gui/profiledialog.cpp110
-rw-r--r--gui/profiledialog.h4
-rw-r--r--gui/profiletablemodel.cpp54
-rw-r--r--gui/profiletablemodel.h7
-rw-r--r--gui/timelinewidget.cpp515
-rw-r--r--gui/timelinewidget.h43
-rw-r--r--gui/ui/profiledialog.ui529
11 files changed, 1200 insertions, 488 deletions
diff --git a/common/trace_profiler.cpp b/common/trace_profiler.cpp
index 402cdacc..0f90ee27 100644
--- a/common/trace_profiler.cpp
+++ b/common/trace_profiler.cpp
@@ -145,7 +145,6 @@ void Profiler::parseLine(const char* in, Profile* profile)
if (type.compare("call") == 0) {
Profile::Call call;
- unsigned programNo;
line >> call.no
>> call.gpuStart
@@ -153,7 +152,7 @@ void Profiler::parseLine(const char* in, Profile* profile)
>> call.cpuStart
>> call.cpuDuration
>> call.pixels
- >> programNo
+ >> call.program
>> call.name;
if (lastGpuTime < call.gpuStart + call.gpuDuration) {
@@ -167,11 +166,11 @@ void Profiler::parseLine(const char* in, Profile* profile)
profile->calls.push_back(call);
if (call.pixels >= 0) {
- if (profile->programs.size() <= programNo) {
- profile->programs.resize(programNo + 1);
+ if (profile->programs.size() <= call.program) {
+ profile->programs.resize(call.program + 1);
}
- Profile::Program& program = profile->programs[programNo];
+ Profile::Program& program = profile->programs[call.program];
program.cpuTotal += call.cpuDuration;
program.gpuTotal += call.gpuDuration;
program.pixelTotal += call.pixels;
diff --git a/common/trace_profiler.hpp b/common/trace_profiler.hpp
index 8463c61f..d8332420 100644
--- a/common/trace_profiler.hpp
+++ b/common/trace_profiler.hpp
@@ -37,6 +37,8 @@ struct Profile {
struct Call {
unsigned no;
+ unsigned program;
+
int64_t gpuStart;
int64_t gpuDuration;
diff --git a/gui/graphwidget.cpp b/gui/graphwidget.cpp
index 401c0346..ea0f6a72 100644
--- a/gui/graphwidget.cpp
+++ b/gui/graphwidget.cpp
@@ -21,15 +21,20 @@ GraphWidget::GraphWidget(QWidget *parent)
m_axisForeground(Qt::black),
m_axisBackground(Qt::lightGray)
{
- setBackgroundRole(QPalette::Base);
- setAutoFillBackground(true);
- setMouseTracking(true);
+ m_selection.type = SelectNone;
+
+ m_graphGradientGpu.setColorAt(0.9, QColor(210, 0, 0));
+ m_graphGradientGpu.setColorAt(0.0, QColor(255, 130, 130));
- m_graphGradientGpu.setColorAt(0.9, QColor(255, 0, 0));
- m_graphGradientGpu.setColorAt(0.0, QColor(255, 200, 200));
+ m_graphGradientCpu.setColorAt(0.9, QColor(0, 0, 210));
+ m_graphGradientCpu.setColorAt(0.0, QColor(130, 130, 255));
- m_graphGradientCpu.setColorAt(0.9, QColor(0, 0, 255));
- m_graphGradientCpu.setColorAt(0.0, QColor(200, 200, 255));
+ m_graphGradientDeselected.setColorAt(0.9, QColor(200, 200, 200));
+ m_graphGradientDeselected.setColorAt(0.0, QColor(220, 220, 220));
+
+ setMouseTracking(true);
+ setAutoFillBackground(true);
+ setBackgroundRole(QPalette::Base);
}
@@ -40,35 +45,84 @@ void GraphWidget::setProfile(trace::Profile* profile, GraphType type)
{
m_type = type;
m_profile = profile;
- m_maxTime = 0;
+ m_timeMax = 0;
/* Find longest call to use as y axis */
if (m_type == GraphGpu) {
for (std::vector<Call>::const_iterator itr = m_profile->calls.begin(); itr != m_profile->calls.end(); ++itr) {
const Call& call = *itr;
- if (call.gpuDuration > m_maxTime) {
- m_maxTime = call.gpuDuration;
+ if (call.gpuDuration > m_timeMax) {
+ m_timeMax = call.gpuDuration;
}
}
} else {
for (std::vector<Call>::const_iterator itr = m_profile->calls.begin(); itr != m_profile->calls.end(); ++itr) {
const Call& call = *itr;
- if (call.cpuDuration > m_maxTime) {
- m_maxTime = call.cpuDuration;
+ if (call.cpuDuration > m_timeMax) {
+ m_timeMax = call.cpuDuration;
}
}
}
- m_minCall = 0;
- m_maxCall = m_profile->calls.size();
+ m_callMin = 0;
+ m_callMax = m_profile->calls.size();
- m_minCallWidth = 10;
- m_maxCallWidth = m_maxCall - m_minCall;
+ m_callWidthMin = 10;
+ m_callWidthMax = m_callMax - m_callMin;
- m_call = m_minCall;
- m_callWidth = m_maxCallWidth;
+ m_call = m_callMin;
+ m_callWidth = m_callWidthMax;
+
+ selectNone();
+ update();
+}
+
+
+/**
+ * Set selection to nothing
+ */
+void GraphWidget::selectNone(bool notify)
+{
+ m_selection.type = SelectNone;
+
+ if (notify) {
+ emit selectedNone();
+ }
+
+ update();
+}
+
+
+/**
+ * Set selection to a time period
+ */
+void GraphWidget::selectTime(int64_t start, int64_t end, bool notify)
+{
+ m_selection.timeStart = start;
+ m_selection.timeEnd = end;
+ m_selection.type = (start == end) ? SelectNone : SelectTime;
+
+ if (notify) {
+ emit selectedTime(start, end);
+ }
+
+ update();
+}
+
+
+/**
+ * Set selection to a program
+ */
+void GraphWidget::selectProgram(unsigned program, bool notify)
+{
+ m_selection.program = program;
+ m_selection.type = SelectProgram;
+
+ if (notify) {
+ emit selectedProgram(program);
+ }
update();
}
@@ -90,22 +144,22 @@ void GraphWidget::changeView(int call, int width)
*/
void GraphWidget::update()
{
- m_maxTime = 0;
+ m_timeMax = 0;
if (m_type == GraphGpu) {
for (int i = m_call; i < m_call + m_callWidth; ++i) {
const Call& call = m_profile->calls[i];
- if (call.gpuDuration > m_maxTime) {
- m_maxTime = call.gpuDuration;
+ if (call.gpuDuration > m_timeMax) {
+ m_timeMax = call.gpuDuration;
}
}
} else {
for (int i = m_call; i < m_call + m_callWidth; ++i) {
const Call& call = m_profile->calls[i];
- if (call.cpuDuration > m_maxTime) {
- m_maxTime = call.cpuDuration;
+ if (call.cpuDuration > m_timeMax) {
+ m_timeMax = call.cpuDuration;
}
}
}
@@ -129,15 +183,15 @@ const Call* GraphWidget::callAtPosition(const QPoint& pos)
int posX = qMax(0, pos.x() - m_axisWidth);
int posY = qMax(0, pos.y() - m_axisHeight);
- time = ((m_graphHeight - posY) / (double)m_graphHeight) * m_maxTime;
- time -= (2 * m_maxTime) / m_graphHeight;
+ time = ((m_graphHeight - posY) / (double)m_graphHeight) * m_timeMax;
+ time -= (2 * m_timeMax) / m_graphHeight;
size = m_callWidth / (double)m_graphWidth;
left = m_call + (posX / (double)m_graphWidth) * m_callWidth;
- left = qMax(m_minCall, left - size);
+ left = qMax(m_callMin, left - size);
- right = qMin(m_maxCall - 1, left + size * 2);
+ right = qMin(m_callMax - 1, left + size * 2);
if (m_type == GraphGpu) {
const Call* longest = NULL;
@@ -184,26 +238,71 @@ void GraphWidget::mousePressEvent(QMouseEvent *e)
}
-void GraphWidget::mouseMoveEvent(QMouseEvent *e)
+void GraphWidget::mouseReleaseEvent(QMouseEvent *e)
{
if (!m_profile) {
return;
}
- if (e->pos().x() < m_axisWidth || e->pos().y() < m_axisHeight) {
+ if (e->button() == Qt::LeftButton) {
+ int dxy = qAbs(m_mousePressPosition.x() - e->pos().x()) + qAbs(m_mousePressPosition.y() - e->pos().y());
+
+ if (dxy <= 2) {
+ int x = qMax(m_axisWidth, e->pos().x());
+ double dcdx = m_callWidth / (double)m_graphWidth;
+
+ int call = m_mousePressCall + dcdx * (x - m_axisWidth);
+
+ int64_t start = m_profile->calls[call].cpuStart;
+ int64_t end = m_profile->calls[call].cpuStart + m_profile->calls[call].cpuDuration;
+
+ if (start < m_selection.timeStart || end > m_selection.timeEnd) {
+ selectNone(true);
+ }
+ }
+ }
+}
+
+
+void GraphWidget::mouseDoubleClickEvent(QMouseEvent *e)
+{
+ const Call* call = callAtPosition(e->pos());
+
+ if (call) {
+ emit jumpToCall(call->no);
+ }
+}
+
+
+void GraphWidget::mouseMoveEvent(QMouseEvent *e)
+{
+ if (!m_profile) {
return;
}
if (e->buttons().testFlag(Qt::LeftButton)) {
- /* Horizontal scroll */
double dcdx = m_callWidth / (double)m_graphWidth;
- dcdx *= m_mousePressPosition.x() - e->pos().x();
- m_call = m_mousePressCall + dcdx;
- m_call = qBound(m_minCall, m_call, m_maxCall - m_callWidth);
+ if (m_mousePressPosition.y() > m_axisHeight) {
+ dcdx *= m_mousePressPosition.x() - e->pos().x();
+
+ /* Horizontal scroll */
+ m_call = m_mousePressCall + dcdx;
+ m_call = qBound(m_callMin, m_call, m_callMax - m_callWidth);
+
+ emit viewChanged(m_call, m_callWidth);
+ update();
+ } else {
+ int x = qMax(m_axisWidth, e->pos().x());
+
+ int down = m_mousePressCall + dcdx * (m_mousePressPosition.x() - m_axisWidth);
+ int up = m_mousePressCall + dcdx * (x - m_axisWidth);
- emit viewChanged(m_call, m_callWidth);
- update();
+ int left = qMax(qMin(down, up), 0);
+ int right = qMin<int>(qMax(down, up), m_profile->calls.size() - 1);
+
+ selectTime(m_profile->calls[left].cpuStart, m_profile->calls[right].cpuStart + m_profile->calls[right].cpuDuration, true);
+ }
}
const Call* call = callAtPosition(e->pos());
@@ -217,6 +316,7 @@ void GraphWidget::mouseMoveEvent(QMouseEvent *e)
if (call->pixels >= 0) {
text += QString("\nGPU Duration: %1").arg(getTimeString(call->gpuDuration));
text += QString("\nPixels Drawn: %1").arg(QLocale::system().toString((qlonglong)call->pixels));
+ text += QString("\nProgram: %1").arg(call->program);
}
QToolTip::showText(e->globalPos(), text);
@@ -232,7 +332,7 @@ void GraphWidget::wheelEvent(QWheelEvent *e)
return;
}
- if (e->pos().x() < m_axisWidth || e->pos().y() < m_axisHeight) {
+ if (e->pos().x() < m_axisWidth) {
return;
}
@@ -251,7 +351,7 @@ void GraphWidget::wheelEvent(QWheelEvent *e)
size /= 120 * (100 / zoomPercent);
m_callWidth += size;
- m_callWidth = qBound(m_minCallWidth, m_callWidth, m_maxCallWidth);
+ m_callWidth = qBound(m_callWidthMin, m_callWidth, m_callWidthMax);
/* Scroll view to zoom around mouse */
dt -= m_callWidth;
@@ -259,23 +359,13 @@ void GraphWidget::wheelEvent(QWheelEvent *e)
dt /= m_graphWidth;
m_call = dt + m_call;
- m_call = qBound(m_minCall, m_call, m_maxCall - m_callWidth);
+ m_call = qBound(m_callMin, m_call, m_callMax - m_callWidth);
emit viewChanged(m_call, m_callWidth);
update();
}
-void GraphWidget::mouseDoubleClickEvent(QMouseEvent *e)
-{
- const Call* call = callAtPosition(e->pos());
-
- if (call) {
- emit jumpToCall(call->no);
- }
-}
-
-
void GraphWidget::resizeEvent(QResizeEvent *e)
{
m_graphWidth = qMax(0, width() - m_axisWidth);
@@ -283,6 +373,7 @@ void GraphWidget::resizeEvent(QResizeEvent *e)
m_graphGradientGpu.setStart(0, m_graphHeight);
m_graphGradientCpu.setStart(0, m_graphHeight);
+ m_graphGradientDeselected.setStart(0, m_graphHeight);
}
@@ -294,16 +385,20 @@ void GraphWidget::paintVerticalAxis(QPainter& painter)
int height = painter.fontMetrics().height();
int ticks = m_graphHeight / (height * 2);
- double step = m_maxTime / (double)ticks;
+ double step = m_timeMax / (double)ticks;
double step10 = qPow(10.0, qFloor(qLn(step) / qLn(10.0)));
step = qFloor((step / step10) * 2) * (step10 / 2);
+ if (step <= 0) {
+ return;
+ }
+
painter.resetTransform();
painter.translate(0, m_axisHeight);
painter.setPen(m_axisForeground);
- for (double tick = 0; tick <= m_maxTime; tick += step) {
- int y = m_graphHeight - ((tick / m_maxTime) * m_graphHeight);
+ for (double tick = 0; tick <= m_timeMax; tick += step) {
+ int y = m_graphHeight - ((tick / m_timeMax) * m_graphHeight);
painter.drawLine(m_axisWidth - 8, y, m_axisWidth - 1, y);
@@ -312,7 +407,7 @@ void GraphWidget::paintVerticalAxis(QPainter& painter)
m_axisWidth - 10,
height,
Qt::AlignRight | Qt::AlignVCenter,
- getTimeString(tick, m_maxTime));
+ getTimeString(tick, m_timeMax));
}
}
@@ -395,7 +490,10 @@ void GraphWidget::paintEvent(QPaintEvent *e)
}
QPainter painter(this);
+ QBrush deselectBrush;
+ QPen deselectPen;
QBrush brush;
+ QPen pen;
/* Draw axes */
paintHorizontalAxis(painter);
@@ -412,81 +510,156 @@ void GraphWidget::paintEvent(QPaintEvent *e)
}
/* Draw graph */
+ deselectBrush = QBrush(m_graphGradientDeselected);
+
if (m_type == GraphGpu) {
brush = QBrush(m_graphGradientGpu);
} else {
brush = QBrush(m_graphGradientCpu);
}
+ pen = QPen(brush, 1);
+ deselectPen = QPen(deselectBrush, 1);
+
painter.setBrush(brush);
- painter.setPen(QPen(brush, 1));
+ painter.setPen(pen);
painter.translate(m_axisWidth, m_axisHeight);
double x = 0;
- double dydt = m_graphHeight / (double)m_maxTime;
+ double dydt = m_graphHeight / (double)m_timeMax;
double dxdc = m_graphWidth / (double)m_callWidth;
+ int selectLeft = m_call + m_callWidth;
+ int selectRight = -1;
+
+ if (m_selection.type == SelectProgram) {
+ painter.setPen(deselectPen);
+ }
+
if (dxdc < 1.0) {
- /* Less than 1 pixel per call, draw the longest call in a pixel */
- int64_t longest = 0;
+ /* Draw the longest call in a pixel */
+ int64_t selectedLongest = 0;
+ int64_t pixelLongest = 0;
int lastX = 0;
- if (m_type == GraphGpu) {
- for (int i = m_call; i < m_call + m_callWidth; ++i) {
- const Call& call = m_profile->calls[i];
+ for (int i = m_call; i < m_call + m_callWidth; ++i) {
+ const Call& call = m_profile->calls[i];
+ int ix;
- if (call.gpuDuration > longest) {
- longest = call.gpuDuration;
+ if (m_type == GraphGpu) {
+ if (call.gpuDuration > pixelLongest) {
+ pixelLongest = call.gpuDuration;
}
- x += dxdc;
+ if (m_selection.type == SelectProgram && call.program == m_selection.program) {
+ if (call.gpuDuration > selectedLongest) {
+ selectedLongest = call.gpuDuration;
+ }
+ }
+ } else {
+ if (call.cpuDuration > pixelLongest) {
+ pixelLongest = call.cpuDuration;
+ }
- if (lastX != (int)x) {
- painter.drawLine(lastX, m_graphHeight, lastX, m_graphHeight - (longest * dydt));
- longest = 0;
- lastX = x;
+ if (m_selection.type == SelectProgram && call.program == m_selection.program) {
+ if (call.cpuDuration > selectedLongest) {
+ selectedLongest = call.cpuDuration;
+ }
}
}
- } else {
- for (int i = m_call; i < m_call + m_callWidth; ++i) {
- const Call& call = m_profile->calls[i];
- if (call.cpuDuration > longest) {
- longest = call.cpuDuration;
+ x += dxdc;
+ ix = (int)x;
+
+ if (lastX != ix) {
+ if (m_selection.type == SelectTime) {
+ if (call.cpuStart < m_selection.timeStart || call.cpuStart > m_selection.timeEnd) {
+ painter.setPen(deselectPen);
+ } else {
+ if (ix < selectLeft) {
+ selectLeft = ix;
+ }
+
+ if (ix > selectRight) {
+ selectRight = ix;
+ }
+
+ painter.setPen(pen);
+ }
}
- x += dxdc;
+ painter.drawLine(lastX, m_graphHeight, lastX, m_graphHeight - (pixelLongest * dydt));
+ pixelLongest = 0;
- if (lastX != (int)x) {
- painter.drawLine(lastX, m_graphHeight, lastX, m_graphHeight - (longest * dydt));
- longest = 0;
- lastX = x;
+ if (selectedLongest > 0) {
+ painter.setPen(pen);
+ painter.drawLine(lastX, m_graphHeight, lastX, m_graphHeight - (selectedLongest * dydt));
+ painter.setPen(deselectPen);
+ selectedLongest = 0;
}
+
+ lastX = ix;
}
}
} else {
- /* At least 1 pixel per call, draw rects */
- if (m_type == GraphGpu) {
- for (int i = m_call; i < m_call + m_callWidth; ++i) {
- const Call& call = m_profile->calls[i];
+ /* Draw rectangles for graph */
+ for (int i = m_call; i < m_call + m_callWidth; ++i, x += dxdc) {
+ const Call& call = m_profile->calls[i];
+ int y;
- if (call.pixels >= 0) {
- int y = qMax<int>(1, call.gpuDuration * dydt);
- painter.fillRect(QRectF(x, m_graphHeight - y, dxdc, y), brush);
+ if (m_type == GraphGpu) {
+ y = qMax<int>(1, call.gpuDuration * dydt);
+ } else {
+ y = qMax<int>(1, call.cpuDuration * dydt);
+ }
+
+ if (m_selection.type == SelectTime) {
+ if (call.cpuStart < m_selection.timeStart || call.cpuStart > m_selection.timeEnd) {
+ if (m_type == GraphCpu || call.pixels >= 0) {
+ painter.fillRect(QRectF(x, m_graphHeight - y, dxdc, y), deselectBrush);
+ }
+
+ continue;
+ } else {
+ if (x < selectLeft) {
+ selectLeft = x;
+ }
+
+ if (x + dxdc > selectRight) {
+ selectRight = x + dxdc;
+ }
}
+ }
- x += dxdc;
+ if (m_type == GraphCpu || call.pixels >= 0) {
+ if (m_selection.type == SelectProgram && call.program != m_selection.program) {
+ painter.fillRect(QRectF(x, m_graphHeight - y, dxdc, y), deselectBrush);
+ } else {
+ painter.fillRect(QRectF(x, m_graphHeight - y, dxdc, y), brush);
+ }
}
- } else {
- for (int i = m_call; i < m_call + m_callWidth; ++i) {
- const Call& call = m_profile->calls[i];
+ }
+ }
- int y = qMax<int>(1, call.cpuDuration * dydt);
- painter.fillRect(QRectF(x, m_graphHeight - y, dxdc, y), brush);
+ /* Draw the selection borders */
+ if (m_selection.type == SelectTime && selectLeft < selectRight) {
+ selectLeft += m_axisWidth;
+ selectRight += m_axisWidth;
- x += dxdc;
- }
+ painter.resetTransform();
+ painter.setPen(Qt::green);
+
+ if (m_profile->calls[m_call].cpuStart <= m_selection.timeStart) {
+ painter.drawLine(selectLeft, 0, selectLeft, height());
}
+
+ if (m_profile->calls[m_call + m_callWidth - 1].cpuStart >= m_selection.timeEnd) {
+ painter.drawLine(selectRight, 0, selectRight, height());
+ }
+
+ selectLeft = qBound(m_axisWidth, selectLeft, width());
+ selectRight = qBound(m_axisWidth, selectRight, width());
+ painter.drawLine(selectLeft, m_axisHeight - 1, selectRight, m_axisHeight - 1);
}
}
diff --git a/gui/graphwidget.h b/gui/graphwidget.h
index 266f6945..7ab17c65 100644
--- a/gui/graphwidget.h
+++ b/gui/graphwidget.h
@@ -12,6 +12,12 @@ enum GraphType {
GraphCpu
};
+enum SelectType {
+ SelectNone,
+ SelectTime,
+ SelectProgram
+};
+
class GraphWidget : public QWidget
{
Q_OBJECT
@@ -22,18 +28,28 @@ public:
void setProfile(trace::Profile* profile, GraphType type);
const trace::Profile::Call* callAtPosition(const QPoint& pos);
+ void selectNone(bool notify = false);
+ void selectTime(int64_t start, int64_t end, bool notify = false);
+ void selectProgram(unsigned program, bool notify = false);
+
protected:
- virtual void mousePressEvent(QMouseEvent *e);
virtual void paintEvent(QPaintEvent *e);
- virtual void mouseMoveEvent(QMouseEvent *e);
+ virtual void resizeEvent(QResizeEvent *e);
+
virtual void wheelEvent(QWheelEvent *e);
+ virtual void mouseMoveEvent(QMouseEvent *e);
+ virtual void mousePressEvent(QMouseEvent *e);
+ virtual void mouseReleaseEvent(QMouseEvent *e);
virtual void mouseDoubleClickEvent(QMouseEvent *e);
- virtual void resizeEvent(QResizeEvent *e);
signals:
void jumpToCall(int no);
void viewChanged(int call, int width);
+ void selectedNone();
+ void selectedProgram(unsigned program);
+ void selectedTime(int64_t start, int64_t end);
+
public slots:
void changeView(int call, int width);
@@ -44,34 +60,46 @@ private:
void paintHorizontalAxis(QPainter& painter);
private:
+ /* Data */
trace::Profile* m_profile;
GraphType m_type;
- int64_t m_maxTime;
-
- int m_minCall;
- int m_maxCall;
-
- int m_minCallWidth;
- int m_maxCallWidth;
+ /* Vertical Axis */
+ int64_t m_timeMax;
+ /* Horizontal axis */
int m_call;
+ int m_callMin;
+ int m_callMax;
int m_callWidth;
+ int m_callWidthMin;
+ int m_callWidthMax;
- QPoint m_mousePressPosition;
+ /* Viewport */
+ int m_graphWidth;
+ int m_graphHeight;
+
+ /* Mouse track data */
int m_mousePressCall;
+ QPoint m_mousePressPosition;
+ /* Style */
int m_axisWidth;
int m_axisHeight;
-
- int m_graphWidth;
- int m_graphHeight;
-
QPen m_axisForeground;
QBrush m_axisBackground;
-
QLinearGradient m_graphGradientGpu;
QLinearGradient m_graphGradientCpu;
+ QLinearGradient m_graphGradientDeselected;
+
+ struct {
+ SelectType type;
+
+ unsigned program;
+
+ int64_t timeStart;
+ int64_t timeEnd;
+ } m_selection;
};
#endif // GRAPHWIDGET_H
diff --git a/gui/profiledialog.cpp b/gui/profiledialog.cpp
index 146e26a2..f3302038 100644
--- a/gui/profiledialog.cpp
+++ b/gui/profiledialog.cpp
@@ -9,13 +9,8 @@ ProfileDialog::ProfileDialog(QWidget *parent)
setupUi(this);
connect(m_timeline, SIGNAL(jumpToCall(int)), SIGNAL(jumpToCall(int)));
- connect(m_timeline, SIGNAL(selectionChanged(int64_t,int64_t)), SLOT(selectionChanged(int64_t,int64_t)));
-
connect(m_gpuGraph, SIGNAL(jumpToCall(int)), SIGNAL(jumpToCall(int)));
connect(m_cpuGraph, SIGNAL(jumpToCall(int)), SIGNAL(jumpToCall(int)));
-
- connect(m_gpuGraph, SIGNAL(viewChanged(int,int)), m_cpuGraph, SLOT(changeView(int,int)));
- connect(m_cpuGraph, SIGNAL(viewChanged(int,int)), m_gpuGraph, SLOT(changeView(int,int)));
}
@@ -32,36 +27,113 @@ void ProfileDialog::tableDoubleClicked(const QModelIndex& index)
if (call) {
emit jumpToCall(call->no);
+ } else {
+ unsigned program = model->getProgram(index);
+ m_timeline->selectProgram(program);
+ m_cpuGraph->selectProgram(program);
+ m_gpuGraph->selectProgram(program);
}
}
void ProfileDialog::setProfile(trace::Profile* profile)
{
- if (m_profile) {
- delete m_profile;
+ delete m_profile;
+
+ if (profile->frames.size() == 0) {
+ m_profile = NULL;
+ } else {
+ m_profile = profile;
+ m_timeline->setProfile(m_profile);
+ m_gpuGraph->setProfile(m_profile, GraphGpu);
+ m_cpuGraph->setProfile(m_profile, GraphCpu);
+
+ ProfileTableModel* model = new ProfileTableModel(m_table);
+ model->setProfile(m_profile);
+
+ delete m_table->model();
+ m_table->setModel(model);
+ m_table->update(QModelIndex());
+ m_table->sortByColumn(1, Qt::DescendingOrder);
+ m_table->horizontalHeader()->setResizeMode(QHeaderView::ResizeToContents);
+ m_table->resizeColumnsToContents();
+ }
+}
+
+
+void ProfileDialog::selectNone()
+{
+ QObject* src = QObject::sender();
+
+ /* Update table model */
+ ProfileTableModel* model = (ProfileTableModel*)m_table->model();
+ model->selectNone();
+ m_table->reset();
+
+ /* Update graphs */
+ if (src != m_gpuGraph) {
+ m_gpuGraph->selectNone();
+ }
+
+ if (src != m_cpuGraph) {
+ m_cpuGraph->selectNone();
+ }
+
+ /* Update timeline */
+ if (src != m_timeline) {
+ m_timeline->selectNone();
}
+}
+
+
+void ProfileDialog::selectProgram(unsigned program)
+{
+ QObject* src = QObject::sender();
- m_profile = profile;
- m_timeline->setProfile(m_profile);
- m_gpuGraph->setProfile(m_profile, GraphGpu);
- m_cpuGraph->setProfile(m_profile, GraphCpu);
+ /* Update table model */
+ ProfileTableModel* model = (ProfileTableModel*)m_table->model();
+ model->selectNone();
+ m_table->reset();
+ m_table->selectRow(model->getRowIndex(program));
+
+ /* Update graphs */
+ if (src != m_gpuGraph) {
+ m_gpuGraph->selectProgram(program);
+ }
- ProfileTableModel* model = new ProfileTableModel(m_table);
- model->setProfile(m_profile);
+ if (src != m_cpuGraph) {
+ m_cpuGraph->selectProgram(program);
+ }
- delete m_table->model();
- m_table->setModel(model);
- m_table->resizeColumnsToContents();
- m_table->sortByColumn(2, Qt::DescendingOrder);
+ /* Update timeline */
+ if (src != m_timeline) {
+ m_timeline->selectProgram(program);
+ }
}
-void ProfileDialog::selectionChanged(int64_t start, int64_t end)
+void ProfileDialog::selectTime(int64_t start, int64_t end)
{
+ QObject* src = QObject::sender();
+
+ /* Update table model */
ProfileTableModel* model = (ProfileTableModel*)m_table->model();
- model->setTimeSelection(start, end);
+ model->selectTime(start, end);
m_table->reset();
+
+ /* Update graphs */
+ if (src != m_gpuGraph) {
+ m_gpuGraph->selectTime(start, end);
+ }
+
+ if (src != m_cpuGraph) {
+ m_cpuGraph->selectTime(start, end);
+ }
+
+ /* Update timeline */
+ if (src != m_timeline) {
+ m_timeline->selectTime(start, end);
+ }
}
diff --git a/gui/profiledialog.h b/gui/profiledialog.h
index 8a2f39ea..22ef066f 100644
--- a/gui/profiledialog.h
+++ b/gui/profiledialog.h
@@ -22,7 +22,9 @@ public slots:
void tableDoubleClicked(const QModelIndex& index);
- void selectionChanged(int64_t start, int64_t end);
+ void selectNone();
+ void selectProgram(unsigned program);
+ void selectTime(int64_t start, int64_t end);
signals:
void jumpToCall(int call);
diff --git a/gui/profiletablemodel.cpp b/gui/profiletablemodel.cpp
index 5b9d4847..cbe2eea9 100644
--- a/gui/profiletablemodel.cpp
+++ b/gui/profiletablemodel.cpp
@@ -48,10 +48,35 @@ void ProfileTableModel::setProfile(trace::Profile* profile)
}
-void ProfileTableModel::setTimeSelection(int64_t start, int64_t end)
+/**
+ * Set selection to nothing
+ */
+void ProfileTableModel::selectNone()
+{
+ m_timeMin = m_timeMax = 0;
+ updateModel();
+ sort(m_sortColumn, m_sortOrder);
+}
+
+
+/**
+ * Set selection to program
+ */
+void ProfileTableModel::selectProgram(unsigned /*program*/)
+{
+ /* We have no program based selection for table */
+ selectNone();
+}
+
+
+/**
+ * Set selection to a period of time
+ */
+void ProfileTableModel::selectTime(int64_t start, int64_t end)
{
m_timeMin = start;
m_timeMax = end;
+
updateModel();
sort(m_sortColumn, m_sortOrder);
}
@@ -141,6 +166,33 @@ const trace::Profile::Call *ProfileTableModel::getJumpCall(const QModelIndex & i
}
+/**
+ * Get the shader program associated with an item in the table
+ */
+unsigned ProfileTableModel::getProgram(const QModelIndex & index) const
+{
+ const ProfileTableRow& row = m_rowData[index.row()];
+ return row.program;
+}
+
+
+/**
+ * Get the row index for a shader program
+ */
+int ProfileTableModel::getRowIndex(unsigned program) const
+{
+ for (int i = 0; i < m_rowData.size(); ++i) {
+ if (m_rowData[i].program == program)
+ return i;
+ }
+
+ return -1;
+}
+
+
+/**
+ * Get the row data for a shader program
+ */
ProfileTableRow* ProfileTableModel::getRow(unsigned program) {
for (QList<ProfileTableRow>::iterator itr = m_rowData.begin(); itr != m_rowData.end(); ++itr) {
if (itr->program == program)
diff --git a/gui/profiletablemodel.h b/gui/profiletablemodel.h
index dc08ba0e..da175503 100644
--- a/gui/profiletablemodel.h
+++ b/gui/profiletablemodel.h
@@ -37,8 +37,13 @@ public:
ProfileTableModel(QObject *parent = NULL);
void setProfile(trace::Profile* profile);
- void setTimeSelection(int64_t start, int64_t end);
+ void selectNone();
+ void selectProgram(unsigned program);
+ void selectTime(int64_t start, int64_t end);
+
+ int getRowIndex(unsigned program) const;
+ unsigned getProgram(const QModelIndex & index) const;
const trace::Profile::Call* getJumpCall(const QModelIndex & index) const;
virtual int rowCount(const QModelIndex & parent) const;
diff --git a/gui/timelinewidget.cpp b/gui/timelinewidget.cpp
index 03758318..0f30225d 100644
--- a/gui/timelinewidget.cpp
+++ b/gui/timelinewidget.cpp
@@ -2,7 +2,7 @@
#include "profiledialog.h"
#include "trace_profiler.hpp"
-#include <math.h>
+#include <qmath.h>
#include <QColor>
#include <QLocale>
#include <QPainter>
@@ -18,8 +18,6 @@ typedef trace::Profile::Program Program;
TimelineWidget::TimelineWidget(QWidget *parent)
: QWidget(parent),
m_profile(NULL),
- m_timeSelectionStart(0),
- m_timeSelectionEnd(0),
m_rowHeight(20),
m_axisWidth(50),
m_axisHeight(30),
@@ -28,8 +26,12 @@ TimelineWidget::TimelineWidget(QWidget *parent)
m_axisForeground(Qt::black),
m_axisBackground(QColor(210, 210, 210)),
m_itemBorder(Qt::red),
- m_itemForeground(Qt::cyan),
- m_itemBackground(Qt::red),
+ m_itemGpuForeground(Qt::cyan),
+ m_itemGpuBackground(Qt::red),
+ m_itemCpuForeground(QColor(255, 255, 0)),
+ m_itemCpuBackground(QColor(0, 0, 255)),
+ m_itemDeselectedForeground(Qt::white),
+ m_itemDeselectedBackground(QColor(155, 155, 155)),
m_selectionBorder(Qt::green),
m_selectionBackground(QColor(100, 255, 100, 8)),
m_zoomBorder(QColor(255, 0, 255)),
@@ -38,6 +40,8 @@ TimelineWidget::TimelineWidget(QWidget *parent)
setBackgroundRole(QPalette::Base);
setAutoFillBackground(true);
setMouseTracking(true);
+
+ m_selection.type = SelectNone;
}
@@ -74,15 +78,47 @@ void TimelineWidget::setVerticalScrollValue(int value)
/**
- * Update the time selection
+ * Set selection to nothing
+ */
+void TimelineWidget::selectNone(bool notify)
+{
+ m_selection.type = SelectNone;
+
+ if (notify) {
+ emit selectedNone();
+ }
+
+ update();
+}
+
+
+/**
+ * Set selection to a program
*/
-void TimelineWidget::setSelection(int64_t start, int64_t end, bool notify)
+void TimelineWidget::selectProgram(unsigned program, bool notify)
{
- m_timeSelectionStart = start;
- m_timeSelectionEnd = end;
+ m_selection.program = program;
+ m_selection.type = SelectProgram;
if (notify) {
- emit selectionChanged(m_timeSelectionStart, m_timeSelectionEnd);
+ emit selectedProgram(program);
+ }
+
+ update();
+}
+
+
+/**
+ * Set selection to a period of time
+ */
+void TimelineWidget::selectTime(int64_t start, int64_t end, bool notify)
+{
+ m_selection.timeStart = start;
+ m_selection.timeEnd = end;
+ m_selection.type = SelectTime;
+
+ if (notify) {
+ emit selectedTime(start, end);
}
update();
@@ -158,7 +194,7 @@ std::vector<unsigned>::const_iterator binarySearchTimespanIndexed(
int64_t time)
{
int lower = 0;
- int upper = end - begin;
+ int upper = end - begin - 1;
int pos = (lower + upper) / 2;
std::vector<unsigned>::const_iterator itr = begin + pos;
@@ -236,6 +272,27 @@ const Call* TimelineWidget::cpuCallAtTime(int64_t time)
/**
* Find the draw call at time
*/
+const Call* TimelineWidget::drawCallAtTime(int64_t time)
+{
+ if (!m_profile) {
+ return NULL;
+ }
+
+ for (int i = 0; i < m_rowPrograms.size(); ++i) {
+ const Call* call = drawCallAtTime(time, m_rowPrograms[i]);
+
+ if (call) {
+ return call;
+ }
+ }
+
+ return NULL;
+}
+
+
+/**
+ * Find the draw call at time for a selected program
+ */
const Call* TimelineWidget::drawCallAtTime(int64_t time, int program)
{
if (!m_profile) {
@@ -314,7 +371,7 @@ void TimelineWidget::setProfile(trace::Profile* profile)
setTimeScroll(m_time);
setRowScroll(0);
-
+ selectNone();
update();
}
@@ -371,7 +428,7 @@ void TimelineWidget::resizeEvent(QResizeEvent *e)
{
/* Update viewport size */
m_viewWidth = qMax(0, width() - m_axisWidth);
- m_viewHeight = qMax(0, height() - m_axisHeight - m_rowHeight);
+ m_viewHeight = qMax(0, height() - m_axisHeight - m_rowHeight * 2);
/* Update vertical scroll bar */
if (m_profile) {
@@ -411,25 +468,48 @@ void TimelineWidget::mouseMoveEvent(QMouseEvent *e)
tooltip = true;
}
} else {
- int row = (y - m_rowHeight + m_scrollY) / m_rowHeight;
+ const Call* call = NULL;
- if (row < m_rowPrograms.size()) {
- const Call* call = drawCallAtTime(time, m_rowPrograms[row]);
-
- if (call) {
- QString text;
- text = QString::fromStdString(call->name);
- text += QString("\nCall: %1").arg(call->no);
- text += QString("\nCPU Start: %1").arg(getTimeString(call->cpuStart));
- text += QString("\nGPU Start: %1").arg(getTimeString(call->gpuStart));
- text += QString("\nCPU Duration: %1").arg(getTimeString(call->cpuDuration));
- text += QString("\nGPU Duration: %1").arg(getTimeString(call->gpuDuration));
- text += QString("\nPixels Drawn: %1").arg(QLocale::system().toString((qlonglong)call->pixels));
-
- QToolTip::showText(e->globalPos(), text);
- tooltip = true;
+ if (y < m_rowHeight * 2) {
+ call = drawCallAtTime(time);
+ } else {
+ int row = (y - m_rowHeight * 2 + m_scrollY) / m_rowHeight;
+
+ if (row < m_rowPrograms.size()) {
+ call = drawCallAtTime(time, m_rowPrograms[row]);
}
}
+
+ if (call) {
+ QString text;
+ text = QString::fromStdString(call->name);
+ text += QString("\nCall: %1").arg(call->no);
+ text += QString("\nCPU Start: %1").arg(getTimeString(call->cpuStart));
+ text += QString("\nGPU Start: %1").arg(getTimeString(call->gpuStart));
+ text += QString("\nCPU Duration: %1").arg(getTimeString(call->cpuDuration));
+ text += QString("\nGPU Duration: %1").arg(getTimeString(call->gpuDuration));
+ text += QString("\nPixels Drawn: %1").arg(QLocale::system().toString((qlonglong)call->pixels));
+
+ QToolTip::showText(e->globalPos(), text);
+ tooltip = true;
+ }
+ }
+ } else if (m_mousePosition.x() < m_axisWidth && m_mousePosition.y() > m_axisHeight) {
+ int y = m_mousePosition.y() - m_axisHeight;
+
+ if (y < m_rowHeight) {
+ QToolTip::showText(e->globalPos(), "All CPU calls");
+ tooltip = true;
+ } else if (y < m_rowHeight * 2) {
+ QToolTip::showText(e->globalPos(), "All GPU calls");
+ tooltip = true;
+ } else {
+ int row = (y - m_rowHeight * 2 + m_scrollY) / m_rowHeight;
+
+ if (row < m_rowPrograms.size()) {
+ QToolTip::showText(e->globalPos(), QString("All calls in Shader Program %1").arg(m_rowPrograms[row]));
+ tooltip = true;
+ }
}
}
} else if (e->buttons().testFlag(Qt::LeftButton)) {
@@ -448,7 +528,7 @@ void TimelineWidget::mouseMoveEvent(QMouseEvent *e)
int64_t down = positionToTime(m_mousePressPosition.x() - m_axisWidth);
int64_t up = positionToTime(qMax(e->pos().x() - m_axisWidth, 0));
- setSelection(qMin(down, up), qMax(down, up));
+ selectTime(qMin(down, up), qMax(down, up), true);
}
update();
@@ -468,18 +548,16 @@ void TimelineWidget::mousePressEvent(QMouseEvent *e)
m_mousePressMode = RulerZoom;
} else {
m_mousePressMode = RulerSelect;
-
- int64_t time = positionToTime(e->pos().x() - m_axisWidth);
- m_timeSelectionStart = time;
- m_timeSelectionEnd = time;
}
- } else {
+ } else if (e->pos().x() >= m_axisWidth) {
m_mousePressMode = DragView;
+ } else {
+ m_mousePressMode = NoMousePress;
}
m_mousePressPosition = e->pos();
m_mousePressTime = m_time;
- m_mousePressRow = m_scrollY;
+ m_mousePressRow = m_scrollY;
update();
}
@@ -493,6 +571,8 @@ void TimelineWidget::mouseReleaseEvent(QMouseEvent *e)
}
/* Calculate new time view based on selected area */
+ int dxy = qAbs(m_mousePressPosition.x() - e->pos().x()) + qAbs(m_mousePressPosition.y() - e->pos().y());
+
int64_t down = positionToTime(m_mousePressPosition.x() - m_axisWidth);
int64_t up = positionToTime(qMax(e->pos().x() - m_axisWidth, 0));
@@ -505,8 +585,23 @@ void TimelineWidget::mouseReleaseEvent(QMouseEvent *e)
m_mousePressMode = NoMousePress;
setTimeScroll(left);
- } else if (m_mousePressMode == RulerSelect) {
- setSelection(m_timeSelectionStart, m_timeSelectionEnd, true);
+ } else {
+ if (dxy <= 2) {
+ if (m_selection.type == SelectTime) {
+ if (left < m_selection.timeStart || right > m_selection.timeEnd || e->pos().x() < m_axisWidth) {
+ selectNone(true);
+ }
+ } else if (m_selection.type == SelectProgram) {
+ int y = e->pos().y() - m_axisHeight;
+ int row = (y - m_rowHeight * 2 + m_scrollY) / m_rowHeight;
+
+ if (row < 0 || m_rowPrograms[row] != m_selection.program) {
+ selectNone(true);
+ }
+ }
+ } else if (m_mousePressMode == RulerSelect) {
+ selectTime(left, right, true);
+ }
}
}
@@ -523,7 +618,7 @@ void TimelineWidget::mouseDoubleClickEvent(QMouseEvent *e)
const Frame* frame = frameAtTime(time);
if (frame) {
- setSelection(frame->cpuStart, frame->cpuStart + frame->cpuDuration, true);
+ selectTime(frame->cpuStart, frame->cpuStart + frame->cpuDuration, true);
return;
}
} else if (row == 0) {
@@ -543,10 +638,13 @@ void TimelineWidget::mouseDoubleClickEvent(QMouseEvent *e)
return;
}
}
- }
+ } else {
+ int y = e->pos().y() - m_axisHeight;
+ int row = (y - m_rowHeight * 2 + m_scrollY) / m_rowHeight;
- if (time < m_timeSelectionStart || time > m_timeSelectionEnd) {
- setSelection(0, 0, true);
+ if (row >= 0 && row < m_rowPrograms.size()) {
+ selectProgram(m_rowPrograms[row], true);
+ }
}
}
@@ -557,6 +655,10 @@ void TimelineWidget::wheelEvent(QWheelEvent *e)
return;
}
+ if (e->pos().x() < m_axisWidth) {
+ return;
+ }
+
int zoomPercent = 10;
/* If holding Ctrl key then zoom 2x faster */
@@ -588,22 +690,31 @@ void TimelineWidget::wheelEvent(QWheelEvent *e)
/**
* Paints a single pixel column of the heat map
*/
-void TimelineWidget::drawHeat(QPainter& painter, int x, int64_t heat, bool isCpu)
+void TimelineWidget::drawHeat(QPainter& painter, int x, int64_t heat, bool gpu, bool selected)
{
if (heat == 0) {
return;
}
- double timePerPixel = m_timeWidth;
- timePerPixel /= m_viewWidth;
+ if (m_selection.type == SelectTime) {
+ selected = x >= m_selectionLeft && x <= m_selectionRight;
+ }
+ double timePerPixel = m_timeWidth / (double)m_viewWidth;
double colour = heat / timePerPixel;
- colour = qBound(0.0, colour * 255.0, 255.0);
- if (isCpu) {
- painter.setPen(QColor(255 - colour, 255 - colour, 255));
- } else {
+ /* Gamma correction */
+ colour = qPow(colour, 1.0 / 2.0);
+
+ if (!selected) {
+ colour = qBound(0.0, colour * 100.0, 100.0);
+ painter.setPen(QColor(255 - colour, 255 - colour, 255 - colour));
+ } else if (gpu) {
+ colour = qBound(0.0, colour * 255.0, 255.0);
painter.setPen(QColor(255, 255 - colour, 255 - colour));
+ } else {
+ colour = qBound(0.0, colour * 255.0, 255.0);
+ painter.setPen(QColor(255 - colour, 255 - colour, 255));
}
painter.drawLine(x, 0, x, m_rowHeight - 1);
@@ -611,156 +722,176 @@ void TimelineWidget::drawHeat(QPainter& painter, int x, int64_t heat, bool isCpu
/**
- * Render the whole widget
+ * Draws a call on the heatmap
*/
-void TimelineWidget::paintEvent(QPaintEvent *e)
+bool TimelineWidget::drawCall(QPainter& painter, const trace::Profile::Call& call, int& lastX, int64_t& heat, bool gpu)
{
- if (!m_profile)
- return;
+ int64_t start, duration, end;
- QPainter painter(this);
+ if (gpu) {
+ start = call.gpuStart;
+ duration = call.gpuDuration;
+ } else {
+ start = call.cpuStart;
+ duration = call.cpuDuration;
+ }
- int rowEnd = qMin(m_row + (m_viewHeight / m_rowHeight) + 1, m_rowCount);
- int64_t timeEnd = m_time + m_timeWidth;
- int64_t heat = 0;
- int lastX = 0;
- int widgetHeight = height();
- int widgetWidth = width();
+ end = start + duration;
- /* Draw GPU rows */
- painter.translate(m_axisWidth, m_axisHeight + m_rowHeight - (m_scrollY % m_rowHeight));
+ if (start > m_timeEnd) {
+ return false;
+ }
- for (int row = m_row; row < rowEnd; ++row) {
- Program& program = m_profile->programs[m_rowPrograms[row]];
- lastX = 0;
- heat = 0;
+ if (end < m_time) {
+ return true;
+ }
- for (std::vector<unsigned>::const_iterator itr = program.calls.begin(); itr != program.calls.end(); ++itr) {
- const Call& call = m_profile->calls[*itr];
- int64_t gpuEnd = call.gpuStart + call.gpuDuration;
+ double left = timeToPosition(start);
+ double right = timeToPosition(end);
- if (call.gpuStart > timeEnd) {
- break;
- }
+ int leftX = left;
+ int rightX = right;
- if (gpuEnd < m_time) {
- continue;
- }
+ bool selected = true;
- double left = timeToPosition(call.gpuStart);
- double right = timeToPosition(gpuEnd);
+ if (m_selection.type == SelectProgram) {
+ selected = call.program == m_selection.program;
+ }
- int leftX = left;
- int rightX = right;
+ /* Draw last heat if needed */
+ if (leftX != lastX) {
+ drawHeat(painter, lastX, heat, gpu, selected);
+ lastX = leftX;
+ heat = 0;
+ }
- /* Draw last heat if needed */
- if (leftX != lastX) {
- drawHeat(painter, lastX, heat, false);
- lastX = leftX;
- heat = 0;
- }
+ if (rightX <= leftX + 1) {
+ if (rightX == lastX) {
+ /* Fully contained in this X */
+ heat += duration;
+ } else {
+ /* Split call time between the two pixels it occupies */
+ int64_t time = positionToTime(rightX);
+ heat += time - start;
- if (rightX <= leftX + 1) {
- if (rightX == lastX) {
- /* Fully contained in this X */
- heat += call.gpuDuration;
- } else {
- /* Split call time between the two pixels it occupies */
- int64_t time = positionToTime(rightX);
+ drawHeat(painter, lastX, heat, gpu, selected);
- heat += time - call.gpuStart;
- drawHeat(painter, lastX, heat, false);
+ heat = end - time;
+ lastX = rightX;
+ }
+ } else {
+ QRect rect;
+ rect.setLeft(left + 0.5);
+ rect.setWidth(right - left);
+ rect.setTop(0);
+ rect.setHeight(m_rowHeight);
+
+ if (m_selection.type == SelectTime) {
+ selected = (start >= m_selection.timeStart && start <= m_selection.timeEnd)
+ || (end >= m_selection.timeStart && end <= m_selection.timeEnd);
+ }
- heat = gpuEnd - time;
- lastX = rightX;
- }
+ /* Draw background rect */
+ if (selected) {
+ if (gpu) {
+ painter.fillRect(rect, m_itemGpuBackground);
} else {
- QRect rect;
- rect.setLeft(left + 0.5);
- rect.setWidth(right - left);
- rect.setTop(0);
- rect.setHeight(m_rowHeight);
-
- painter.fillRect(rect, m_itemBackground);
+ painter.fillRect(rect, m_itemCpuBackground);
+ }
+ } else {
+ painter.fillRect(rect, m_itemDeselectedBackground);
+ }
- if (rect.width() > 6) {
- rect.adjust(1, 0, -1, -2);
- painter.setPen(m_itemForeground);
+ /* If wide enough, draw text */
+ if (rect.width() > 6) {
+ rect.adjust(1, 0, -1, -2);
- painter.drawText(rect,
- Qt::AlignLeft | Qt::AlignVCenter,
- painter.fontMetrics().elidedText(QString::fromStdString(call.name), Qt::ElideRight, rect.width()));
+ if (selected) {
+ if (gpu) {
+ painter.setPen(m_itemGpuForeground);
+ } else {
+ painter.setPen(m_itemCpuForeground);
}
+ } else {
+ painter.setPen(m_itemDeselectedForeground);
}
- }
- painter.translate(0, m_rowHeight);
+ painter.drawText(rect,
+ Qt::AlignLeft | Qt::AlignVCenter,
+ painter.fontMetrics().elidedText(QString::fromStdString(call.name), Qt::ElideRight, rect.width()));
+ }
}
- /* Draw CPU row */
- painter.resetTransform();
- painter.translate(m_axisWidth, m_axisHeight);
- painter.fillRect(0, 0, m_viewWidth, m_rowHeight, Qt::white);
+ return true;
+}
- for (std::vector<Call>::const_iterator itr = m_profile->calls.begin(); itr != m_profile->calls.end(); ++itr) {
- const Call& call = *itr;
- int64_t cpuEnd = call.cpuStart + call.cpuDuration;
- if (call.cpuStart > timeEnd) {
- continue;
- }
+/**
+ * Render the whole widget
+ */
+void TimelineWidget::paintEvent(QPaintEvent *e)
+{
+ if (!m_profile)
+ return;
- if (cpuEnd < m_time) {
- continue;
- }
+ QPainter painter(this);
- double left = timeToPosition(call.cpuStart);
- double right = timeToPosition(cpuEnd);
+ int rowEnd = qMin(m_row + qCeil(m_viewHeight / (double)m_rowHeight) + 1, m_rowCount);
+ int64_t heatGPU = 0, heatCPU = 0;
+ int lastCpuX = 0, lastGpuX = 0;
+ int widgetHeight = height();
+ int widgetWidth = width();
- int leftX = left;
- int rightX = right;
+ m_timeEnd = m_time + m_timeWidth;
+ m_selectionLeft = timeToPosition(m_selection.timeStart);
+ m_selectionRight = (timeToPosition(m_selection.timeEnd) + 0.5);
- /* Draw last heat if needed */
- if (leftX != lastX) {
- drawHeat(painter, lastX, heat, true);
- lastX = leftX;
- heat = 0;
- }
- if (rightX <= leftX + 1) {
- if (rightX == lastX) {
- /* Fully contained in this X */
- heat += call.cpuDuration;
- } else {
- /* Split call time between the two pixels it occupies */
- int64_t time = positionToTime(rightX);
+ /* Draw program rows */
+ painter.translate(m_axisWidth, m_axisHeight + m_rowHeight * 2 - (m_scrollY % m_rowHeight));
+
+ for (int row = m_row; row < rowEnd; ++row) {
+ Program& program = m_profile->programs[m_rowPrograms[row]];
+ lastGpuX = 0;
+ heatGPU = 0;
- heat += time - call.cpuStart;
- drawHeat(painter, lastX, heat, true);
+ for (std::vector<unsigned>::const_iterator itr = program.calls.begin(); itr != program.calls.end(); ++itr) {
+ const Call& call = m_profile->calls[*itr];
- heat = cpuEnd - time;
- lastX = rightX;
+ if (!drawCall(painter, call, lastGpuX, heatGPU, true)) {
+ break;
}
- } else {
- QRect rect;
- rect.setLeft(left + 0.5);
- rect.setWidth(right - left);
- rect.setTop(0);
- rect.setHeight(m_rowHeight);
+ }
- painter.fillRect(rect, QColor(0, 0, 255));
+ painter.translate(0, m_rowHeight);
+ }
- if (rect.width() > 6) {
- rect.adjust(1, 0, -1, -2);
- painter.setPen(QColor(255, 255, 0));
- painter.drawText(rect,
- Qt::AlignLeft | Qt::AlignVCenter,
- painter.fontMetrics().elidedText(QString::fromStdString(call.name), Qt::ElideRight, rect.width()));
- }
+ /* Draw CPU/GPU rows */
+ painter.resetTransform();
+ painter.translate(m_axisWidth, m_axisHeight);
+ painter.fillRect(0, 0, m_viewWidth, m_rowHeight * 2, Qt::white);
+
+ lastCpuX = lastGpuX = 0;
+ heatCPU = heatGPU = 0;
+
+ for (std::vector<Call>::const_iterator itr = m_profile->calls.begin(); itr != m_profile->calls.end(); ++itr) {
+ const Call& call = *itr;
+
+ /* Draw gpu row */
+ if (call.pixels >= 0) {
+ painter.translate(0, m_rowHeight);
+ drawCall(painter, call, lastGpuX, heatGPU, true);
+ painter.translate(0, -m_rowHeight);
+ }
+
+ /* Draw cpu row */
+ if (!drawCall(painter, call, lastCpuX, heatCPU, false)) {
+ break;
}
}
+
/* Draw axis */
painter.resetTransform();
painter.setPen(m_axisBorder);
@@ -773,8 +904,9 @@ void TimelineWidget::paintEvent(QPaintEvent *e)
painter.fillRect(0, m_axisHeight - 1, m_axisWidth - 1, widgetHeight, m_axisBackground);
painter.drawLine(m_axisWidth - 1, 0, m_axisWidth - 1, widgetHeight);
+
/* Draw the program numbers */
- painter.translate(0, m_axisHeight + m_rowHeight);
+ painter.translate(0, m_axisHeight + m_rowHeight * 2);
for (int row = m_row; row < rowEnd; ++row) {
int y = (row - m_row) * m_rowHeight - (m_scrollY % m_rowHeight);
@@ -782,13 +914,21 @@ void TimelineWidget::paintEvent(QPaintEvent *e)
painter.setPen(m_axisForeground);
painter.drawText(0, y, m_axisWidth, m_rowHeight, Qt::AlignHCenter | Qt::AlignVCenter, QString("%1").arg(m_rowPrograms[row]));
- painter.setPen(m_axisBorder);
- painter.drawLine(0, y + m_rowHeight - 1, m_axisWidth - 1, y + m_rowHeight - 1);
+ if (m_selection.type == SelectProgram && m_selection.program == m_rowPrograms[row]) {
+ painter.setPen(m_selectionBorder);
+ painter.drawLine(0, qMax(0, y - 1), widgetWidth, qMax(0, y - 1));
+ painter.drawLine(0, y + m_rowHeight - 1, widgetWidth, y + m_rowHeight - 1);
+ painter.drawLine(m_axisWidth - 1, y - 1, m_axisWidth - 1, y + m_rowHeight - 1);
+ } else {
+ painter.setPen(m_axisBorder);
+ painter.drawLine(0, y + m_rowHeight - 1, m_axisWidth - 1, y + m_rowHeight - 1);
- painter.setPen(m_axisLine);
- painter.drawLine(m_axisWidth, y + m_rowHeight - 1, widgetWidth, y + m_rowHeight - 1);
+ painter.setPen(m_axisLine);
+ painter.drawLine(m_axisWidth, y + m_rowHeight - 1, widgetWidth, y + m_rowHeight - 1);
+ }
}
+
/* Draw the "CPU" axis label */
painter.resetTransform();
painter.translate(0, m_axisHeight);
@@ -804,13 +944,27 @@ void TimelineWidget::paintEvent(QPaintEvent *e)
painter.drawLine(m_axisWidth, m_rowHeight - 1, widgetWidth, m_rowHeight - 1);
+ /* Draw the "GPU" axis label */
+ painter.translate(0, m_rowHeight);
+
+ painter.setPen(m_axisBorder);
+ painter.setBrush(m_axisBackground);
+ painter.drawRect(-1, -1, m_axisWidth, m_rowHeight);
+
+ painter.setPen(m_axisForeground);
+ painter.drawText(0, 0, m_axisWidth - 1, m_rowHeight - 1, Qt::AlignHCenter | Qt::AlignVCenter, "GPU");
+
+ painter.setPen(m_axisBorder);
+ painter.drawLine(m_axisWidth, m_rowHeight - 1, widgetWidth, m_rowHeight - 1);
+
+
/* Draw the frame numbers */
painter.resetTransform();
painter.setPen(m_axisForeground);
painter.translate(m_axisWidth, 0);
- int lastLabel = -9999;
+ int lastLabel = -999; /* Ensure first label gets drawn */
double scroll = m_time;
scroll /= m_timeWidth;
@@ -822,7 +976,7 @@ void TimelineWidget::paintEvent(QPaintEvent *e)
bool draw = true;
int width;
- if (frame.cpuStart > timeEnd) {
+ if (frame.cpuStart > m_timeEnd) {
break;
}
@@ -873,6 +1027,7 @@ void TimelineWidget::paintEvent(QPaintEvent *e)
}
}
+
/* Draw "Frame" axis label */
painter.resetTransform();
@@ -883,28 +1038,30 @@ void TimelineWidget::paintEvent(QPaintEvent *e)
painter.setPen(m_axisForeground);
painter.drawText(0, 0, m_axisWidth - 1, m_axisHeight - 1, Qt::AlignHCenter | Qt::AlignVCenter, "Frame");
- /* Draw the active selection border */
- if (m_timeSelectionStart != m_timeSelectionEnd) {
- int selectionLeft = timeToPosition(m_timeSelectionStart) + m_axisWidth;
- int selectionRight = (timeToPosition(m_timeSelectionEnd) + 0.5) + m_axisWidth;
+ /* Draw the active selection border */
+ if (m_selection.type == SelectTime) {
painter.setPen(m_selectionBorder);
- if (selectionLeft >= m_axisWidth && selectionLeft < widgetWidth) {
- painter.drawLine(selectionLeft, 0, selectionLeft, widgetHeight);
+ m_selectionLeft += m_axisWidth;
+ m_selectionRight += m_axisWidth;
+
+ if (m_selectionLeft >= m_axisWidth && m_selectionLeft < widgetWidth) {
+ painter.drawLine(m_selectionLeft, 0, m_selectionLeft, widgetHeight);
}
- if (selectionRight >= m_axisWidth && selectionRight < widgetWidth) {
- painter.drawLine(selectionRight, 0, selectionRight, widgetHeight);
+ if (m_selectionRight >= m_axisWidth && m_selectionRight < widgetWidth) {
+ painter.drawLine(m_selectionRight, 0, m_selectionRight, widgetHeight);
}
- selectionLeft = qBound(m_axisWidth, selectionLeft, widgetWidth);
- selectionRight = qBound(m_axisWidth, selectionRight, widgetWidth);
+ m_selectionLeft = qBound(m_axisWidth, m_selectionLeft, widgetWidth);
+ m_selectionRight = qBound(m_axisWidth, m_selectionRight, widgetWidth);
- painter.drawLine(selectionLeft, m_axisHeight - 1, selectionRight, m_axisHeight - 1);
- painter.fillRect(selectionLeft, 0, selectionRight - selectionLeft, widgetHeight, m_selectionBackground);
+ painter.drawLine(m_selectionLeft, m_axisHeight - 1, m_selectionRight, m_axisHeight - 1);
+ painter.fillRect(m_selectionLeft, 0, m_selectionRight - m_selectionLeft, widgetHeight, m_selectionBackground);
}
+
/* Draw the ruler zoom */
if (m_mousePressMode == RulerZoom) {
int x1 = m_mousePressPosition.x();
diff --git a/gui/timelinewidget.h b/gui/timelinewidget.h
index 9d5d8a51..ba42a101 100644
--- a/gui/timelinewidget.h
+++ b/gui/timelinewidget.h
@@ -17,11 +17,21 @@ class TimelineWidget : public QWidget
RulerSelect
};
+ enum SelectType {
+ SelectNone,
+ SelectTime,
+ SelectProgram
+ };
+
public:
TimelineWidget(QWidget *parent = 0);
void setProfile(trace::Profile* profile);
+ void selectNone(bool notify = false);
+ void selectProgram(unsigned program, bool notify = false);
+ void selectTime(int64_t start, int64_t end, bool notify = false);
+
protected:
virtual void wheelEvent(QWheelEvent *e);
virtual void mousePressEvent(QMouseEvent *e);
@@ -45,14 +55,16 @@ signals:
void jumpToCall(int call);
- void selectionChanged(int64_t start, int64_t end);
+ void selectedNone();
+ void selectedProgram(unsigned program);
+ void selectedTime(int64_t start, int64_t end);
private:
- void setSelection(int64_t start, int64_t end, bool notify = false);
void setRowScroll(int position, bool notify = true);
void setTimeScroll(int64_t time, bool notify = true);
- void drawHeat(QPainter& painter, int x, int64_t heat, bool isCpu);
+ bool drawCall(QPainter& painter, const trace::Profile::Call& call, int &lastX, int64_t &heat, bool gpu);
+ void drawHeat(QPainter& painter, int x, int64_t heat, bool gpu, bool selected);
double timeToPosition(int64_t time);
int64_t positionToTime(int pos);
@@ -61,6 +73,7 @@ private:
const trace::Profile::Frame* frameAtTime(int64_t time);
const trace::Profile::Call* cpuCallAtTime(int64_t time);
+ const trace::Profile::Call* drawCallAtTime(int64_t time);
const trace::Profile::Call* drawCallAtTime(int64_t time, int program);
private:
@@ -80,13 +93,15 @@ private:
/* Visible Times */
int64_t m_time;
+ int64_t m_timeEnd;
int64_t m_timeMin;
int64_t m_timeMax;
int64_t m_timeWidth;
int64_t m_timeWidthMin;
int64_t m_timeWidthMax;
- int64_t m_timeSelectionStart;
- int64_t m_timeSelectionEnd;
+
+ int m_selectionLeft;
+ int m_selectionRight;
/* Visible Rows */
int m_row;
@@ -108,12 +123,26 @@ private:
QPen m_axisForeground;
QBrush m_axisBackground;
QPen m_itemBorder;
- QPen m_itemForeground;
- QBrush m_itemBackground;
+ QPen m_itemGpuForeground;
+ QBrush m_itemGpuBackground;
+ QPen m_itemCpuForeground;
+ QBrush m_itemCpuBackground;
+ QPen m_itemDeselectedForeground;
+ QBrush m_itemDeselectedBackground;
QPen m_selectionBorder;
QBrush m_selectionBackground;
QPen m_zoomBorder;
QBrush m_zoomBackground;
+
+ /* Selection */
+ struct {
+ SelectType type;
+
+ unsigned program;
+
+ int64_t timeStart;
+ int64_t timeEnd;
+ } m_selection;
};
#endif // TIMELINEWIDGET_H
diff --git a/gui/ui/profiledialog.ui b/gui/ui/profiledialog.ui
index 49b77bd1..7a54ef72 100644
--- a/gui/ui/profiledialog.ui
+++ b/gui/ui/profiledialog.ui
@@ -9,181 +9,185 @@
<rect>
<x>0</x>
<y>0</y>
- <width>1079</width>
- <height>768</height>
+ <width>1105</width>
+ <height>804</height>
</rect>
</property>
<property name="windowTitle">
<string>Profile Results</string>
</property>
- <layout class="QVBoxLayout" name="verticalLayout_3">
- <property name="spacing">
- <number>0</number>
- </property>
+ <property name="styleSheet">
+ <string notr="true"/>
+ </property>
+ <layout class="QVBoxLayout" name="verticalLayout_2">
<property name="margin">
<number>0</number>
</property>
<item>
- <widget class="QTabWidget" name="tabWidget">
- <property name="currentIndex">
- <number>1</number>
+ <widget class="QSplitter" name="splitter">
+ <property name="orientation">
+ <enum>Qt::Vertical</enum>
</property>
- <widget class="QWidget" name="tabTimeline">
- <attribute name="title">
- <string>Timeline</string>
- </attribute>
- <layout class="QVBoxLayout" name="verticalLayout_2">
+ <property name="opaqueResize">
+ <bool>false</bool>
+ </property>
+ <widget class="QWidget" name="timelineContainer" native="true">
+ <property name="sizePolicy">
+ <sizepolicy hsizetype="Expanding" vsizetype="Expanding">
+ <horstretch>0</horstretch>
+ <verstretch>1</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="focusPolicy">
+ <enum>Qt::WheelFocus</enum>
+ </property>
+ <layout class="QVBoxLayout" name="verticalLayout">
+ <property name="spacing">
+ <number>0</number>
+ </property>
<property name="margin">
<number>0</number>
</property>
<item>
- <widget class="QSplitter" name="splitter">
- <property name="sizePolicy">
- <sizepolicy hsizetype="Expanding" vsizetype="Expanding">
- <horstretch>0</horstretch>
- <verstretch>0</verstretch>
- </sizepolicy>
- </property>
- <property name="orientation">
- <enum>Qt::Vertical</enum>
+ <layout class="QGridLayout" name="gridLayout">
+ <property name="spacing">
+ <number>2</number>
</property>
- <widget class="QWidget" name="timelineContainer" native="true">
- <property name="sizePolicy">
- <sizepolicy hsizetype="Expanding" vsizetype="Expanding">
- <horstretch>0</horstretch>
- <verstretch>1</verstretch>
- </sizepolicy>
- </property>
- <property name="focusPolicy">
- <enum>Qt::WheelFocus</enum>
- </property>
- <layout class="QVBoxLayout" name="verticalLayout">
- <property name="spacing">
- <number>0</number>
+ <item row="0" column="0">
+ <widget class="TimelineWidget" name="m_timeline" native="true">
+ <property name="sizePolicy">
+ <sizepolicy hsizetype="Expanding" vsizetype="Expanding">
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
</property>
- <property name="margin">
- <number>0</number>
+ <property name="focusPolicy">
+ <enum>Qt::WheelFocus</enum>
</property>
- <item>
- <layout class="QGridLayout" name="gridLayout">
- <property name="spacing">
- <number>2</number>
- </property>
- <item row="0" column="0">
- <widget class="TimelineWidget" name="m_timeline" native="true">
- <property name="sizePolicy">
- <sizepolicy hsizetype="Expanding" vsizetype="Expanding">
- <horstretch>0</horstretch>
- <verstretch>0</verstretch>
- </sizepolicy>
- </property>
- <property name="focusPolicy">
- <enum>Qt::WheelFocus</enum>
- </property>
- </widget>
- </item>
- <item row="0" column="1">
- <widget class="QScrollBar" name="m_verticalScrollBar">
- <property name="sizePolicy">
- <sizepolicy hsizetype="Fixed" vsizetype="Expanding">
- <horstretch>0</horstretch>
- <verstretch>0</verstretch>
- </sizepolicy>
- </property>
- <property name="orientation">
- <enum>Qt::Vertical</enum>
- </property>
- </widget>
- </item>
- <item row="1" column="0">
- <widget class="QScrollBar" name="m_horizontalScrollBar">
- <property name="sizePolicy">
- <sizepolicy hsizetype="Minimum" vsizetype="Fixed">
- <horstretch>0</horstretch>
- <verstretch>0</verstretch>
- </sizepolicy>
- </property>
- <property name="maximum">
- <number>10000</number>
- </property>
- <property name="orientation">
- <enum>Qt::Horizontal</enum>
- </property>
- </widget>
- </item>
- </layout>
- </item>
- </layout>
- </widget>
- <widget class="QTableView" name="m_table">
- <property name="sizePolicy">
- <sizepolicy hsizetype="Expanding" vsizetype="Expanding">
- <horstretch>0</horstretch>
- <verstretch>0</verstretch>
- </sizepolicy>
- </property>
- <property name="editTriggers">
- <set>QAbstractItemView::NoEditTriggers</set>
- </property>
- <property name="selectionMode">
- <enum>QAbstractItemView::SingleSelection</enum>
- </property>
- <property name="verticalScrollMode">
- <enum>QAbstractItemView::ScrollPerPixel</enum>
- </property>
- <property name="horizontalScrollMode">
- <enum>QAbstractItemView::ScrollPerPixel</enum>
- </property>
- <property name="sortingEnabled">
- <bool>true</bool>
- </property>
- <property name="wordWrap">
- <bool>false</bool>
- </property>
- <attribute name="verticalHeaderVisible">
- <bool>false</bool>
- </attribute>
- </widget>
- </widget>
+ </widget>
+ </item>
+ <item row="0" column="1">
+ <widget class="QScrollBar" name="m_verticalScrollBar">
+ <property name="sizePolicy">
+ <sizepolicy hsizetype="Fixed" vsizetype="Expanding">
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="orientation">
+ <enum>Qt::Vertical</enum>
+ </property>
+ </widget>
+ </item>
+ <item row="1" column="0">
+ <widget class="QScrollBar" name="m_horizontalScrollBar">
+ <property name="sizePolicy">
+ <sizepolicy hsizetype="Minimum" vsizetype="Fixed">
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="maximum">
+ <number>10000</number>
+ </property>
+ <property name="orientation">
+ <enum>Qt::Horizontal</enum>
+ </property>
+ </widget>
+ </item>
+ </layout>
</item>
</layout>
</widget>
- <widget class="QWidget" name="tabCalls">
- <attribute name="title">
- <string>Histogram</string>
- </attribute>
- <layout class="QVBoxLayout" name="verticalLayout_4">
+ <widget class="QWidget" name="graphContainer" native="true">
+ <property name="sizePolicy">
+ <sizepolicy hsizetype="Expanding" vsizetype="Expanding">
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="minimumSize">
+ <size>
+ <width>0</width>
+ <height>200</height>
+ </size>
+ </property>
+ <layout class="QVBoxLayout" name="verticalLayout_3">
+ <property name="spacing">
+ <number>0</number>
+ </property>
<property name="margin">
<number>0</number>
</property>
<item>
- <widget class="QSplitter" name="splitter_2">
- <property name="orientation">
- <enum>Qt::Vertical</enum>
+ <widget class="GraphWidget" name="m_gpuGraph" native="true">
+ <property name="sizePolicy">
+ <sizepolicy hsizetype="Expanding" vsizetype="Expanding">
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="minimumSize">
+ <size>
+ <width>0</width>
+ <height>0</height>
+ </size>
+ </property>
+ <property name="focusPolicy">
+ <enum>Qt::WheelFocus</enum>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="GraphWidget" name="m_cpuGraph" native="true">
+ <property name="sizePolicy">
+ <sizepolicy hsizetype="Expanding" vsizetype="Expanding">
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="minimumSize">
+ <size>
+ <width>0</width>
+ <height>0</height>
+ </size>
</property>
- <widget class="GraphWidget" name="m_gpuGraph" native="true">
- <property name="sizePolicy">
- <sizepolicy hsizetype="Expanding" vsizetype="Expanding">
- <horstretch>0</horstretch>
- <verstretch>0</verstretch>
- </sizepolicy>
- </property>
- <property name="focusPolicy">
- <enum>Qt::WheelFocus</enum>
- </property>
- </widget>
- <widget class="GraphWidget" name="m_cpuGraph" native="true">
- <property name="sizePolicy">
- <sizepolicy hsizetype="Expanding" vsizetype="Expanding">
- <horstretch>0</horstretch>
- <verstretch>0</verstretch>
- </sizepolicy>
- </property>
- </widget>
</widget>
</item>
</layout>
</widget>
+ <widget class="QTableView" name="m_table">
+ <property name="sizePolicy">
+ <sizepolicy hsizetype="Expanding" vsizetype="Expanding">
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="editTriggers">
+ <set>QAbstractItemView::NoEditTriggers</set>
+ </property>
+ <property name="selectionMode">
+ <enum>QAbstractItemView::SingleSelection</enum>
+ </property>
+ <property name="selectionBehavior">
+ <enum>QAbstractItemView::SelectRows</enum>
+ </property>
+ <property name="verticalScrollMode">
+ <enum>QAbstractItemView::ScrollPerPixel</enum>
+ </property>
+ <property name="horizontalScrollMode">
+ <enum>QAbstractItemView::ScrollPerPixel</enum>
+ </property>
+ <property name="sortingEnabled">
+ <bool>true</bool>
+ </property>
+ <property name="wordWrap">
+ <bool>false</bool>
+ </property>
+ <attribute name="verticalHeaderVisible">
+ <bool>false</bool>
+ </attribute>
+ </widget>
</widget>
</item>
</layout>
@@ -200,6 +204,9 @@
<signal>horizontalScrollMaxChanged(int)</signal>
<signal>verticalScrollMaxChanged(int)</signal>
<signal>jumpToCall(int)</signal>
+ <signal>selectedTime(int64_t,int64_t)</signal>
+ <signal>selectedProgram(unsigned)</signal>
+ <signal>selectedNone()</signal>
<slot>setHorizontalScrollValue(int)</slot>
<slot>setVerticalScrollValue(int)</slot>
</slots>
@@ -209,6 +216,13 @@
<extends>QWidget</extends>
<header>graphwidget.h</header>
<container>1</container>
+ <slots>
+ <signal>viewChanged(int,int)</signal>
+ <signal>selectedTime(int64_t,int64_t)</signal>
+ <signal>selectedProgram(unsigned)</signal>
+ <signal>selectedNone()</signal>
+ <slot>changeView(int,int)</slot>
+ </slots>
</customwidget>
</customwidgets>
<resources/>
@@ -220,12 +234,12 @@
<slot>setHorizontalScrollValue(int)</slot>
<hints>
<hint type="sourcelabel">
- <x>402</x>
- <y>195</y>
+ <x>373</x>
+ <y>434</y>
</hint>
<hint type="destinationlabel">
- <x>402</x>
- <y>93</y>
+ <x>373</x>
+ <y>213</y>
</hint>
</hints>
</connection>
@@ -236,12 +250,12 @@
<slot>setVerticalScrollValue(int)</slot>
<hints>
<hint type="sourcelabel">
- <x>813</x>
- <y>93</y>
+ <x>754</x>
+ <y>213</y>
</hint>
<hint type="destinationlabel">
- <x>402</x>
- <y>93</y>
+ <x>373</x>
+ <y>213</y>
</hint>
</hints>
</connection>
@@ -252,12 +266,12 @@
<slot>setValue(int)</slot>
<hints>
<hint type="sourcelabel">
- <x>402</x>
- <y>93</y>
+ <x>373</x>
+ <y>213</y>
</hint>
<hint type="destinationlabel">
- <x>402</x>
- <y>195</y>
+ <x>373</x>
+ <y>434</y>
</hint>
</hints>
</connection>
@@ -268,12 +282,12 @@
<slot>setValue(int)</slot>
<hints>
<hint type="sourcelabel">
- <x>402</x>
- <y>93</y>
+ <x>373</x>
+ <y>213</y>
</hint>
<hint type="destinationlabel">
- <x>813</x>
- <y>93</y>
+ <x>754</x>
+ <y>213</y>
</hint>
</hints>
</connection>
@@ -284,8 +298,8 @@
<slot>setHorizontalScrollMax(int)</slot>
<hints>
<hint type="sourcelabel">
- <x>504</x>
- <y>277</y>
+ <x>373</x>
+ <y>213</y>
</hint>
<hint type="destinationlabel">
<x>511</x>
@@ -300,8 +314,8 @@
<slot>setVerticalScrollMax(int)</slot>
<hints>
<hint type="sourcelabel">
- <x>504</x>
- <y>277</y>
+ <x>373</x>
+ <y>213</y>
</hint>
<hint type="destinationlabel">
<x>511</x>
@@ -310,14 +324,46 @@
</hints>
</connection>
<connection>
+ <sender>m_cpuGraph</sender>
+ <signal>viewChanged(int,int)</signal>
+ <receiver>m_gpuGraph</receiver>
+ <slot>changeView(int,int)</slot>
+ <hints>
+ <hint type="sourcelabel">
+ <x>511</x>
+ <y>687</y>
+ </hint>
+ <hint type="destinationlabel">
+ <x>511</x>
+ <y>527</y>
+ </hint>
+ </hints>
+ </connection>
+ <connection>
+ <sender>m_gpuGraph</sender>
+ <signal>viewChanged(int,int)</signal>
+ <receiver>m_cpuGraph</receiver>
+ <slot>changeView(int,int)</slot>
+ <hints>
+ <hint type="sourcelabel">
+ <x>511</x>
+ <y>527</y>
+ </hint>
+ <hint type="destinationlabel">
+ <x>511</x>
+ <y>687</y>
+ </hint>
+ </hints>
+ </connection>
+ <connection>
<sender>m_table</sender>
<signal>doubleClicked(QModelIndex)</signal>
<receiver>ProfileDialog</receiver>
<slot>tableDoubleClicked(QModelIndex)</slot>
<hints>
<hint type="sourcelabel">
- <x>511</x>
- <y>671</y>
+ <x>895</x>
+ <y>220</y>
</hint>
<hint type="destinationlabel">
<x>511</x>
@@ -325,11 +371,158 @@
</hint>
</hints>
</connection>
+ <connection>
+ <sender>m_cpuGraph</sender>
+ <signal>selectedTime(int64_t,int64_t)</signal>
+ <receiver>ProfileDialog</receiver>
+ <slot>selectTime(int64_t,int64_t)</slot>
+ <hints>
+ <hint type="sourcelabel">
+ <x>552</x>
+ <y>555</y>
+ </hint>
+ <hint type="destinationlabel">
+ <x>552</x>
+ <y>401</y>
+ </hint>
+ </hints>
+ </connection>
+ <connection>
+ <sender>m_gpuGraph</sender>
+ <signal>selectedTime(int64_t,int64_t)</signal>
+ <receiver>ProfileDialog</receiver>
+ <slot>selectTime(int64_t,int64_t)</slot>
+ <hints>
+ <hint type="sourcelabel">
+ <x>552</x>
+ <y>455</y>
+ </hint>
+ <hint type="destinationlabel">
+ <x>552</x>
+ <y>401</y>
+ </hint>
+ </hints>
+ </connection>
+ <connection>
+ <sender>m_timeline</sender>
+ <signal>selectedTime(int64_t,int64_t)</signal>
+ <receiver>ProfileDialog</receiver>
+ <slot>selectTime(int64_t,int64_t)</slot>
+ <hints>
+ <hint type="sourcelabel">
+ <x>544</x>
+ <y>192</y>
+ </hint>
+ <hint type="destinationlabel">
+ <x>552</x>
+ <y>401</y>
+ </hint>
+ </hints>
+ </connection>
+ <connection>
+ <sender>m_cpuGraph</sender>
+ <signal>selectedProgram(unsigned)</signal>
+ <receiver>ProfileDialog</receiver>
+ <slot>selectProgram(unsigned)</slot>
+ <hints>
+ <hint type="sourcelabel">
+ <x>552</x>
+ <y>555</y>
+ </hint>
+ <hint type="destinationlabel">
+ <x>552</x>
+ <y>401</y>
+ </hint>
+ </hints>
+ </connection>
+ <connection>
+ <sender>m_gpuGraph</sender>
+ <signal>selectedProgram(unsigned)</signal>
+ <receiver>ProfileDialog</receiver>
+ <slot>selectProgram(unsigned)</slot>
+ <hints>
+ <hint type="sourcelabel">
+ <x>552</x>
+ <y>455</y>
+ </hint>
+ <hint type="destinationlabel">
+ <x>552</x>
+ <y>401</y>
+ </hint>
+ </hints>
+ </connection>
+ <connection>
+ <sender>m_timeline</sender>
+ <signal>selectedProgram(unsigned)</signal>
+ <receiver>ProfileDialog</receiver>
+ <slot>selectProgram(unsigned)</slot>
+ <hints>
+ <hint type="sourcelabel">
+ <x>544</x>
+ <y>192</y>
+ </hint>
+ <hint type="destinationlabel">
+ <x>552</x>
+ <y>401</y>
+ </hint>
+ </hints>
+ </connection>
+ <connection>
+ <sender>m_cpuGraph</sender>
+ <signal>selectedNone()</signal>
+ <receiver>ProfileDialog</receiver>
+ <slot>selectNone()</slot>
+ <hints>
+ <hint type="sourcelabel">
+ <x>552</x>
+ <y>555</y>
+ </hint>
+ <hint type="destinationlabel">
+ <x>552</x>
+ <y>401</y>
+ </hint>
+ </hints>
+ </connection>
+ <connection>
+ <sender>m_gpuGraph</sender>
+ <signal>selectedNone()</signal>
+ <receiver>ProfileDialog</receiver>
+ <slot>selectNone()</slot>
+ <hints>
+ <hint type="sourcelabel">
+ <x>552</x>
+ <y>455</y>
+ </hint>
+ <hint type="destinationlabel">
+ <x>552</x>
+ <y>401</y>
+ </hint>
+ </hints>
+ </connection>
+ <connection>
+ <sender>m_timeline</sender>
+ <signal>selectedNone()</signal>
+ <receiver>ProfileDialog</receiver>
+ <slot>selectNone()</slot>
+ <hints>
+ <hint type="sourcelabel">
+ <x>544</x>
+ <y>192</y>
+ </hint>
+ <hint type="destinationlabel">
+ <x>552</x>
+ <y>401</y>
+ </hint>
+ </hints>
+ </connection>
</connections>
<slots>
<signal>jumpToCall(int)</signal>
<slot>setVerticalScrollMax(int)</slot>
<slot>setHorizontalScrollMax(int)</slot>
<slot>tableDoubleClicked(QModelIndex)</slot>
+ <slot>selectTime(int64_t,int64_t)</slot>
+ <slot>selectProgram(unsigned)</slot>
+ <slot>selectNone()</slot>
</slots>
</ui>