X-Git-Url: https://git.cworth.org/git?a=blobdiff_plain;f=gui%2Fgraphwidget.cpp;h=ea0f6a72e72ba418fba0f2af0eae34b217b26e42;hb=b70a86af10057c5b7fcf79b674cfe5abbeaadebb;hp=401c03464efdcc1ecbd9071533b902e93d8c39d0;hpb=661baf14834d3efc1d9d9b5416223c9a27c3d415;p=apitrace diff --git a/gui/graphwidget.cpp b/gui/graphwidget.cpp index 401c034..ea0f6a7 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::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::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(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(1, call.gpuDuration * dydt); - painter.fillRect(QRectF(x, m_graphHeight - y, dxdc, y), brush); + if (m_type == GraphGpu) { + y = qMax(1, call.gpuDuration * dydt); + } else { + y = qMax(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(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); } }